Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/audio_output/android/   (Android Betriebssystem Version 17©)  Datei vom 23.9.2026 mit Größe 10 kB image not shown  

Quelle  device.c   Sprache: C

 

/*****************************************************************************
 * android/device.c: Android AudioTrack/AAudio device handler
 *****************************************************************************
 * Copyright © 2012-2022 VLC authors and VideoLAN, VideoLabs
 *
 * Authors: Thomas Guillem <thomas@gllm.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <string.h>

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_modules.h>
#include <vlc_aout.h>

#include <android/api-level.h>
#include <sys/system_properties.h>

#include "device.h"
#include "audioformat_jni.h"

/* There is an undefined behavior when configuring AudioTrack with SPDIF or
 * more than 2 channels when there is no HDMI out. It may succeed and the
 * Android ressampler will be used to downmix to stereo. It may fails cleanly,
 * and this module will be able to recover and fallback to stereo. Finally, in
 * some rare cases, it may crash during init or while ressampling. Because of
 * the last case we don't try up to 8 channels and we use
 * ANDROID_AUDIO_DEVICE_STEREO device per default */

#define ANDROID_AUDIO_DEVICE_DEFAULT ANDROID_AUDIO_DEVICE_STEREO

static const struct {
    const char *id;
    const char *name;
    enum android_audio_device_type adev;
} adevs[] = {
    { "stereo", "Up to 2 channels (compat mode).", ANDROID_AUDIO_DEVICE_STEREO },
    { "pcm", "Up to 8 channels.", ANDROID_AUDIO_DEVICE_PCM },

    /* With "encoded", the module will try to play every audio codecs via
     * passthrough.
     *
     * With "encoded:ENCODING_FLAGS_MASK", the module will try to play only
     * codecs specified by ENCODING_FLAGS_MASK. This extra value is a long long
     * that contains binary-shifted AudioFormat.ENCODING_* values. */

    { "encoded", "Up to 8 channels, passthrough if available.", ANDROID_AUDIO_DEVICE_ENCODED },
    {  NULL, NULL, ANDROID_AUDIO_DEVICE_DEFAULT },
};

/* Audio output Allow/Deny Logic Start */
enum AudioOutput
{
    OPENSLES, ALL
};

static const struct
{
    const char *property;
    const char *property_value;
    enum AudioOutput audio_output;
} audio_output_by_soc[] = {
    /* getPlaybackHeadPosition returns an invalid position on Fire OS,
     * thus Audiotrack is not usable */

    { "ro.product.brand", "Amazon", OPENSLES },
    { "ro.product.manufacturer", "Amazon", OPENSLES }
};


static enum AudioOutput get_audio_output_from_device(void)
{
    if (android_get_device_api_level() >= 28)
        return ALL;

    int len = 0;
    char value[PROP_VALUE_MAX];
    for (size_t i = 0; i < ARRAY_SIZE(audio_output_by_soc); i++)
    {
        /* On return, len will equal (int)strlen(model_id) */
        len = __system_property_get(audio_output_by_soc[i].property, value);
        if (len > 0)
        {
            if (strstr(value, audio_output_by_soc[i].property_value) != NULL)
                return audio_output_by_soc[i].audio_output;
        }
    }
    return ALL;
}
/* Audio output Allow/Deny Logic End */

struct sys {
    aout_stream_t *stream;

    enum android_audio_device_type adev;
    long long encoding_flags;

    bool mute;
    float volume;
};

static void
Drain(audio_output_t *aout)
{
    struct sys *sys = aout->sys;
    assert(sys->stream != NULL);
    assert(sys->stream->drain != NULL);

    sys->stream->drain(sys->stream);
}

static int
Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
{
    struct sys *sys = aout->sys;

    if (!vlc_android_AudioFormat_HasEncoding(sys->encoding_flags, fmt->i_format))
        return VLC_EGENERIC;

    aout_stream_t *s = vlc_object_create(aout, sizeof (*s));
    if (unlikely(s == NULL))
        return VLC_EGENERIC;
    s->aout = aout;

    /* There is only one "aout" module for android, that take care of choosing
     * the best API by default (AAudio, AudioTrack, OpenSLES). This is needed
     * because AAudio, that is the best API to use, doesn't handle pass-through
     * while AudioTrack can. Therefore, this intermediate "aout" module allow
     * choosing AAudio for PCM and AudioTrack for pass-through. The user is
     * still able to force an API via LibVLC because the "aout" choice is
     * forwarded to the "aout android stream" module probe. */

    char *modlist = var_InheritString(aout, "aout");
    module_t **mods;
    ssize_t total = vlc_module_match("aout android stream", modlist, false, &mods, NULL);
    int ret = VLC_EGENERIC;
    for (ssize_t i = 0; i < total; i++)
    {
        aout_stream_start start = vlc_module_map(vlc_object_logger(aout), mods[i]);
        if (start == NULL)
            continue;
        ret = start(s, fmt, sys->adev);
        if (ret == VLC_SUCCESS)
        {
            sys->stream = s;

            assert(s->stop != NULL && s->play != NULL &&
                   s->pause != NULL && s->flush != NULL);

            aout->drain = s->drain != NULL ? Drain : NULL;

            if (s->volume_set != NULL)
                s->volume_set(s, sys->volume);
            if (s->mute_set != NULL && sys->mute)
                s->mute_set(s, true);
            break;
        }
    }

    free(modlist);
    free(mods);

    return ret;
}

static void
Stop(audio_output_t *aout)
{
    struct sys *sys = aout->sys;
    assert(sys->stream != NULL);

    sys->stream->stop(sys->stream);

    vlc_object_delete(sys->stream);
    sys->stream = NULL;
}

static void
Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
{
    struct sys *sys = aout->sys;
    assert(sys->stream != NULL);

    sys->stream->play(sys->stream, block, date);
}

static void
Pause(audio_output_t *aout, bool paused, vlc_tick_t date)
{
    struct sys *sys = aout->sys;
    assert(sys->stream != NULL);

    sys->stream->pause(sys->stream, paused, date);
}

static void
Flush(audio_output_t *aout)
{
    struct sys *sys = aout->sys;
    assert(sys->stream != NULL);

    sys->stream->flush(sys->stream);
}

static int
VolumeSet(audio_output_t *aout, float vol)
{
    struct sys *sys = aout->sys;

    sys->volume = vol;
    if (sys->stream != NULL && sys->stream->volume_set != NULL)
        sys->stream->volume_set(sys->stream, vol);

    aout_VolumeReport(aout, vol);
    return 0;
}

static int
MuteSet(audio_output_t *aout, bool mute)
{
    struct sys *sys = aout->sys;

    sys->mute = mute;
    if (sys->stream != NULL && sys->stream->mute_set != NULL)
        sys->stream->mute_set(sys->stream, mute);

    aout_MuteReport(aout, mute);
    return 0;
}

static int DeviceSelect(audio_output_t *aout, const char *id)
{
    struct sys *sys = aout->sys;
    enum android_audio_device_type adev = ANDROID_AUDIO_DEVICE_DEFAULT;

    if (id)
    {
        for (unsigned int i = 0; adevs[i].id; ++i)
        {
            if (strncmp(id, adevs[i].id, strlen(adevs[i].id))== 0)
            {
                adev = adevs[i].adev;
                break;
            }
        }
    }

    long long encoding_flags = 0;
    if (adev == ANDROID_AUDIO_DEVICE_ENCODED)
    {
        const size_t prefix_size = strlen("encoded:");
        if (strncmp(id, "encoded:", prefix_size)== 0)
            encoding_flags = atoll(id + prefix_size);
    }

    if (adev != sys->adev || encoding_flags != sys->encoding_flags)
    {
        sys->adev = adev;
        sys->encoding_flags = encoding_flags;
        aout_RestartRequest(aout, true);
        msg_Dbg(aout, "selected device: %s", id);

        if (adev == ANDROID_AUDIO_DEVICE_ENCODED)
        {
            static const vlc_fourcc_t enc_fourccs[] = {
                VLC_CODEC_DTS, VLC_CODEC_DTSHD, VLC_CODEC_A52, VLC_CODEC_EAC3,
                VLC_CODEC_TRUEHD,
            };
            for (size_t i = 0;
                 i < sizeof(enc_fourccs)/ sizeof(enc_fourccs[0]); ++i)
            {
                if (vlc_android_AudioFormat_HasEncoding(sys->encoding_flags, enc_fourccs[i]))
                    msg_Dbg(aout, "device has %4.4s passthrough support",
                             (const char *)&enc_fourccs[i]);
            }
        }
    }
    aout_DeviceReport(aout, id);
    return VLC_SUCCESS;
}

static int
Open(vlc_object_t *obj)
{
    audio_output_t *aout = (audio_output_t *)obj;

    if (vlc_android_AudioFormat_InitJNI(obj) != VLC_SUCCESS)
        return VLC_EGENERIC;

    /* Return an error if OpenSLES should be used */
    if (get_audio_output_from_device() == OPENSLES)
        return VLC_EGENERIC;

    struct sys *sys = aout->sys = vlc_obj_malloc(obj, sizeof(*sys));
    if (sys == NULL)
        return VLC_ENOMEM;

    sys->adev = ANDROID_AUDIO_DEVICE_DEFAULT;
    sys->encoding_flags = 0;
    sys->volume = 1.f;
    sys->mute = false;
    sys->stream = NULL;

    aout->start = Start;
    aout->stop = Stop;
    aout->play = Play;
    aout->pause = Pause;
    aout->flush = Flush;
    aout->drain = NULL;
    aout->device_select = DeviceSelect;
    aout->volume_set = VolumeSet;
    aout->mute_set = MuteSet;

    for (unsigned int i = 0; adevs[i].id; ++i)
        aout_HotplugReport(aout, adevs[i].id, adevs[i].name);

    if (var_InheritBool(aout, "spdif"))
        DeviceSelect(aout, "encoded");

    return VLC_SUCCESS;
}


#define add_aout(shortcut, name, desc) \
    add_submodule() \
        add_shortcut(name) \
        set_shortname(name) \
        set_description(desc) \
        set_capability("audio output", 0) \
        set_callback(Open)

#define AUDIOTRACK_SESSION_ID_TEXT " Id of audio session the AudioTrack must be attached to"

vlc_module_begin ()
    set_shortname("Android Audio")
    set_description("Android automatic audio output")
    set_capability("audio output", 200)
    set_subcategory(SUBCAT_AUDIO_AOUT)
    add_integer("audiotrack-session-id", 0,
            AUDIOTRACK_SESSION_ID_TEXT, NULL )
        change_private()
    set_callback(Open)
    add_aout("audiotrack", "AudioTrack", "Android AudioTrack audio output")
    add_aout("aaudio", "AAudio", "Android AAudio output")
vlc_module_end ()

Messung
CHZG
839710093

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.