osxaudiosrc: Implement caps probing
authorArun Raghavan <git@arunraghavan.net>
Mon, 1 Dec 2014 14:11:35 +0000 (19:41 +0530)
committerArun Raghavan <git@arunraghavan.net>
Mon, 15 Dec 2014 05:49:52 +0000 (11:19 +0530)
https://bugzilla.gnome.org/show_bug.cgi?id=740987

sys/osxaudio/gstosxaudiosrc.c
sys/osxaudio/gstosxaudiosrc.h
sys/osxaudio/gstosxcoreaudio.c
sys/osxaudio/gstosxcoreaudio.h

index b0be5f1..a32ccca 100644 (file)
@@ -177,7 +177,7 @@ gst_osx_audio_src_init (GstOsxAudioSrc * src)
   gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
 
   src->device_id = kAudioDeviceUnknown;
-  src->deviceChannels = -1;
+  src->cached_caps = NULL;
 }
 
 static void
@@ -250,6 +250,7 @@ gst_osx_audio_src_probe_caps (GstOsxAudioSrc * osxsrc)
   GstOsxAudioRingBuffer *ringbuffer =
       GST_OSX_AUDIO_RING_BUFFER (GST_AUDIO_BASE_SRC (osxsrc)->ringbuffer);
   GstCoreAudio *core_audio = ringbuffer->core_audio;
+  GstCaps *caps;
   AudioStreamBasicDescription asbd_in;
   UInt32 propertySize;
   OSStatus status;
@@ -258,15 +259,27 @@ gst_osx_audio_src_probe_caps (GstOsxAudioSrc * osxsrc)
   status = AudioUnitGetProperty (core_audio->audiounit,
       kAudioUnitProperty_StreamFormat,
       kAudioUnitScope_Input, 1, &asbd_in, &propertySize);
+  if (status)
+    goto fail;
 
-  if (status) {
-    AudioComponentInstanceDispose (core_audio->audiounit);
-    core_audio->audiounit = NULL;
-    GST_WARNING_OBJECT (core_audio,
-        "Unable to obtain device properties: %d", (int) status);
-  } else {
-    osxsrc->deviceChannels = asbd_in.mChannelsPerFrame;
-  }
+  caps = gst_core_audio_asbd_to_caps (&asbd_in);
+  if (!caps)
+    GST_WARNING_OBJECT (osxsrc, "Could not get caps from stream description");
+  else
+    GST_DEBUG_OBJECT (osxsrc, "Got caps on device: %p", caps);
+
+  if (osxsrc->cached_caps)
+    gst_caps_unref (osxsrc->cached_caps);
+
+  osxsrc->cached_caps = caps;
+
+  return;
+
+fail:
+  AudioComponentInstanceDispose (core_audio->audiounit);
+  core_audio->audiounit = NULL;
+  GST_WARNING_OBJECT (osxsrc,
+      "Unable to obtain device properties: %d", (int) status);
 }
 
 static GstCaps *
@@ -275,9 +288,7 @@ gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter)
   GstElementClass *gstelement_class;
   GstOsxAudioSrc *osxsrc;
   GstAudioRingBuffer *buf;
-  GstPadTemplate *pad_template;
-  GstCaps *caps;
-  gint min, max;
+  GstCaps *ret = NULL;
 
   gstelement_class = GST_ELEMENT_GET_CLASS (src);
   osxsrc = GST_OSX_AUDIO_SRC (src);
@@ -285,38 +296,34 @@ gst_osx_audio_src_get_caps (GstBaseSrc * src, GstCaps * filter)
 
   if (buf) {
     GST_OBJECT_LOCK (buf);
-    if (buf->open && osxsrc->deviceChannels == -1) {
+
+    if (buf->acquired) {
+      /* Caps are fixed, use what we have */
+      ret = gst_pad_get_current_caps (GST_BASE_SINK_PAD (src));
+      if (!ret) {
+        GST_OBJECT_UNLOCK (buf);
+        g_return_val_if_reached (NULL);
+      }
+
+    } else if (buf->open && !osxsrc->cached_caps) {
       /* Device is open, let's probe its caps */
       gst_osx_audio_src_probe_caps (osxsrc);
     }
-    GST_OBJECT_UNLOCK (buf);
-  }
 
-  if (osxsrc->deviceChannels == -1) {
-    /* -1 means we don't know the number of channels yet.  for now, return
-     * template caps.
-     */
-    return NULL;
+    GST_OBJECT_UNLOCK (buf);
   }
 
-  max = osxsrc->deviceChannels;
-  if (max < 1)
-    max = 1;                    /* 0 channels means 1 channel? */
+  if (!ret && osxsrc->cached_caps)
+    ret = gst_caps_ref (osxsrc->cached_caps);
 
-  min = MIN (1, max);
-
-  pad_template = gst_element_class_get_pad_template (gstelement_class, "src");
-  g_return_val_if_fail (pad_template != NULL, NULL);
-
-  caps = gst_caps_copy (gst_pad_template_get_caps (pad_template));
-
-  if (min == max) {
-    gst_caps_set_simple (caps, "channels", G_TYPE_INT, max, NULL);
-  } else {
-    gst_caps_set_simple (caps, "channels", GST_TYPE_INT_RANGE, min, max, NULL);
+  if (filter) {
+    GstCaps *tmp;
+    tmp = gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (ret);
+    ret = tmp;
   }
 
-  return caps;
+  return ret;
 }
 
 static GstAudioRingBuffer *
index a5f5d84..163303c 100644 (file)
@@ -67,8 +67,7 @@ struct _GstOsxAudioSrc
 
   AudioDeviceID device_id;
 
-  /* actual number of channels reported by input device */
-  int deviceChannels;
+  GstCaps *cached_caps;
 };
 
 struct _GstOsxAudioSrcClass 
index 19c0d44..d99ff29 100644 (file)
@@ -184,3 +184,73 @@ gst_core_audio_audio_device_is_spdif_avail (AudioDeviceID device_id)
 {
   return gst_core_audio_audio_device_is_spdif_avail_impl (device_id);
 }
+
+GstCaps *
+gst_core_audio_asbd_to_caps (AudioStreamBasicDescription * asbd)
+{
+  GstAudioInfo info;
+  GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
+  int rate, channels, bps, endianness;
+  gboolean sign, interleaved;
+
+  if (asbd->mFormatID != kAudioFormatLinearPCM) {
+    GST_WARNING ("Only linear PCM is supported");
+    goto error;
+  }
+
+  if (!(asbd->mFormatFlags & kAudioFormatFlagIsPacked)) {
+    GST_WARNING ("Only packed formats supported");
+    goto error;
+  }
+
+  if (asbd->mFormatFlags & kLinearPCMFormatFlagsSampleFractionMask) {
+    GST_WARNING ("Fixed point audio is unsupported");
+    goto error;
+  }
+
+  rate = asbd->mSampleRate;
+  if (rate == kAudioStreamAnyRate)
+    rate = GST_AUDIO_DEF_RATE;
+
+  channels = asbd->mChannelsPerFrame;
+  if (channels == 0) {
+    /* The documentation says this should not happen! */
+    channels = 1;
+  }
+
+  bps = asbd->mBitsPerChannel;
+  endianness = asbd->mFormatFlags & kAudioFormatFlagIsBigEndian ?
+      G_BIG_ENDIAN : G_LITTLE_ENDIAN;
+  sign = asbd->mFormatID & kAudioFormatFlagIsSignedInteger ? TRUE : FALSE;
+  interleaved = asbd->mFormatFlags & kAudioFormatFlagIsNonInterleaved ?
+      TRUE : FALSE;
+
+  if (asbd->mFormatFlags & kAudioFormatFlagIsFloat) {
+    if (bps == 32) {
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_F32LE;
+      else
+        format = GST_AUDIO_FORMAT_F32BE;
+
+    } else if (bps == 64) {
+      if (endianness == G_LITTLE_ENDIAN)
+        format = GST_AUDIO_FORMAT_F64LE;
+      else
+        format = GST_AUDIO_FORMAT_F64BE;
+    }
+  } else {
+    format = gst_audio_format_build_integer (sign, endianness, bps, bps);
+  }
+
+  if (format == GST_AUDIO_FORMAT_UNKNOWN) {
+    GST_WARNING ("Unsupported sample format");
+    goto error;
+  }
+
+  gst_audio_info_set_format (&info, format, rate, channels, NULL);
+
+  return gst_audio_info_to_caps (&info);
+
+error:
+  return NULL;
+}
index b1f7a28..39670f4 100644 (file)
@@ -143,6 +143,7 @@ gboolean gst_core_audio_select_device                        (GstCoreAudio * cor
 
 AudioChannelLayout * gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id, gboolean output);
 
+GstCaps * gst_core_audio_asbd_to_caps (AudioStreamBasicDescription * asbd);
 
 G_END_DECLS