[vlc-devel] [PATCH 3/4] aout: propose a "Direct" choice in Output Mode

Thomas Guillem thomas at gllm.fr
Fri Mar 30 13:57:11 CEST 2018


This choice is only proposed for compatible es tracks and when the aout module
can't fetch the passthrough preference from the OS (this is the case for
mmdevice, cf. next commit).

We need to pass the input codec from the decoder to the aout in order to know
if the current track is compatible with the direct mode (cf. AOUT_FMT_SPDIF and
AOUT_FMT_HDMI).
---
 include/vlc_aout.h               | 26 ++++++++++++
 src/audio_output/aout_internal.h |  4 +-
 src/audio_output/dec.c           |  3 +-
 src/audio_output/output.c        | 85 ++++++++++++++++++++++++++++++++++------
 src/input/decoder.c              |  2 +-
 src/libvlccore.sym               |  1 +
 6 files changed, 107 insertions(+), 14 deletions(-)

diff --git a/include/vlc_aout.h b/include/vlc_aout.h
index b9cf6615f1..1a650a1068 100644
--- a/include/vlc_aout.h
+++ b/include/vlc_aout.h
@@ -97,6 +97,7 @@
 #define AOUT_VAR_CHAN_DOLBYS        5
 #define AOUT_VAR_CHAN_HEADPHONES    6
 #define AOUT_VAR_CHAN_MONO          7
+#define AOUT_VAR_CHAN_DIRECT        8
 
 /*****************************************************************************
  * Main audio output structures
@@ -173,6 +174,14 @@ struct audio_output
     struct {
         bool headphones; /**< Default to false, set it to true if the current
                               sink is using headphones */
+        enum
+        {
+            AOUT_DIRECT_HANDLED_BY_OS,
+            AOUT_DIRECT_NOT_CAPABLE,
+            AOUT_DIRECT_CAPABLE,
+
+        } direct; /**< Default to AOUT_DIRECT_HANDLED_BY_OS. If CAPABLE,
+                       "Direct" will be proposed in Output Modes. */
     } current_sink_info;
     /**< Current sink informations set by the module from the start() function */
 
@@ -303,6 +312,23 @@ VLC_API char *aout_DeviceGet (audio_output_t *);
 VLC_API int aout_DeviceSet (audio_output_t *, const char *);
 VLC_API int aout_DevicesList (audio_output_t *, char ***, char ***);
 
+enum aout_direct_mode {
+    /** Follow aout preferences. */
+    AOUT_DIRECT_DEFAULT,
+    /** Direct mode requested by the user */
+    AOUT_DIRECT_ENABLED,
+    /** Linear mode requested by the user */
+    AOUT_DIRECT_DISABLED,
+};
+
+/**
+ * Fetch the direct mode requested by the user
+ *
+ * Only valid from the start callback and if current_sink_info.direct is
+ * changed from this module.
+ */
+VLC_API enum aout_direct_mode aout_GetDirectMode(audio_output_t *);
+
 /**
  * Report change of configured audio volume to the core and UI.
  */
diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index 96f83618cc..6b345c42b2 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -85,6 +85,8 @@ typedef struct
     } sync;
 
     int requested_output_mode; /**< Requested output mode set by the user */
+    enum aout_direct_mode direct_mode;
+    vlc_fourcc_t input_codec;
 
     audio_sample_format_t input_format;
     audio_sample_format_t mixer_format;
@@ -151,7 +153,7 @@ bool aout_ChangeFilterString( vlc_object_t *manager, vlc_object_t *aout,
 #define AOUT_DEC_CHANGED 1
 #define AOUT_DEC_FAILED VLC_EGENERIC
 
-int aout_DecNew(audio_output_t *, const audio_sample_format_t *,
+int aout_DecNew(audio_output_t *, vlc_fourcc_t, const audio_sample_format_t *,
                 const audio_replay_gain_t *, const aout_request_vout_t *);
 void aout_DecDelete(audio_output_t *);
 int aout_DecPlay(audio_output_t *, block_t *, int i_input_rate);
diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index 2c5706876a..436bbd5135 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -40,7 +40,7 @@
 /**
  * Creates an audio output
  */
-int aout_DecNew( audio_output_t *p_aout,
+int aout_DecNew( audio_output_t *p_aout, vlc_fourcc_t i_input_codec,
                  const audio_sample_format_t *p_format,
                  const audio_replay_gain_t *p_replay_gain,
                  const aout_request_vout_t *p_request_vout )
@@ -80,6 +80,7 @@ int aout_DecNew( audio_output_t *p_aout,
     owner->volume = aout_volume_New (p_aout, p_replay_gain);
 
     atomic_store (&owner->restart, 0);
+    owner->input_codec  = i_input_codec;
     owner->input_format = *p_format;
     owner->mixer_format = owner->input_format;
     owner->request_vout = *p_request_vout;
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 6f16ebe66d..63e724e791 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -175,17 +175,35 @@ static int AoutModeCallback (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;
+    (void)varname; (void)data;
 
     aout_owner_t *owner = aout_owner (aout);
     vlc_mutex_lock (&owner->lock);
     owner->requested_output_mode = newval.i_int;
-    vlc_mutex_unlock (&owner->lock);
 
-    aout_RestartRequest (aout, AOUT_RESTART_OUTPUTMODE);
+    if( oldval.i_int == AOUT_VAR_CHAN_DIRECT
+     || newval.i_int == AOUT_VAR_CHAN_DIRECT )
+    {
+        const bool enable_direct = newval.i_int == AOUT_VAR_CHAN_DIRECT;
+
+        owner->direct_mode = enable_direct ? AOUT_DIRECT_ENABLED : AOUT_DIRECT_DISABLED;
+
+        aout_RestartRequest (aout, AOUT_RESTART_OUTPUT); /* full restart */
+    }
+    else
+        aout_RestartRequest (aout, AOUT_RESTART_OUTPUTMODE);
+
+    vlc_mutex_unlock (&owner->lock);
     return 0;
 }
 
+enum aout_direct_mode aout_GetDirectMode(audio_output_t *aout)
+{
+    aout_owner_t *owner = aout_owner (aout);
+    aout_OutputAssertLocked (aout);
+    return owner->direct_mode;
+}
+
 static int ViewpointCallback (vlc_object_t *obj, const char *var,
                               vlc_value_t prev, vlc_value_t cur, void *data)
 {
@@ -344,6 +362,18 @@ audio_output_t *aout_New (vlc_object_t *parent)
     /* Stereo mode */
     var_Create (aout, "aout-mode", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
     owner->requested_output_mode = var_GetInteger (aout, "aout-mode");
+    switch (owner->requested_output_mode)
+    {
+        case AOUT_VAR_CHAN_UNSET:
+            owner->direct_mode = AOUT_DIRECT_DEFAULT;
+            break;
+        case AOUT_VAR_CHAN_DIRECT:
+            owner->direct_mode = AOUT_DIRECT_ENABLED;
+            break;
+        default:
+            owner->direct_mode = AOUT_DIRECT_DISABLED;
+            break;
+    }
 
     var_AddCallback (aout, "aout-mode", AoutModeCallback, NULL);
     vlc_value_t txt;
@@ -421,7 +451,22 @@ static void aout_PrepareOutputMode (audio_output_t *aout,
     int i_output_mode = owner->requested_output_mode;
     int i_default_mode = AOUT_VAR_CHAN_UNSET;
 
-    if (!AOUT_FMT_LINEAR(fmt))
+    bool has_direct_mode = aout->current_sink_info.direct == AOUT_DIRECT_CAPABLE;
+    if (has_direct_mode)
+    {
+        /* The current sink is direct capable: now check if the input codec is
+         * compatible */
+        aout_owner_t *owner = aout_owner (aout);
+        const audio_format_t fmttest = { .i_format = owner->input_codec };
+        if (!AOUT_FMT_SPDIF(&fmttest) && !AOUT_FMT_HDMI(&fmttest))
+            has_direct_mode = false;
+    }
+
+    const bool is_linear = AOUT_FMT_LINEAR(fmt);
+
+    /* Don't propose any choice if the current sink is encoded and if the
+     * direct mode is handled by the OS. */
+    if (!is_linear && !has_direct_mode)
         return;
 
     if (i_nb_input_channels > 1)
@@ -468,15 +513,26 @@ static void aout_PrepareOutputMode (audio_output_t *aout,
         var_Change (aout, "aout-mode", VLC_VAR_ADDCHOICE, &val, &txt);
     }
 
-    if (input_chan_type == AUDIO_CHANNEL_TYPE_AMBISONICS
-     || i_nb_input_channels > 2)
+    if (!has_direct_mode)
     {
-        val.i_int = AOUT_VAR_CHAN_HEADPHONES;
-        txt.psz_string = _("Headphones");
-        var_Change (aout, "aout-mode", VLC_VAR_ADDCHOICE, &val, &txt);
+        if (input_chan_type == AUDIO_CHANNEL_TYPE_AMBISONICS
+         || i_nb_input_channels > 2)
+        {
+            val.i_int = AOUT_VAR_CHAN_HEADPHONES;
+            txt.psz_string = _("Headphones");
+            var_Change (aout, "aout-mode", VLC_VAR_ADDCHOICE, &val, &txt);
 
-        if (aout->current_sink_info.headphones)
-            i_default_mode = AOUT_VAR_CHAN_HEADPHONES;
+            if (aout->current_sink_info.headphones)
+                i_default_mode = AOUT_VAR_CHAN_HEADPHONES;
+        }
+    }
+    else
+    {
+        val.i_int = AOUT_VAR_CHAN_DIRECT;
+        txt.psz_string = _("Direct");
+        var_Change (aout, "aout-mode", VLC_VAR_ADDCHOICE, &val, &txt);
+        if (!is_linear)
+            i_default_mode = AOUT_VAR_CHAN_DIRECT;
     }
 
     bool mode_available = false;
@@ -522,6 +578,8 @@ static void aout_PrepareOutputMode (audio_output_t *aout,
             for (size_t i = 0; i < AOUT_CHANIDX_MAX; ++ i)
                 filters_cfg->remap[i] = AOUT_CHANIDX_LEFT;
             break;
+        case AOUT_VAR_CHAN_DIRECT:
+            break;
         default:
             break;
     }
@@ -583,6 +641,7 @@ int aout_OutputNew (audio_output_t *aout, audio_sample_format_t *restrict fmt,
     }
 
     aout->current_sink_info.headphones = false;
+    aout->current_sink_info.direct = AOUT_DIRECT_HANDLED_BY_OS;
 
     if (aout->start (aout, fmt))
     {
@@ -590,6 +649,10 @@ int aout_OutputNew (audio_output_t *aout, audio_sample_format_t *restrict fmt,
         return -1;
     }
 
+    /* Can't be both headphones and direct capable */
+    assert(!aout->current_sink_info.headphones ||
+           aout->current_sink_info.direct != AOUT_DIRECT_CAPABLE);
+
     aout_PrepareOutputMode (aout, fmt, filters_cfg, input_chan_type,
                             i_nb_input_channels);
 
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 98817e6f39..2aec72814b 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -369,7 +369,7 @@ static int aout_update_format( decoder_t *p_dec )
             if( p_dec->fmt_out.i_codec == VLC_CODEC_DTS )
                 var_SetBool( p_aout, "dtshd", p_dec->fmt_out.i_profile > 0 );
 
-            if( aout_DecNew( p_aout, &format,
+            if( aout_DecNew( p_aout, p_dec->fmt_in.i_codec, &format,
                              &p_dec->fmt_out.audio_replay_gain,
                              &request_vout ) )
             {
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index b119285cdb..97b1f67183 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -6,6 +6,7 @@ aout_ChannelExtract
 aout_ChannelReorder
 aout_CheckChannelExtraction
 aout_CheckChannelReorder
+aout_GetDirectMode
 aout_Interleave
 aout_Deinterleave
 aout_filter_RequestVout
-- 
2.11.0



More information about the vlc-devel mailing list