pulsesrc: Move to extended stream API

This is needed as a precursor to allowing capture of IEC61937
formats. We now also need to include the channel map while converting
format info to caps so that a correct channel mask is generated for
pulsesrc's caps.
This commit is contained in:
Arun Raghavan 2018-05-28 14:41:05 +05:30 committed by Arun Raghavan
parent 8f8de410c5
commit 4d67d1bd16
5 changed files with 83 additions and 26 deletions

View file

@ -898,7 +898,7 @@ gst_pulseringbuffer_acquire (GstAudioRingBuffer * buf,
GST_LOG_OBJECT (psink, "creating sample spec");
/* convert the gstreamer sample spec to the pulseaudio format */
if (!gst_pulse_fill_format_info (spec, &pbuf->format, &pbuf->channels))
if (!gst_pulse_fill_format_info (spec, &pbuf->format, NULL, &pbuf->channels))
goto invalid_spec;
pbuf->is_pcm = pa_format_info_is_pcm (pbuf->format);
@ -2273,7 +2273,7 @@ gst_pulsesink_query_acceptcaps (GstPulseSink * psink, GstCaps * caps)
if (!gst_audio_ring_buffer_parse_caps (&spec, caps))
goto out;
if (!gst_pulse_fill_format_info (&spec, &format, &channels))
if (!gst_pulse_fill_format_info (&spec, &format, NULL, &channels))
goto out;
/* Make sure input is framed (one frame per buffer) and can be payloaded */

View file

@ -261,7 +261,7 @@ gst_pulsesrc_init (GstPulseSrc * pulsesrc)
pulsesrc->read_buffer = NULL;
pulsesrc->read_buffer_length = 0;
pa_sample_spec_init (&pulsesrc->sample_spec);
pulsesrc->format = NULL;
pulsesrc->operation_success = FALSE;
pulsesrc->paused = TRUE;
@ -340,6 +340,8 @@ gst_pulsesrc_finalize (GObject * object)
gst_structure_free (pulsesrc->properties);
if (pulsesrc->proplist)
pa_proplist_free (pulsesrc->proplist);
if (pulsesrc->format)
pa_format_info_free (pulsesrc->format);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -628,7 +630,7 @@ gst_pulsesrc_set_stream_volume (GstPulseSrc * pulsesrc, gdouble volume)
GST_DEBUG_OBJECT (pulsesrc, "setting volume to %f", volume);
gst_pulse_cvolume_from_linear (&v, pulsesrc->sample_spec.channels, volume);
gst_pulse_cvolume_from_linear (&v, pulsesrc->channels, volume);
if (!(o = pa_context_set_source_output_volume (pulsesrc->context,
pulsesrc->source_output_idx, &v, NULL, NULL)))
@ -1220,7 +1222,7 @@ gst_pulsesrc_delay (GstAudioSrc * asrc)
if (negative)
result = 0;
else
result = (guint) ((t * pulsesrc->sample_spec.rate) / 1000000LL);
result = (guint) ((t * pulsesrc->rate) / 1000000LL);
}
return result;
@ -1238,7 +1240,7 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps,
GstAudioRingBufferSpec * rspec)
{
pa_channel_map channel_map;
const pa_channel_map *m;
pa_format_info *formats[1];
GstStructure *s;
gboolean need_channel_layout = FALSE;
GstAudioRingBufferSpec new_spec, *spec = NULL;
@ -1298,34 +1300,36 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps ** caps,
g_assert_not_reached ();
}
if (!gst_pulse_fill_sample_spec (spec, &pulsesrc->sample_spec))
if (!gst_pulse_fill_format_info (spec, &pulsesrc->format, &pulsesrc->rate,
&pulsesrc->channels))
goto invalid_spec;
if (need_channel_layout) {
pa_channel_map_init_auto (&channel_map, pulsesrc->channels,
PA_CHANNEL_MAP_DEFAULT);
}
pa_format_info_set_channel_map (pulsesrc->format, &channel_map);
pa_threaded_mainloop_lock (pulsesrc->mainloop);
if (!pulsesrc->context)
goto bad_context;
name = "Record Stream";
if (pulsesrc->proplist) {
if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
name, &pulsesrc->sample_spec,
(need_channel_layout) ? NULL : &channel_map,
pulsesrc->proplist)))
goto create_failed;
} else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
name, &pulsesrc->sample_spec,
(need_channel_layout) ? NULL : &channel_map)))
formats[0] = pulsesrc->format;
if (!(pulsesrc->stream = pa_stream_new_extended (pulsesrc->context,
name, formats, 1, pulsesrc->proplist)))
goto create_failed;
if (caps) {
m = pa_stream_get_channel_map (pulsesrc->stream);
gst_pulse_channel_map_to_gst (m, &new_spec);
gst_pulse_channel_map_to_gst (&channel_map, &new_spec);
gst_audio_channel_positions_to_valid_order (new_spec.info.position,
new_spec.info.channels);
gst_caps_unref (*caps);
*caps = gst_audio_info_to_caps (&new_spec.info);
*caps = gst_pulse_format_info_to_caps (pulsesrc->format);
GST_DEBUG_OBJECT (pulsesrc, "Caps are %" GST_PTR_FORMAT, *caps);
}
@ -1479,10 +1483,15 @@ gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
{
GstAudioRingBufferSpec s = *spec;
const pa_channel_map *m;
pa_channel_map m;
m = pa_stream_get_channel_map (pulsesrc->stream);
gst_pulse_channel_map_to_gst (m, &s);
if (gst_pulse_format_info_get_channel_map (pulsesrc->format, &m) < 0) {
GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
("Could not get channel map for stream"), (NULL));
goto unlock_and_fail;
}
gst_pulse_channel_map_to_gst (&m, &s);
gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
(pulsesrc)->ringbuffer, s.info.position);
}

View file

@ -60,7 +60,9 @@ struct _GstPulseSrc
pa_stream *stream;
guint32 source_output_idx;
pa_sample_spec sample_spec;
pa_format_info *format;
guint rate;
guint channels;
const void *read_buffer;
size_t read_buffer_length;

View file

@ -138,7 +138,7 @@ gst_pulse_fill_sample_spec (GstAudioRingBufferSpec * spec, pa_sample_spec * ss)
gboolean
gst_pulse_fill_format_info (GstAudioRingBufferSpec * spec, pa_format_info ** f,
guint * channels)
guint * rate, guint * channels)
{
pa_format_info *format;
pa_sample_format_t sf = PA_SAMPLE_INVALID;
@ -186,7 +186,10 @@ gst_pulse_fill_format_info (GstAudioRingBufferSpec * spec, pa_format_info ** f,
goto fail;
*f = format;
*channels = GST_AUDIO_INFO_CHANNELS (ainfo);
if (rate)
*rate = GST_AUDIO_INFO_RATE (ainfo);
if (channels)
*channels = GST_AUDIO_INFO_CHANNELS (ainfo);
return TRUE;
@ -434,12 +437,34 @@ gst_pulse_format_info_int_prop_to_value (pa_format_info * format,
return TRUE;
}
/* FIXME: switch to PA API when it is available */
int
gst_pulse_format_info_get_channel_map (pa_format_info * f, pa_channel_map * map)
{
int r;
char *map_str;
r = pa_format_info_get_prop_string (f, PA_PROP_FORMAT_CHANNEL_MAP, &map_str);
if (r < 0)
return r;
map = pa_channel_map_parse (map, map_str);
pa_xfree (map_str);
if (!map)
return -PA_ERR_INVALID;
return 0;
}
GstCaps *
gst_pulse_format_info_to_caps (pa_format_info * format)
{
GstCaps *ret = NULL;
GValue v = { 0, };
pa_sample_spec ss;
pa_channel_map map;
int channels = 0;
switch (format->encoding) {
case PA_ENCODING_PCM:{
@ -504,6 +529,25 @@ gst_pulse_format_info_to_caps (pa_format_info * format)
&v))
gst_caps_set_value (ret, "channels", &v);
if (pa_format_info_get_prop_int (format, PA_PROP_FORMAT_CHANNELS,
&channels) == 0
&& gst_pulse_format_info_get_channel_map (format, &map) == 0) {
guint64 channel_mask;
GstAudioRingBufferSpec spec;
GST_AUDIO_INFO_CHANNELS (&spec.info) = channels;
if (gst_pulse_channel_map_to_gst (&map, &spec) &&
!(GST_AUDIO_INFO_IS_UNPOSITIONED (&spec.info)) &&
gst_audio_channel_positions_to_mask (&GST_AUDIO_INFO_POSITION
(&spec.info, 0), channels, FALSE, &channel_mask)) {
gst_caps_set_simple (ret, "channel-mask", GST_TYPE_BITMASK,
channel_mask, NULL);
} else {
GST_WARNING ("Could not convert channel map to channel mask");
}
}
out:
return ret;
}

View file

@ -75,7 +75,7 @@
gboolean gst_pulse_fill_sample_spec (GstAudioRingBufferSpec * spec,
pa_sample_spec * ss);
gboolean gst_pulse_fill_format_info (GstAudioRingBufferSpec * spec,
pa_format_info ** f, guint * channels);
pa_format_info ** f, guint * rate, guint * channels);
const char * gst_pulse_sample_format_to_caps_format (pa_sample_format_t sf);
gchar *gst_pulse_client_name (void);
@ -91,6 +91,8 @@ void gst_pulse_cvolume_from_linear (pa_cvolume *v, unsigned channels, gdouble vo
pa_proplist *gst_pulse_make_proplist (const GstStructure *properties);
GstStructure *gst_pulse_make_structure (pa_proplist *properties);
int gst_pulse_format_info_get_channel_map (pa_format_info * format,
pa_channel_map *map);
GstCaps * gst_pulse_format_info_to_caps (pa_format_info * format);
GstCaps * gst_pulse_fix_pcm_caps (GstCaps * incaps);