[vlc-devel] [PATCH V2 3/8] aout: add exclusive_mode support

Thomas Guillem thomas at gllm.fr
Fri Nov 8 18:13:09 CET 2019


- VLC_AOUT_EXCLUSIVE_ON will disable any filters/resampler/converter and will
  work only if the input and output formats are compatible.

- VLC_AOUT_EXCLUSIVE_FORCED will disable any filters/resampler but will try to
  adapt the input format to the output format by adding a converter

- VLC_AOUT_EXCLUSIVE_OFF will act as normal.
---
 include/vlc_aout.h               |  8 +++
 src/audio_output/aout_internal.h |  1 +
 src/audio_output/dec.c           |  2 +
 src/audio_output/filters.c       | 85 +++++++++++++++++++++-----------
 src/audio_output/output.c        | 15 +++++-
 src/libvlc-module.c              | 19 +++++++
 6 files changed, 99 insertions(+), 31 deletions(-)

diff --git a/include/vlc_aout.h b/include/vlc_aout.h
index 46022e98625..677897a0bb8 100644
--- a/include/vlc_aout.h
+++ b/include/vlc_aout.h
@@ -112,6 +112,12 @@
 /* FIXME to remove once aout.h is cleaned a bit more */
 #include <vlc_block.h>
 
+enum vlc_aout_exclusive_mode {
+    VLC_AOUT_EXCLUSIVE_OFF,
+    VLC_AOUT_EXCLUSIVE_ON,
+    VLC_AOUT_EXCLUSIVE_FORCED,
+};
+
 struct vlc_audio_output_events {
     void (*timing_report)(audio_output_t *, vlc_tick_t system_now, vlc_tick_t pts);
     void (*volume_report)(audio_output_t *, float);
@@ -510,11 +516,13 @@ typedef struct
      * binauralizer audio filter).
      */
     bool headphones;
+    enum vlc_aout_exclusive_mode exclusive_mode;
 } aout_filters_cfg_t;
 
 #define AOUT_FILTERS_CFG_INIT (aout_filters_cfg_t) \
     { .remap = AOUT_CHAN_REMAP_INIT, \
       .headphones = false, \
+      .exclusive_mode = VLC_AOUT_EXCLUSIVE_OFF, \
     };
 
 typedef struct aout_filters aout_filters_t;
diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index a94d0864105..2959290a813 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -46,6 +46,7 @@ typedef struct
     module_t *module; /**< Output plugin (or NULL if inactive) */
     aout_filters_t *filters;
     aout_volume_t *volume;
+    enum vlc_aout_exclusive_mode exclusive_mode;
 
     struct
     {
diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index d89fedbf62c..0f4878e3ed2 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -98,6 +98,7 @@ int aout_DecNew(audio_output_t *p_aout, const audio_sample_format_t *p_format,
     owner->sync.clock = clock;
 
     owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
+    owner->filters_cfg.exclusive_mode = owner->exclusive_mode;
     if (aout_OutputNew (p_aout))
         goto error;
     aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
@@ -164,6 +165,7 @@ static int aout_CheckReady (audio_output_t *aout)
                 aout_OutputDelete (aout);
             owner->filter_format = owner->mixer_format = owner->input_format;
             owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
+            owner->filters_cfg.exclusive_mode = owner->exclusive_mode;
             if (aout_OutputNew (aout))
                 owner->mixer_format.i_format = 0;
             aout_volume_SetFormat (owner->volume,
diff --git a/src/audio_output/filters.c b/src/audio_output/filters.c
index a297f4c6974..ef8a278f43f 100644
--- a/src/audio_output/filters.c
+++ b/src/audio_output/filters.c
@@ -582,35 +582,57 @@ aout_filters_t *aout_FiltersNewWithClock(vlc_object_t *obj, const vlc_clock_t *c
 
     assert(input_format.channel_type == AUDIO_CHANNEL_TYPE_BITMAP);
 
-    /* parse user filter lists */
-    if (var_InheritBool (obj, "audio-time-stretch"))
+    bool exclusive_forced = false;
+    if (cfg)
     {
-        if (AppendFilter(obj, "audio filter", "scaletempo",
-                         filters, &input_format, &output_format, NULL) == 0)
-            filters->rate_filter = filters->tab[filters->count - 1];
+        if (cfg->exclusive_mode == VLC_AOUT_EXCLUSIVE_ON)
+        {
+            /* Exclusive mode is not possible if input and output formats don't
+             * match */
+            if (!AOUT_FMTS_IDENTICAL(&input_format, &output_format))
+                goto error;
+            return filters;
+        }
+        else if (cfg->exclusive_mode == VLC_AOUT_EXCLUSIVE_FORCED)
+        {
+            /* Forced exclusive mode is mode permissive. Allow to add visual
+             * filters and a converter, but don't insert any resamplers */
+            exclusive_forced = true;
+        }
     }
 
-    if (cfg != NULL)
+    if (!exclusive_forced)
     {
-        AppendRemapFilter(obj, filters, &input_format, &output_format,
-                          cfg->remap);
+        /* parse user filter lists */
+        if (var_InheritBool (obj, "audio-time-stretch"))
+        {
+            if (AppendFilter(obj, "audio filter", "scaletempo",
+                             filters, &input_format, &output_format, NULL) == 0)
+                filters->rate_filter = filters->tab[filters->count - 1];
+        }
 
-        if (input_format.i_channels > 2 && cfg->headphones)
-            AppendFilter(obj, "audio filter", "binauralizer", filters,
-                         &input_format, &output_format, NULL);
-    }
+        if (cfg != NULL)
+        {
+            AppendRemapFilter(obj, filters, &input_format, &output_format,
+                              cfg->remap);
 
-    /* Now add user filters */
-    char *str = var_InheritString (obj, "audio-filter");
-    if (str != NULL)
-    {
-        char *p = str, *name;
-        while ((name = strsep (&p, " :")) != NULL)
+            if (input_format.i_channels > 2 && cfg->headphones)
+                AppendFilter(obj, "audio filter", "binauralizer", filters,
+                             &input_format, &output_format, NULL);
+        }
+
+        /* Now add user filters */
+        char *str = var_InheritString (obj, "audio-filter");
+        if (str != NULL)
         {
-            AppendFilter(obj, "audio filter", name, filters,
-                         &input_format, &output_format, NULL);
+            char *p = str, *name;
+            while ((name = strsep (&p, " :")) != NULL)
+            {
+                AppendFilter(obj, "audio filter", name, filters,
+                             &input_format, &output_format, NULL);
+            }
+            free (str);
         }
-        free (str);
     }
 
     char *visual = var_InheritString(obj, "audio-visual");
@@ -630,17 +652,20 @@ aout_filters_t *aout_FiltersNewWithClock(vlc_object_t *obj, const vlc_clock_t *c
     input_format = output_format;
 
     /* insert the resampler */
-    output_format.i_rate = outfmt->i_rate;
-    assert (AOUT_FMTS_IDENTICAL(&output_format, outfmt));
-    filters->resampler = FindResampler (obj, &input_format,
-                                        &output_format);
-    if (filters->resampler == NULL && input_format.i_rate != outfmt->i_rate)
+    if (!exclusive_forced)
     {
-        msg_Err (obj, "cannot setup a resampler");
-        goto error;
+        output_format.i_rate = outfmt->i_rate;
+        assert (AOUT_FMTS_IDENTICAL(&output_format, outfmt));
+        filters->resampler = FindResampler (obj, &input_format,
+                                            &output_format);
+        if (filters->resampler == NULL && input_format.i_rate != outfmt->i_rate)
+        {
+            msg_Err (obj, "cannot setup a resampler");
+            goto error;
+        }
+        if (filters->rate_filter == NULL)
+            filters->rate_filter = filters->resampler;
     }
-    if (filters->rate_filter == NULL)
-        filters->rate_filter = filters->resampler;
 
     return filters;
 
diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 4177b3bfe03..55795e83b80 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -338,6 +338,18 @@ audio_output_t *aout_New (vlc_object_t *parent)
     var_Create (aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
     var_Create (aout, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
 
+    char *exclusive_str = var_InheritString (aout, "aout-exclusive");
+    if (!exclusive_str)
+        owner->exclusive_mode = VLC_AOUT_EXCLUSIVE_OFF;
+    else if (strcmp(exclusive_str, "on") == 0)
+        owner->exclusive_mode = VLC_AOUT_EXCLUSIVE_ON;
+    else if (strcmp(exclusive_str, "forced") == 0)
+        owner->exclusive_mode = VLC_AOUT_EXCLUSIVE_FORCED;
+    else
+        owner->exclusive_mode = VLC_AOUT_EXCLUSIVE_OFF;
+
+    free (exclusive_str);
+
     return aout;
 }
 
@@ -600,7 +612,8 @@ int aout_OutputNew (audio_output_t *aout)
     for (size_t i = 0; formats[i] != 0 && ret != VLC_SUCCESS; ++i)
     {
         filter_fmt->i_format = fmt->i_format = formats[i];
-        ret = aout->start(aout, fmt, owner->exclusive_mode);
+        ret = aout->start(aout, fmt,
+                          owner->exclusive_mode != VLC_AOUT_EXCLUSIVE_OFF);
     }
     vlc_mutex_unlock(&owner->lock);
     if (ret)
diff --git a/src/libvlc-module.c b/src/libvlc-module.c
index 9dc892e82bf..1fe7a40a0af 100644
--- a/src/libvlc-module.c
+++ b/src/libvlc-module.c
@@ -124,6 +124,14 @@ static const char *const ppsz_snap_formats[] =
 #define ROLE_TEXT N_("Media role")
 #define ROLE_LONGTEXT N_("Media (player) role for operating system policy.")
 
+#define AOUT_EXCLUSIVE_TEXT N_("Exclusive mode")
+#define AOUT_EXCLUSIVE_LONGTEXT N_( \
+    "VLC will have a direct connection of the audio endpoint device. " \
+    "This mode can be used to reduce the audio latency or " \
+    "to assure that the audio stream won't be modified by the OS. " \
+    "This mode is more likely to fail if the soundcard format is not handled " \
+    "by VLC or if the audio output isn't compatible." )
+
 #define AUDIO_TEXT N_("Enable audio")
 #define AUDIO_LONGTEXT N_( \
     "You can completely disable the audio output. The audio " \
@@ -139,6 +147,14 @@ static const char *ppsz_roles_text[] = {
     N_("Accessibility"), N_("Test"),
 };
 
+static const char *ppsz_aout_exclusive[] = {
+    "off", "on", "forced"
+};
+static const char *ppsz_aout_exclusive_text[] = {
+    N_("Off"), N_("On"),
+    N_("Forced (with audio conversion)")
+};
+
 #define GAIN_TEXT N_("Audio gain")
 #define GAIN_LONGTEXT N_( \
     "This linear gain will be applied to outputted audio.")
@@ -1617,6 +1633,9 @@ vlc_module_begin ()
         change_short('A')
     add_string( "role", "video", ROLE_TEXT, ROLE_LONGTEXT, true )
         change_string_list( ppsz_roles, ppsz_roles_text )
+    add_string( "aout-exclusive", "off", AOUT_EXCLUSIVE_TEXT,
+                AOUT_EXCLUSIVE_LONGTEXT, false )
+        change_string_list( ppsz_aout_exclusive, ppsz_aout_exclusive_text )
 
     set_subcategory( SUBCAT_AUDIO_AFILTER )
     add_module_list("audio-filter", "audio filter", NULL,
-- 
2.20.1



More information about the vlc-devel mailing list