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

Rémi Denis-Courmont remi at remlab.net
Tue Jul 11 15:29:41 CEST 2017


On lundi 10 juillet 2017 15:00:20 EEST Thomas Guillem wrote:
> On Fri, Jul 7, 2017, at 17:16, Rémi Denis-Courmont wrote:
> > Le 7 juillet 2017 17:03:01 GMT+03:00, Thomas Guillem <thomas at gllm.fr> a
> > écrit :>> ---> 
> >>  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;
> > 
> > Why do you impose the channel order here?!
> 
> I use the current channel layout of the pulse stream. The ambisonics
> renderer need the output channel layout untouched since the rendering
> algorithm depend of the channel layout.

If you fix the channel map, not only you need to reorder (which is wasteful and 
was carefully avoided previously) but you have to support *every* channel 
positions defined by PulseAudio, or you might fail to playback completely.

Good luck with that... Seriously,that seems highly impractical.

-- 
Rémi



More information about the vlc-devel mailing list