[vlc-devel] [PATCH 15/16] pulse: handle AUDIO_CHANNELS_TYPE_AMBISONICS

Thomas Guillem thomas at gllm.fr
Fri Jul 7 16:03:01 CEST 2017


---
 modules/audio_output/pulse.c | 90 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 1 deletion(-)

diff --git a/modules/audio_output/pulse.c b/modules/audio_output/pulse.c
index ac1254c8b9..ccec8df8f4 100644
--- a/modules/audio_output/pulse.c
+++ b/modules/audio_output/pulse.c
@@ -74,6 +74,10 @@ struct aout_sys_t
     pa_stream_flags_t flags_force; /**< Forced flags (stream must be NULL) */
     char *sink_force; /**< Forced sink name (stream must be NULL) */
 
+    vlc_fourcc_t fourcc;
+    uint8_t chans_table[AOUT_CHAN_MAX];
+    uint8_t chans_to_reorder;
+
     struct sink *sinks; /**< Locally-cached list of sinks */
 };
 
@@ -490,6 +494,11 @@ static void Play(audio_output_t *aout, block_t *block)
     aout_sys_t *sys = aout->sys;
     pa_stream *s = sys->stream;
 
+    if (sys->chans_to_reorder)
+        aout_ChannelReorder(block->p_buffer, block->i_buffer,
+                            sys->chans_to_reorder, sys->chans_table,
+                            sys->fourcc);
+
     const void *ptr = data_convert(&block);
     if (unlikely(ptr == NULL))
         return;
@@ -687,6 +696,36 @@ static const char *str_map(const char *key, const char *const table[][2],
      return (r != NULL) ? r[1] : NULL;
 }
 
+static int channel_map_pulse_to_vlc(pa_channel_position_t map)
+{
+    static_assert(AOUT_CHAN_MAX == 9, "Missing channels");
+
+    switch (map)
+    {
+        case PA_CHANNEL_POSITION_FRONT_LEFT:
+            return AOUT_CHAN_LEFT;
+        case PA_CHANNEL_POSITION_FRONT_RIGHT:
+            return AOUT_CHAN_RIGHT;
+        case PA_CHANNEL_POSITION_SIDE_LEFT:
+            return AOUT_CHAN_MIDDLELEFT;
+        case PA_CHANNEL_POSITION_SIDE_RIGHT:
+            return AOUT_CHAN_MIDDLERIGHT;
+        case PA_CHANNEL_POSITION_REAR_LEFT:
+            return AOUT_CHAN_REARLEFT;
+        case PA_CHANNEL_POSITION_REAR_RIGHT:
+            return AOUT_CHAN_REARRIGHT;
+        case PA_CHANNEL_POSITION_REAR_CENTER:
+            return AOUT_CHAN_REARCENTER;
+        case PA_CHANNEL_POSITION_LFE:
+            return AOUT_CHAN_LFE;
+        case PA_CHANNEL_POSITION_MONO:
+        case PA_CHANNEL_POSITION_FRONT_CENTER:
+            return AOUT_CHAN_CENTER;
+        default:
+            return 0;
+    }
+}
+
 /**
  * Create a PulseAudio playback stream, a.k.a. a sink input.
  */
@@ -804,6 +843,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
 
     if (encoding != PA_ENCODING_PCM)
     {
+        assert(fmt->channels_type == AUDIO_CHANNELS_TYPE_PHYSICAL);
         pa_format_info_set_channels(formatv, ss.channels);
 
         /* FIX flags are only permitted for PCM, and there is no way to pass
@@ -812,7 +852,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
                  | PA_STREAM_FIX_RATE
                  | PA_STREAM_FIX_CHANNELS);
     }
-    else
+    else if (fmt->channels_type == AUDIO_CHANNELS_TYPE_PHYSICAL)
     {
         /* Channel mapping (order defined in vlc_aout.h) */
         struct pa_channel_map map;
@@ -861,6 +901,19 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
         pa_format_info_set_channels(formatv, ss.channels);
         pa_format_info_set_channel_map(formatv, &map);
     }
+    else
+    {   /* AUDIO_CHANNELS_TYPE_AMBISONICS */
+        fmt->channels_type = AUDIO_CHANNELS_TYPE_PHYSICAL;
+
+        /* Use the channel layout of the sink and override the current one.
+         * This new layout be will used to configure the ambisonics filter. */
+        flags |= PA_STREAM_FIX_CHANNELS;
+
+        /* Setup low latency in order to quickly react to ambisonics filters
+         * viewpoint changes. */
+        flags |= PA_STREAM_ADJUST_LATENCY;
+        attr.tlength = pa_usec_to_bytes(2 * AOUT_MIN_PREPARE_TIME, &ss);
+    }
 
     /* Create a playback stream */
     pa_proplist *props = pa_proplist_new();
@@ -934,9 +987,44 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
         fmt->i_rate = spec->rate;
     }
 
+    if (flags & PA_STREAM_FIX_CHANNELS)
+    {
+        const pa_channel_map *map = pa_stream_get_channel_map(s);
+        assert(map != NULL);
+
+        const char *name = pa_channel_map_to_name(map);
+        msg_Info(aout, "using %s channel map", (name != NULL) ? name : "?");
+
+        uint8_t chans_out_count = 0;
+        uint32_t chans_out[AOUT_CHAN_MAX];
+        fmt->i_physical_channels = 0;
+        for (uint8_t i = 0; i < map->channels; ++i)
+        {
+            int vlcchan = channel_map_pulse_to_vlc(map->map[i]);
+            if (vlcchan != 0)
+            {
+                chans_out[chans_out_count++] = vlcchan;
+                assert(chans_out_count <= AOUT_CHAN_MAX);
+                fmt->i_physical_channels |= vlcchan;
+            }
+        }
+        if (chans_out_count != map->channels)
+            msg_Warn(aout, "%u channels won't be mapped",
+                     map->channels - chans_out_count);
+        fmt->i_original_channels = fmt->i_physical_channels;
+        aout_FormatPrepare(fmt);
+
+        sys->chans_to_reorder =
+            aout_CheckChannelReorder(NULL, chans_out, fmt->i_physical_channels,
+                                     sys->chans_table);
+    }
+    else
+        sys->chans_to_reorder = 0;
+
     stream_buffer_attr_cb(s, aout);
     stream_moved_cb(s, aout);
     pa_threaded_mainloop_unlock(sys->mainloop);
+    sys->fourcc = fmt->i_format;
 
     return VLC_SUCCESS;
 
-- 
2.11.0



More information about the vlc-devel mailing list