Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  output.c   Sprache: C

 

/*****************************************************************************
 * output.c : internal management of output streams for the audio output
 *****************************************************************************
 * Copyright (C) 2002-2004 VLC authors and VideoLAN
 *
 * Authors: Christophe Massiot <massiot@via.ecp.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 <stdlib.h>
#include <assert.h>

#include <vlc_common.h>
#include <vlc_configuration.h>
#include <vlc_aout.h>
#include <vlc_modules.h>
#include <vlc_atomic.h>

#include "../libvlc.h"
#include "aout_internal.h"

typedef struct aout_dev
{
    struct vlc_list node;
    char *name;
    char id[1];
} aout_dev_t;


/* Local functions */

static inline float clampf(const float value, const float min, const float max)
{
    if (value < min)
        return min;
    else if (value > max)
        return max;
    else
        return value;
}

static int var_Copy (vlc_object_t *src, const char *name, vlc_value_t prev,
                     vlc_value_t value, void *data)
{
    vlc_object_t *dst = data;

    (void) src; (void) prev;
    return var_Set (dst, name, value);
}

static int var_CopyDevice (vlc_object_t *src, const char *name,
                           vlc_value_t prev, vlc_value_t value, void *data)
{
    vlc_object_t *dst = data;

    (void) src; (void) name; (void) prev;
    return var_Set (dst, "audio-device", value);
}

static void aout_TimingNotify(audio_output_t *aout, vlc_tick_t system_ts,
                              vlc_tick_t audio_ts)
{
    aout_owner_t *owner = aout_owner (aout);
    assert(owner->main_stream);
    vlc_aout_stream_NotifyTiming(owner->main_stream, system_ts, audio_ts);
}

static void aout_DrainedNotify(audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);
    assert(owner->main_stream);
    vlc_aout_stream_NotifyDrained(owner->main_stream);
}

/**
 * Supply or update the current custom ("hardware") volume.
 *
 * @param aout the audio output notifying the new volume
 * @param volume current custom volume
 *
 * @warning The caller (i.e. the audio output plug-in) is responsible for
 * interlocking and synchronizing call to this function and to the
 * audio_output_t.volume_set callback. This ensures that VLC gets correct
 * volume information (possibly with a latency).
 */

static void aout_VolumeNotify (audio_output_t *aout, float volume)
{
    var_SetFloat (aout, "volume", volume);
}

static void aout_MuteNotify (audio_output_t *aout, bool mute)
{
    var_SetBool (aout, "mute", mute);
}

static void aout_PolicyNotify (audio_output_t *aout, bool cork)
{
    (cork ? var_IncInteger : var_DecInteger)(vlc_object_parent(aout), "corks");
}

static void aout_DeviceNotify (audio_output_t *aout, const char *id)
{
    var_SetString (aout, "device", (id != NULL) ? id : "");
}

static void aout_HotplugNotify (audio_output_t *aout,
                                const char *id, const char *name)
{
    aout_owner_t *owner = aout_owner (aout);
    aout_dev_t *dev = NULL, *p;

    vlc_mutex_lock (&owner->dev.lock);
    vlc_list_foreach(p, &owner->dev.list, node)
    {
        if (!strcmp (id, p->id))
        {
            dev = p;
            break;
        }
    }

    if (name != NULL)
    {
        if (dev == NULL) /* Added device */
        {
            dev = malloc (sizeof (*dev) + strlen (id));
            if (unlikely(dev == NULL))
                goto out;
            strcpy (dev->id, id);
            vlc_list_append(&dev->node, &owner->dev.list);
            owner->dev.count++;
        }
        else /* Modified device */
            free (dev->name);
        dev->name = strdup (name);
    }
    else
    {
        if (dev != NULL) /* Removed device */
        {
            owner->dev.count--;
            vlc_list_remove(&dev->node);
            free (dev->name);
            free (dev);
        }
    }
out:
    vlc_mutex_unlock (&owner->dev.lock);
}

static void aout_RestartNotify (audio_output_t *aout, bool restart_dec)
{
    aout_owner_t *owner = aout_owner (aout);
    if (owner->main_stream)
    {
        unsigned mode = restart_dec ? AOUT_RESTART_OUTPUT_DEC : AOUT_RESTART_OUTPUT;
        vlc_aout_stream_RequestRestart(owner->main_stream, mode);
    }
}

void aout_InputRequestRestart(audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);
    if (owner->main_stream)
        vlc_aout_stream_RequestRestart(owner->main_stream, AOUT_RESTART_FILTERS);
}

static int aout_GainNotify (audio_output_t *aout, float gain)
{
    aout_owner_t *owner = aout_owner (aout);

    vlc_mutex_assert(&owner->lock);
    /* XXX: ideally, return -1 if format cannot be amplified */
    if (owner->main_stream != NULL)
        vlc_aout_stream_NotifyGain(owner->main_stream, gain);
    return 0;
}

static const struct vlc_audio_output_events aout_events = {
    aout_TimingNotify,
    aout_DrainedNotify,
    aout_VolumeNotify,
    aout_MuteNotify,
    aout_PolicyNotify,
    aout_DeviceNotify,
    aout_HotplugNotify,
    aout_RestartNotify,
    aout_GainNotify,
};

static int FilterCallback (vlc_object_t *obj, const char *var,
                           vlc_value_t prev, vlc_value_t cur, void *data)
{
    if (strcmp(prev.psz_string, cur.psz_string))
        aout_InputRequestRestart ((audio_output_t *)obj);
    (void) var; (void) data;
    return VLC_SUCCESS;
}

static int StereoModeCallback (vlc_object_t *obj, const char *varname,
                               vlc_value_t oldval, vlc_value_t newval, void *data)
{
    audio_output_t *aout = (audio_output_t *)obj;
    (void)varname; (void)oldval; (void)newval; (void)data;

    aout_owner_t *owner = aout_owner (aout);
    vlc_mutex_lock (&owner->lock);
    owner->requested_stereo_mode = newval.i_int;
    vlc_mutex_unlock (&owner->lock);

    if (owner->main_stream)
        vlc_aout_stream_RequestRestart(owner->main_stream, AOUT_RESTART_OUTPUT);
    return 0;
}

static int MixModeCallback (vlc_object_t *obj, const char *varname,
                               vlc_value_t oldval, vlc_value_t newval, void *data)
{
    audio_output_t *aout = (audio_output_t *)obj;
    (void)varname; (void)oldval; (void)newval; (void)data;

    aout_owner_t *owner = aout_owner (aout);
    vlc_mutex_lock (&owner->lock);
    owner->requested_mix_mode = newval.i_int;
    vlc_mutex_unlock (&owner->lock);

    if (owner->main_stream)
        vlc_aout_stream_RequestRestart(owner->main_stream, AOUT_RESTART_OUTPUT);
    return 0;
}

static void aout_ChangeViewpoint(audio_output_t *, const vlc_viewpoint_t *);

static int ViewpointCallback (vlc_object_t *obj, const char *var,
                              vlc_value_t prev, vlc_value_t cur, void *data)
{
    if( cur.p_address != NULL )
        aout_ChangeViewpoint((audio_output_t *)obj, cur.p_address );
    (void) var; (void) data; (void) prev;
    return VLC_SUCCESS;
}

#undef aout_New
/**
 * Creates an audio output object and initializes an output module.
 */

audio_output_t *aout_New (vlc_object_t *parent)
{
    vlc_value_t val;

    audio_output_t *aout = vlc_custom_create (parent, sizeof (aout_instance_t),
                                              "audio output");
    if (unlikely(aout == NULL))
        return NULL;

    aout_owner_t *owner = aout_owner (aout);

    vlc_mutex_init (&owner->lock);
    vlc_mutex_init (&owner->dev.lock);
    vlc_mutex_init (&owner->vp.lock);
    vlc_viewpoint_init (&owner->vp.value);
    vlc_list_init(&owner->dev.list);
    atomic_init (&owner->vp.update, false);
    vlc_atomic_rc_init(&owner->rc);
    vlc_audio_meter_Init(&owner->meter, aout);

    owner->main_stream = NULL;

    /* Audio output module callbacks */
    var_Create (aout, "volume", VLC_VAR_FLOAT);
    var_SetFloat(aout, "volume", -1.f);
    var_AddCallback (aout, "volume", var_Copy, parent);
    var_Create (aout, "mute", VLC_VAR_BOOL);
    var_AddCallback (aout, "mute", var_Copy, parent);
    var_Create (aout, "device", VLC_VAR_STRING);
    var_AddCallback (aout, "device", var_CopyDevice, parent);

    aout->events = &aout_events;

    /* Audio output module initialization */
    aout->start = NULL;
    aout->stop = NULL;
    aout->volume_set = NULL;
    aout->mute_set = NULL;
    aout->device_select = NULL;
    owner->module = module_need_var(aout, "audio output", "aout");
    if (owner->module == NULL)
    {
        msg_Err (aout, "no suitable audio output module");
        vlc_object_delete(aout);
        return NULL;
    }
    assert(aout->start && aout->stop);

    /*
     * Persistent audio output variables
     */

    module_config_t *cfg;
    char *str;

    /* Visualizations */
    var_Create (aout, "audio-visual", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_Change(aout, "audio-visual", VLC_VAR_SETTEXT,
               _("Audio visualizations"));

    var_Create (aout, "visual", VLC_VAR_STRING);
    var_Change(aout, "visual", VLC_VAR_SETTEXT, _("Visualizations"));
    val.psz_string = (char *)"";
    var_Change(aout, "visual", VLC_VAR_ADDCHOICE, val, _("Disable"));
    val.psz_string = (char *)"spectrometer";
    var_Change(aout, "visual", VLC_VAR_ADDCHOICE, val, _("Spectrometer"));
    val.psz_string = (char *)"scope";
    var_Change(aout, "visual", VLC_VAR_ADDCHOICE, val, _("Scope"));
    val.psz_string = (char *)"spectrum";
    var_Change(aout, "visual", VLC_VAR_ADDCHOICE, val, _("Spectrum"));
    val.psz_string = (char *)"vuMeter";
    var_Change(aout, "visual", VLC_VAR_ADDCHOICE, val, _("VU meter"));
    /* Same list the preferences use; "visual" is covered by its effects. */
    char **vis_vals, **vis_texts;
    ssize_t vis_count = config_GetPszChoices ("audio-visual", &vis_vals,
                                              &vis_texts);
    for (ssize_t i = 0; i < vis_count; i++)
    {
        if (strcmp (vis_vals[i], "any") && strcmp (vis_vals[i], "none")
         && strcmp (vis_vals[i], "visual"))
        {
            val.psz_string = vis_vals[i];
            var_Change(aout, "visual", VLC_VAR_ADDCHOICE, val, vis_texts[i]);
        }
        free (vis_vals[i]);
        free (vis_texts[i]);
    }
    free (vis_vals);
    free (vis_texts);

    /* Show the configured visualization as the selected one. */
    str = var_GetNonEmptyString (aout, "audio-visual");
    if (str != NULL && strcasecmp (str, "none") && strcasecmp (str, "any"))
    {
        if (!strcasecmp (str, "visual"))
        {
            /* The visual plugin picks its effect with "effect-list". */
            free (str);
            str = module_exists ("visual")
                ? var_InheritString (aout, "effect-list") : NULL;
        }
        if (str != NULL)
            var_SetString (aout, "visual", str);
    }
    free (str);

    var_Create (aout, "audio-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_AddCallback (aout, "audio-filter", FilterCallback, NULL);
    var_Change(aout, "audio-filter", VLC_VAR_SETTEXT, _("Audio filters"));

    var_Create (aout, "viewpoint", VLC_VAR_ADDRESS );
    var_AddCallback (aout, "viewpoint", ViewpointCallback, NULL);

    /* Replay gain */
    var_Create (aout, "audio-replay-gain-mode",
                VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Change(aout, "audio-replay-gain-mode", VLC_VAR_SETTEXT,
               _("Replay gain"));
    cfg = config_FindConfig("audio-replay-gain-mode");
    if (likely(cfg != NULL))
        for (unsigned i = 0; i < cfg->list_count; i++)
        {
            val.psz_string = (char *)cfg->list.psz[i];
            var_Change(aout, "audio-replay-gain-mode", VLC_VAR_ADDCHOICE,
                       val, vlc_gettext(cfg->list_text[i]));
        }

    /* Stereo mode */
    var_Create (aout, "stereo-mode", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    owner->requested_stereo_mode = var_GetInteger (aout, "stereo-mode");

    var_AddCallback (aout, "stereo-mode", StereoModeCallback, NULL);
    var_Change(aout, "stereo-mode", VLC_VAR_SETTEXT, _("Stereo audio mode"));

    /* Mix mode */
    var_Create (aout, "mix-mode", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
    owner->requested_mix_mode = var_GetInteger (aout, "mix-mode");
    var_AddCallback (aout, "mix-mode", MixModeCallback, NULL);
    var_Change(aout, "mix-mode", VLC_VAR_SETTEXT, _("Audio mix mode"));

    /* Equalizer */
    int doinherit = module_exists("equalizer") ? VLC_VAR_DOINHERIT : 0;
    var_Create (aout, "equalizer-preamp", VLC_VAR_FLOAT | doinherit);
    var_Create (aout, "equalizer-bands", VLC_VAR_STRING | doinherit);
    var_Create (aout, "equalizer-preset", VLC_VAR_STRING | doinherit);

    owner->bitexact = var_InheritBool (aout, "audio-bitexact");

    return aout;
}

audio_output_t *aout_Hold(audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner(aout);

    vlc_atomic_rc_inc(&owner->rc);
    return aout;
}

/**
 * Deinitializes an audio output module and destroys an audio output object.
 */

static void aout_Destroy (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner (aout);

    vlc_mutex_lock(&owner->lock);
    module_unneed (aout, owner->module);
    /* Protect against late call from intf.c */
    aout->volume_set = NULL;
    aout->mute_set = NULL;
    aout->device_select = NULL;
    vlc_audio_meter_Destroy(&owner->meter);
    vlc_mutex_unlock(&owner->lock);

    var_DelCallback (aout, "viewpoint", ViewpointCallback, NULL);
    var_DelCallback (aout, "audio-filter", FilterCallback, NULL);
    var_DelCallback(aout, "device", var_CopyDevice, vlc_object_parent(aout));
    var_DelCallback(aout, "mute", var_Copy, vlc_object_parent(aout));
    var_SetFloat (aout, "volume", -1.f);
    var_DelCallback(aout, "volume", var_Copy, vlc_object_parent(aout));
    var_DelCallback (aout, "stereo-mode", StereoModeCallback, NULL);
    var_DelCallback (aout, "mix-mode", MixModeCallback, NULL);

    aout_dev_t *dev;
    vlc_list_foreach(dev, &owner->dev.list, node)
    {
        vlc_list_remove(&dev->node);
        free (dev->name);
        free (dev);
    }

    vlc_object_delete(VLC_OBJECT(aout));
}

void aout_Release(audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner(aout);

    if (!vlc_atomic_rc_dec(&owner->rc))
        return;

    aout_Destroy(aout);
}

static int aout_PrepareStereoMode(audio_output_t *aout,
                                  const audio_sample_format_t *restrict fmt)
{
    aout_owner_t *owner = aout_owner (aout);

    /* Fill Stereo mode choices */
    vlc_value_t val;
    const char *txt;
    val.i_int = 0;

    if (!AOUT_FMT_LINEAR(fmt) || fmt->i_channels != 2)
        return AOUT_VAR_CHAN_UNSET;

    int i_default_mode = owner->requested_stereo_mode;

    val.i_int = AOUT_VAR_CHAN_MONO;
    var_Change(aout, "stereo-mode", VLC_VAR_ADDCHOICE, val, _("Mono"));

    if (fmt->i_chan_mode & AOUT_CHANMODE_DOLBYSTEREO)
    {
        val.i_int = AOUT_VAR_CHAN_DOLBYS;
        txt = _("Dolby Surround");
    }
    else
    {
        val.i_int = AOUT_VAR_CHAN_STEREO;
        txt = _("Stereo");
    }
    var_Change(aout, "stereo-mode", VLC_VAR_ADDCHOICE, val, txt);

    if (fmt->i_chan_mode & AOUT_CHANMODE_DUALMONO)
        i_default_mode = AOUT_VAR_CHAN_LEFT;
    else
        i_default_mode = val.i_int; /* Stereo or Dolby Surround */

    val.i_int = AOUT_VAR_CHAN_LEFT;
    var_Change(aout, "stereo-mode", VLC_VAR_ADDCHOICE, val, _("Left"));
    val.i_int = AOUT_VAR_CHAN_RIGHT;
    var_Change(aout, "stereo-mode", VLC_VAR_ADDCHOICE, val, _("Right"));

    val.i_int = AOUT_VAR_CHAN_RSTEREO;
    var_Change(aout, "stereo-mode", VLC_VAR_ADDCHOICE, val,
               _("Reverse stereo"));

    return i_default_mode;
}

static void aout_UpdateStereoMode(audio_output_t *aout, int mode,
                                  audio_sample_format_t *restrict fmt,
                                  aout_filters_cfg_t *filters_cfg)
{
    /* The user may have selected a different channels configuration. */
    switch (mode)
    {
        case AOUT_VAR_CHAN_RSTEREO:
            filters_cfg->remap[AOUT_CHANIDX_LEFT] = AOUT_CHANIDX_RIGHT;
            filters_cfg->remap[AOUT_CHANIDX_RIGHT] = AOUT_CHANIDX_LEFT;
            break;
        case AOUT_VAR_CHAN_STEREO:
            break;
        case AOUT_VAR_CHAN_LEFT:
            filters_cfg->remap[AOUT_CHANIDX_RIGHT] = AOUT_CHANIDX_DISABLE;
            fmt->i_physical_channels = AOUT_CHAN_CENTER;
            aout_FormatPrepare (fmt);
            break;
        case AOUT_VAR_CHAN_RIGHT:
            filters_cfg->remap[AOUT_CHANIDX_LEFT] = AOUT_CHANIDX_DISABLE;
            fmt->i_physical_channels = AOUT_CHAN_CENTER;
            aout_FormatPrepare (fmt);
            break;
        case AOUT_VAR_CHAN_DOLBYS:
            fmt->i_chan_mode = AOUT_CHANMODE_DOLBYSTEREO;
            break;
        case AOUT_VAR_CHAN_MONO:
            /* Remix all channels into one */
            for (size_t i = 0; i < AOUT_CHANIDX_MAX; ++ i)
                filters_cfg->remap[i] = AOUT_CHANIDX_LEFT;
            break;
        default:
            break;
    }

    var_Change(aout, "stereo-mode", VLC_VAR_SETVALUE,
               (vlc_value_t) { .i_int = mode});
}

static bool aout_HasStereoMode(audio_output_t *aout, int mode)
{
    bool mode_available = false;
    vlc_value_t *vals;
    size_t count;

    if (!var_Change(aout, "stereo-mode", VLC_VAR_GETCHOICES,
                    &count, &vals, (char ***)NULL))
    {
        for (size_t i = 0; !mode_available && i < count; ++i)
        {
            if (vals[i].i_int == mode)
                mode_available = true;
        }
        free(vals);
    }
    return mode_available;
}

static void aout_AddMixModeChoice(audio_output_t *aout, int mode,
                                  const char *suffix,
                                  const audio_sample_format_t *restrict fmt)
{
    assert(suffix);
    const char *text;
    char *buffer = NULL;

    if (fmt == NULL)
        text = suffix;
    else
    {
        const char *channels = aout_FormatPrintChannels(fmt);
        if (asprintf(&buffer, "%s: %s", suffix, channels) < 0)
            return;
        text = buffer;
    }

    vlc_value_t val = { .i_int = mode };
    var_Change(aout, "mix-mode", VLC_VAR_ADDCHOICE, val, text);

    free(buffer);
}

static void aout_SetupMixModeChoices (audio_output_t *aout,
                                      const audio_sample_format_t *restrict fmt)
{
    if (fmt->i_channels <= 2)
        return;

    const bool has_spatialaudio = module_exists("spatialaudio");

    /* Don't propose the mix option if we don't have the spatialaudio module
     * and if the content is ambisonics */

    if (fmt->channel_type != AUDIO_CHANNEL_TYPE_AMBISONICS || has_spatialaudio)
    {
        aout_AddMixModeChoice(aout, AOUT_MIX_MODE_UNSET, _("Original"), fmt);
        aout_AddMixModeChoice(aout, AOUT_MIX_MODE_STEREO, _("Stereo"), NULL);
    }

    if (has_spatialaudio)
        aout_AddMixModeChoice(aout, AOUT_MIX_MODE_BINAURAL, _("Binaural"), NULL);

    /* Only propose Original and Binaural for Ambisonics content */
    if (fmt->channel_type == AUDIO_CHANNEL_TYPE_AMBISONICS && has_spatialaudio)
        return;

    if (fmt->i_physical_channels != AOUT_CHANS_4_0)
    {
        static const audio_sample_format_t fmt_4_0 = {
            .i_physical_channels = AOUT_CHANS_4_0,
            .i_channels = 4,
        };
        aout_AddMixModeChoice(aout, AOUT_MIX_MODE_4_0, _("4.0"), &fmt_4_0);
    }

    if (fmt->i_physical_channels != AOUT_CHANS_5_1)
    {
        static const audio_sample_format_t fmt_5_1 = {
            .i_physical_channels = AOUT_CHANS_5_1,
            .i_channels = 6,
        };
        aout_AddMixModeChoice(aout, AOUT_MIX_MODE_5_1, _("5.1"), &fmt_5_1);
    }

    if (fmt->i_physical_channels != AOUT_CHANS_7_1)
    {
        static const audio_sample_format_t fmt_7_1 = {
            .i_physical_channels = AOUT_CHANS_7_1,
            .i_channels = 8,
        };
        aout_AddMixModeChoice(aout, AOUT_MIX_MODE_7_1, _("7.1"), &fmt_7_1);
    }
}

static bool aout_HasMixModeChoice(audio_output_t *aout, int mode)
{
    bool mode_available = false;
    vlc_value_t *vals;
    size_t count;

    if (!var_Change(aout, "mix-mode", VLC_VAR_GETCHOICES,
                    &count, &vals, (char ***)NULL))
    {
        for (size_t i = 0; !mode_available && i < count; ++i)
        {
            if (vals[i].i_int == mode)
                mode_available = true;
        }
        free(vals);
    }
    return mode_available;
}


static void aout_UpdateMixMode(audio_output_t *aout, int mode,
                               audio_sample_format_t *restrict fmt)
{
    /* The user may have selected a different channels configuration. */
    switch (mode)
    {
        case AOUT_MIX_MODE_UNSET:
            break;
        case AOUT_MIX_MODE_BINAURAL:
            fmt->i_physical_channels = AOUT_CHANS_STEREO;
            fmt->i_chan_mode = AOUT_CHANMODE_BINAURAL;
            break;
        case AOUT_MIX_MODE_STEREO:
            fmt->i_physical_channels = AOUT_CHANS_STEREO;
            break;
        case AOUT_MIX_MODE_4_0:
            fmt->i_physical_channels = AOUT_CHANS_4_0;
            break;
        case AOUT_MIX_MODE_5_1:
            fmt->i_physical_channels = AOUT_CHANS_5_1;
            break;
        case AOUT_MIX_MODE_7_1:
            fmt->i_physical_channels = AOUT_CHANS_7_1;
            break;
        default:
            break;
    }

    assert(mode == AOUT_VAR_CHAN_UNSET || aout_HasMixModeChoice(aout, mode));

    var_Change(aout, "mix-mode", VLC_VAR_SETVALUE, (vlc_value_t) { .i_int = mode});
}

int aout_OutputNew(audio_output_t *aout, vlc_aout_stream *stream,
                   audio_sample_format_t *fmt, int input_profile,
                   audio_sample_format_t *filter_fmt,
                   aout_filters_cfg_t *filters_cfg)
{
    aout_owner_t *owner = aout_owner (aout);

    vlc_fourcc_t formats[] = {
        fmt->i_format, 0, 0
    };

    var_Change(aout, "stereo-mode", VLC_VAR_CLEARCHOICES);
    var_Change(aout, "mix-mode", VLC_VAR_CLEARCHOICES);

    /* Ideally, the audio filters would be created before the audio output,
     * and the ideal audio format would be the output of the filters chain.
     * But that scheme would not really play well with digital pass-through. */

    if (AOUT_FMT_LINEAR(fmt))
    {
        if (fmt->channel_type == AUDIO_CHANNEL_TYPE_BITMAP
         && aout_FormatNbChannels(fmt) == 0)
        {
            /* The output channel map is unknown, use the WAVE one. */
            assert(fmt->i_channels > 0);
            aout_SetWavePhysicalChannels(fmt);
        }

        if (fmt->channel_type == AUDIO_CHANNEL_TYPE_AMBISONICS)
        {
            /* Set the maximum of channels to render ambisonics contents. The
             * aout module will still be free to select less channels in order
             * to respect the sink setup. */

            fmt->i_physical_channels = AOUT_CHANS_7_1;
        }

        /* Try to stay in integer domain if possible for no/slow FPU. */
        fmt->i_format = (fmt->i_bitspersample > 16) ? VLC_CODEC_FL32
                                                    : VLC_CODEC_S16N;

        aout_SetupMixModeChoices(aout, fmt);

        /* Prefer the user requested mode if available, otherwise, use the
         * default one */

        if (aout_HasMixModeChoice(aout, owner->requested_mix_mode))
            aout_UpdateMixMode(aout, owner->requested_mix_mode, fmt);

        aout_FormatPrepare (fmt);
        assert (aout_FormatNbChannels(fmt) > 0);
    }
    else
    {
        switch (fmt->i_format)
        {
            static_assert(ARRAY_SIZE(formats) >= 3, "fallback array too small");
            case VLC_CODEC_DTS:
                if (input_profile > 0)
                {
                    /* DTSHD can be played as DTSHD or as DTS */
                    formats[0] = VLC_CODEC_DTSHD;
                    formats[1] = VLC_CODEC_DTS;
                }
                break;
            case VLC_CODEC_A52:
                if (input_profile > 0)
                {
                    formats[0] = VLC_CODEC_EAC3;
                    formats[1] = VLC_CODEC_A52;
                }
                break;
            default:
                break;
        }
    }

    int stereo_mode = aout_PrepareStereoMode(aout, fmt);

    if (stereo_mode != AOUT_VAR_CHAN_UNSET
     && aout_HasStereoMode(aout, stereo_mode))
        aout_UpdateStereoMode(aout, stereo_mode, fmt, filters_cfg);

    aout->current_sink_info.headphones = false;

    vlc_mutex_lock(&owner->lock);
    /* XXX: Remove when aout/stream support is complete (in all modules) */
    assert(owner->main_stream == NULL);

    int ret = VLC_EGENERIC;
    for (size_t i = 0; formats[i] != 0 && ret != VLC_SUCCESS; ++i)
    {
        filter_fmt->i_format = fmt->i_format = formats[i];
        owner->main_stream = stream;
        ret = aout->start(aout, fmt);
        if (ret != 0)
            owner->main_stream = NULL;
    }
    vlc_mutex_unlock(&owner->lock);
    if (ret)
    {
        if (AOUT_FMT_LINEAR(fmt))
            msg_Err (aout, "failed to start audio output");
        else
            msg_Warn (aout, "failed to start passthrough audio output, "
                      "failing back to linear format");
        return -1;
    }
    assert(aout->flush != NULL && aout->play != NULL);

    /* Autoselect the headphones mode if available and if the user didn't
     * request any mode */

    if (aout->current_sink_info.headphones
     && owner->requested_mix_mode == AOUT_VAR_CHAN_UNSET
     && fmt->i_physical_channels == AOUT_CHANS_STEREO
     && aout_HasMixModeChoice(aout, AOUT_MIX_MODE_BINAURAL))
    {
        assert(stereo_mode == AOUT_VAR_CHAN_UNSET);
        aout_UpdateMixMode(aout, AOUT_MIX_MODE_BINAURAL, fmt);
    }

    aout_FormatPrepare (fmt);
    assert (fmt->i_bytes_per_frame > 0 && fmt->i_frame_length > 0);
    aout_FormatPrint (aout, "output", fmt);

    return 0;
}

void aout_OutputDelete (audio_output_t *aout)
{
    aout_owner_t *owner = aout_owner(aout);
    vlc_mutex_lock(&owner->lock);
    aout->stop (aout);
    owner->main_stream = NULL;
    vlc_mutex_unlock(&owner->lock);
}

float aout_VolumeGet (audio_output_t *aout)
{
    return var_GetFloat (aout, "volume");
}

int aout_VolumeSet (audio_output_t *aout, float vol)
{
    aout_owner_t *owner = aout_owner(aout);
    int ret;

    vlc_mutex_lock(&owner->lock);
    ret = aout->volume_set ? aout->volume_set(aout, vol) : -1;
    vlc_mutex_unlock(&owner->lock);
    return ret ? -1 : 0;
}

int aout_VolumeUpdate (audio_output_t *aout, int value, float *volp)
{
    int ret = -1;
    const float defaultVolume = (float)AOUT_VOLUME_DEFAULT;
    const float stepSize = var_InheritFloat (aout, "volume-step") / defaultVolume;
    float vol = aout_VolumeGet (aout);

    if (vol >= 0.f)
    {
        vol += (value * stepSize);
        vol = (roundf (vol / stepSize)) * stepSize;
        vol = clampf(vol, 0.f, AOUT_VOLUME_MAX / defaultVolume);
        if (volp != NULL)
            *volp = vol;
        ret = aout_VolumeSet (aout, vol);
    }
    return ret;
}

int aout_MuteGet (audio_output_t *aout)
{
    return var_InheritBool (aout, "mute");
}

int aout_MuteSet (audio_output_t *aout, bool mute)
{
    aout_owner_t *owner = aout_owner(aout);
    int ret;

    vlc_mutex_lock(&owner->lock);
    ret = aout->mute_set ? aout->mute_set(aout, mute) : -1;
    vlc_mutex_unlock(&owner->lock);
    return ret ? -1 : 0;
}

char *aout_DeviceGet (audio_output_t *aout)
{
    return var_GetNonEmptyString (aout, "device");
}

int aout_DeviceSet (audio_output_t *aout, const char *id)
{
    aout_owner_t *owner = aout_owner(aout);
    int ret;

    vlc_mutex_lock(&owner->lock);
    ret = aout->device_select ? aout->device_select(aout, id) : -1;
    vlc_mutex_unlock(&owner->lock);
    return ret ? -1 : 0;
}

int aout_DevicesList (audio_output_t *aout, char ***ids, char ***names)
{
    aout_owner_t *owner = aout_owner (aout);
    char **tabid, **tabname;
    unsigned i = 0;

    vlc_mutex_lock (&owner->dev.lock);
    tabid = vlc_alloc (owner->dev.count, sizeof (*tabid));
    tabname = vlc_alloc (owner->dev.count, sizeof (*tabname));

    if (unlikely(tabid == NULL || tabname == NULL))
        goto error;

    *ids = tabid;
    *names = tabname;

    aout_dev_t *dev;
    vlc_list_foreach(dev, &owner->dev.list, node)
    {
        tabid[i] = strdup(dev->id);
        if (unlikely(tabid[i] == NULL))
            goto error;

        tabname[i] = strdup(dev->name);
        if (unlikely(tabname[i] == NULL))
        {
            free(tabid[i]);
            goto error;
        }

        i++;
    }
    vlc_mutex_unlock (&owner->dev.lock);

    return i;

error:
    vlc_mutex_unlock(&owner->dev.lock);
    while (i > 0)
    {
        i--;
        free(tabname[i]);
        free(tabid[i]);
    }
    free(tabname);
    free(tabid);
    return -1;
}

static void aout_ChangeViewpoint(audio_output_t *aout,
                                 const vlc_viewpoint_t *p_viewpoint)
{
    aout_owner_t *owner = aout_owner(aout);

    vlc_mutex_lock(&owner->vp.lock);
    owner->vp.value = *p_viewpoint;
    atomic_store_explicit(&owner->vp.update, true, memory_order_relaxed);
    vlc_mutex_unlock(&owner->vp.lock);
}

vlc_audio_meter_plugin *
aout_AddMeterPlugin(audio_output_t *aout, const char *chain,
                    const struct vlc_audio_meter_plugin_owner *meter_plugin_owner)
{
    aout_owner_t *owner = aout_owner(aout);

    return vlc_audio_meter_AddPlugin(&owner->meter, chain, meter_plugin_owner);
}

void
aout_RemoveMeterPlugin(audio_output_t *aout, vlc_audio_meter_plugin *plugin)
{
    aout_owner_t *owner = aout_owner(aout);

    vlc_audio_meter_RemovePlugin(&owner->meter, plugin);
}

Messung
CHZG
83949992

¤ Dauer der Verarbeitung: 0.5 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104848
#Domains=416967