pulsesrc: Move to extended stream API
authorArun Raghavan <arunsr@codeaurora.org>
Mon, 28 May 2018 09:11:05 +0000 (14:41 +0530)
committerArun Raghavan <arun@arunraghavan.net>
Thu, 10 Jan 2019 09:16:02 +0000 (09:16 +0000)
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.

ext/pulse/pulsesink.c
ext/pulse/pulsesrc.c
ext/pulse/pulsesrc.h
ext/pulse/pulseutil.c
ext/pulse/pulseutil.h

index 42330a4..44b7fa0 100644 (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 */
index 30c6e7f..8d3f8e2 100644 (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;
+
+    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;
+    }
 
-    m = pa_stream_get_channel_map (pulsesrc->stream);
-    gst_pulse_channel_map_to_gst (m, &s);
+    gst_pulse_channel_map_to_gst (&m, &s);
     gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
         (pulsesrc)->ringbuffer, s.info.position);
   }
index efa7d97..93d6795 100644 (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;
index ea08d15..92e729d 100644 (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;
 }
index c70369f..b2ed0de 100644 (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);