sys/osxaudio/: Rewrite osxaudio to work more flexibly and more reliably, using a...
authorJustin Karnegas <justin@affinix.com>
Fri, 2 Jan 2009 20:39:34 +0000 (20:39 +0000)
committerMichael Smith <msmith@xiph.org>
Fri, 2 Jan 2009 20:39:34 +0000 (20:39 +0000)
Original commit message from CVS:
Patch by: Justin Karnegas <justin@affinix.com> and
Michael Smith <msmith@songbirdnest.com>
* sys/osxaudio/gstosxaudio.c:
* sys/osxaudio/gstosxaudioelement.c:
* sys/osxaudio/gstosxaudioelement.h:
* sys/osxaudio/gstosxaudiosink.c:
* sys/osxaudio/gstosxaudiosink.h:
* sys/osxaudio/gstosxaudiosrc.c:
* sys/osxaudio/gstosxaudiosrc.h:
* sys/osxaudio/gstosxringbuffer.c:
* sys/osxaudio/gstosxringbuffer.h:
Rewrite osxaudio to work more flexibly and more reliably, using a
different abstraction layer of coreaudio that is the recommended way of
doing low-level audio I/O on OSX.
Fixes byg #564948.

ChangeLog
sys/osxaudio/gstosxaudio.c
sys/osxaudio/gstosxaudioelement.c
sys/osxaudio/gstosxaudioelement.h
sys/osxaudio/gstosxaudiosink.c
sys/osxaudio/gstosxaudiosink.h
sys/osxaudio/gstosxaudiosrc.c
sys/osxaudio/gstosxaudiosrc.h
sys/osxaudio/gstosxringbuffer.c
sys/osxaudio/gstosxringbuffer.h

index bdfdaed..ff7a370 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2009-01-02  Michael Smith <msmith@songbirdnest.com>
+
+         Patch by: Justin Karnegas <justin@affinix.com> and
+                   Michael Smith <msmith@songbirdnest.com>
+       * sys/osxaudio/gstosxaudio.c:
+       * sys/osxaudio/gstosxaudioelement.c:
+       * sys/osxaudio/gstosxaudioelement.h:
+       * sys/osxaudio/gstosxaudiosink.c:
+       * sys/osxaudio/gstosxaudiosink.h:
+       * sys/osxaudio/gstosxaudiosrc.c:
+       * sys/osxaudio/gstosxaudiosrc.h:
+       * sys/osxaudio/gstosxringbuffer.c:
+       * sys/osxaudio/gstosxringbuffer.h:
+         Rewrite osxaudio to work more flexibly and more reliably, using a
+         different abstraction layer of coreaudio that is the recommended way of
+         doing low-level audio I/O on OSX.
+         Fixes byg #564948.
+
 2009-01-02  Wim Taymans  <wim.taymans@collabora.co.uk>
 
        * tests/examples/rtp/server-decodebin-H263p-AMR.sh:
index 9d63929..262c7d9 100644 (file)
@@ -1,5 +1,6 @@
-/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+/*
+ * GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
  * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
  *
  * This library is free software; you can redistribute it and/or
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
- * 
- * The development of this code was made possible due to the involvement of 
+ *
+ * The development of this code was made possible due to the involvement of
  * Pioneers of the Inevitable, the creators of the Songbird Music player
- * 
+ *
  */
 
 /**
  * Last reviewed on 2006-03-01 (0.10.4)
  */
 
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-
 #include "gstosxaudioelement.h"
 #include "gstosxaudiosink.h"
 #include "gstosxaudiosrc.h"
@@ -55,7 +54,6 @@
 static gboolean
 plugin_init (GstPlugin * plugin)
 {
-
   if (!gst_element_register (plugin, "osxaudiosink", GST_RANK_PRIMARY,
           GST_TYPE_OSX_AUDIO_SINK)) {
     return FALSE;
index c3c2833..ceff749 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * GStreamer
- * Copyright 2006 Zaheer Abbas Merali  <zaheerabbas at merali dot org>
- * Copyright 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
- * 
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
- * 
- * The development of this code was made possible due to the involvement of Pioneers of the * Inevitable, the creators of the Songbird Music player
- * 
+ *
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
  */
 
 #include <gst/gst.h>
@@ -67,12 +68,11 @@ gst_osx_audio_element_get_type ()
       0,
       0,
       NULL,
+      NULL
     };
 
     gst_osxaudioelement_type = g_type_register_static (G_TYPE_INTERFACE,
         "GstOsxAudioElement", &gst_osxaudioelement_info, 0);
-    /*g_type_interface_add_prerequisite (gst_osxaudioelement_type,
-       GST_TYPE_IMPLEMENTS_INTERFACE); */
   }
 
   return gst_osxaudioelement_type;
@@ -84,11 +84,9 @@ gst_osx_audio_element_class_init (GstOsxAudioElementInterface * klass)
   static gboolean initialized = FALSE;
 
   if (!initialized) {
-
     initialized = TRUE;
   }
 
   /* default virtual functions */
   klass->io_proc = NULL;
-
 }
index 1ab487a..b5d90c0 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * GStreamer
- * Copyright 2006 Zaheer Abbas Merali  <zaheerabbas at merali dot org>
- * Copyright 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
- * 
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -41,8 +41,9 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * The development of this code was made possible due to the involvement of Pioneers of the * Inevitable, the creators of the Songbird Music player
- * 
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
  */
 
 #ifndef __GST_OSX_AUDIO_ELEMENT_H__
 
 #include <gst/gst.h>
 #include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
 
-#define GST_OSX_AUDIO_ELEMENT_TYPE                       (gst_osx_audio_element_get_type())
-#define GST_OSX_AUDIO_ELEMENT(obj)                       (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_OSX_AUDIO_ELEMENT_TYPE, GstOsxAudioElementInterface))
-#define GST_IS_OSX_AUDIO_ELEMENT(obj)                    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_OSX_AUDIO_ELEMENT_TYPE))
-#define GST_OSX_AUDIO_ELEMENT_GET_INTERFACE(inst)        (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_OSX_AUDIO_ELEMENT_TYPE, GstOsxAudioElementInterface))
+G_BEGIN_DECLS
+
+#define GST_OSX_AUDIO_ELEMENT_TYPE \
+  (gst_osx_audio_element_get_type())
+#define GST_OSX_AUDIO_ELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface))
+#define GST_IS_OSX_AUDIO_ELEMENT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_OSX_AUDIO_ELEMENT_TYPE))
+#define GST_OSX_AUDIO_ELEMENT_GET_INTERFACE(inst) \
+  (G_TYPE_INSTANCE_GET_INTERFACE((inst),GST_OSX_AUDIO_ELEMENT_TYPE,GstOsxAudioElementInterface))
 
 typedef struct _GstOsxAudioElementInterface GstOsxAudioElementInterface;
 
-struct _GstOsxAudioElementInterface {
-       GTypeInterface parent;
-       
-       OSStatus (*io_proc) (AudioDeviceID inDevice, const AudioTimeStamp *inNow, const AudioBufferList *inInputData, const AudioTimeStamp *inInputTime, AudioBufferList *outOutputData, const AudioTimeStamp *inOutputTime, void *inClientData);
-       
+struct _GstOsxAudioElementInterface
+{
+  GTypeInterface parent;
+
+  OSStatus (*io_proc) (void * userdata,
+      AudioUnitRenderActionFlags * ioActionFlags,
+      const AudioTimeStamp * inTimeStamp,
+      UInt32 inBusNumber, UInt32 inNumberFrames,
+      AudioBufferList * bufferList);
 };
 
 GType gst_osx_audio_element_get_type (void);
 
+G_END_DECLS
 
-#endif
+#endif /* __GST_OSX_AUDIO_ELEMENT_H__ */
index 46d229b..aec8874 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * GStreamer
- * Copyright 2005,2006 Zaheer Abbas Merali  <zaheerabbas at merali dot org>
- * Copyright 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
- * 
+ * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007,2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -41,8 +41,8 @@
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- *  The development of this code was made possible due to the involvement of 
- *  Pioneers of the Inevitable, the creators of the Songbird Music player.
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
  *
  */
 
@@ -67,8 +67,6 @@
 #include <CoreAudio/CoreAudio.h>
 #include <CoreAudio/AudioHardware.h>
 #include "gstosxaudiosink.h"
-#include "gstosxaudiosrc.h"
-
 #include "gstosxaudioelement.h"
 
 GST_DEBUG_CATEGORY_STATIC (osx_audiosink_debug);
@@ -90,9 +88,12 @@ enum
 enum
 {
   ARG_0,
-  ARG_DEVICE
+  ARG_DEVICE,
+  ARG_VOLUME
 };
 
+#define DEFAULT_VOLUME 1.0
+
 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
@@ -101,27 +102,28 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
         "signed = (boolean) { TRUE }, "
         "width = (int) 32, "
         "depth = (int) 32, "
-        "rate = (int) [1, MAX], " "channels = (int) [1, 2]")
+        "rate = (int) [1, MAX], " "channels = (int) [1, MAX]")
     );
 
 static void gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
-static GstCaps *gst_osx_audio_sink_getcaps (GstBaseSink * sink);
 
 static GstRingBuffer *gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink *
     sink);
 static void gst_osx_audio_sink_osxelement_init (gpointer g_iface,
     gpointer iface_data);
-OSStatus gst_osx_audio_sink_io_proc (AudioDeviceID inDevice,
-    const AudioTimeStamp * inNow, const AudioBufferList * inInputData,
-    const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData,
-    const AudioTimeStamp * inOutputTime, void *inClientData);
 static void gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink);
+static void gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink);
+
+static OSStatus gst_osx_audio_sink_io_proc (GstOsxRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList);
 
 static void
-gst_osx_audio_sink_osxelement_do_init (GType type)
+gst_osx_audio_sink_do_init (GType type)
 {
   static const GInterfaceInfo osxelement_info = {
     gst_osx_audio_sink_osxelement_init,
@@ -137,8 +139,7 @@ gst_osx_audio_sink_osxelement_do_init (GType type)
 }
 
 GST_BOILERPLATE_FULL (GstOsxAudioSink, gst_osx_audio_sink, GstBaseAudioSink,
-    GST_TYPE_BASE_AUDIO_SINK, gst_osx_audio_sink_osxelement_do_init);
-
+    GST_TYPE_BASE_AUDIO_SINK, gst_osx_audio_sink_do_init);
 
 static void
 gst_osx_audio_sink_base_init (gpointer g_class)
@@ -151,7 +152,6 @@ gst_osx_audio_sink_base_init (gpointer g_class)
   gst_element_class_set_details (element_class, &gst_osx_audio_sink_details);
 }
 
-/* initialize the plugin's class */
 static void
 gst_osx_audio_sink_class_init (GstOsxAudioSinkClass * klass)
 {
@@ -176,25 +176,21 @@ gst_osx_audio_sink_class_init (GstOsxAudioSinkClass * klass)
       g_param_spec_int ("device", "Device ID", "Device ID of output device",
           0, G_MAXINT, 0, G_PARAM_READWRITE));
 
-  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_getcaps);
+  g_object_class_install_property (gobject_class, ARG_VOLUME,
+      g_param_spec_double ("volume", "Volume", "Volume of this stream",
+          0, 1.0, 1.0, G_PARAM_READWRITE));
+
   gstbaseaudiosink_class->create_ringbuffer =
       GST_DEBUG_FUNCPTR (gst_osx_audio_sink_create_ringbuffer);
-
 }
 
-/* initialize the new element
- * instantiate pads and add them to element
- * set functions
- * initialize structure
- */
 static void
 gst_osx_audio_sink_init (GstOsxAudioSink * sink, GstOsxAudioSinkClass * gclass)
 {
-/*  GstElementClass *klass = GST_ELEMENT_GET_CLASS (sink); */
   GST_DEBUG ("Initialising object");
 
   sink->device_id = kAudioDeviceUnknown;
-  sink->stream_id = kAudioStreamUnknown;
+  sink->volume = DEFAULT_VOLUME;
 }
 
 static void
@@ -207,6 +203,10 @@ gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
     case ARG_DEVICE:
       sink->device_id = g_value_get_int (value);
       break;
+    case ARG_VOLUME:
+      sink->volume = g_value_get_double (value);
+      gst_osx_audio_sink_set_volume (sink);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -222,109 +222,15 @@ gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
     case ARG_DEVICE:
       g_value_set_int (value, sink->device_id);
       break;
+    case ARG_VOLUME:
+      g_value_set_double (value, sink->volume);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
 }
 
-/* GstElement vmethod implementations */
-
-/* GstBaseSink vmethod implementations */
-static GstCaps *
-gst_osx_audio_sink_getcaps (GstBaseSink * sink)
-{
-  GstCaps *caps = NULL;
-  GstOsxAudioSink *osxsink;
-  OSStatus status;
-  AudioValueRange *rates = NULL;
-  UInt32 propertySize;
-  int i;
-  gboolean foundFixedRate = FALSE;
-  GstStructure *structure;
-  GValue rate_v = { 0 };
-  GValue rates_v = { 0 };
-
-  osxsink = GST_OSX_AUDIO_SINK (sink);
-
-  gst_osx_audio_sink_select_device (osxsink);
-
-  GST_DEBUG_OBJECT (osxsink, "Using device_id %d", (int) osxsink->device_id);
-
-  status = AudioDeviceGetPropertyInfo (osxsink->device_id, 0,   /* Master channel */
-      FALSE,                    /* isInput */
-      kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, NULL);
-
-  if (status) {
-    GST_WARNING_OBJECT (osxsink, "Failed to get sample rates size: %ld",
-        status);
-    goto done;
-  }
-
-  GST_DEBUG_OBJECT (osxsink, "Allocating %d bytes for sizes",
-      (int) propertySize);
-  rates = g_malloc (propertySize);
-
-  status = AudioDeviceGetProperty (osxsink->device_id, 0,       /* Master channel */
-      FALSE,                    /* isInput */
-      kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, rates);
-
-  if (status) {
-    GST_WARNING_OBJECT (osxsink, "Failed to get sample rates: %ld", status);
-    goto done;
-  }
-
-  GST_DEBUG_OBJECT (osxsink, "Used %d bytes for sizes", (int) propertySize);
-
-  if (propertySize < sizeof (AudioValueRange)) {
-    GST_WARNING_OBJECT (osxsink, "Zero sample rates available");
-    goto done;
-  }
-
-  /* Create base caps object, then modify to suit. */
-  caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
-          (sink)));
-  structure = gst_caps_get_structure (caps, 0);
-
-  GST_DEBUG
-      ("Getting available sample rates: Status: %ld number of ranges: %lu",
-      status, propertySize / sizeof (AudioValueRange));
-
-  g_value_init (&rates_v, GST_TYPE_LIST);
-  g_value_init (&rate_v, G_TYPE_INT);
-
-  for (i = 0; i < propertySize / sizeof (AudioValueRange); i++) {
-    GST_LOG_OBJECT (osxsink, "Range from %f to %f", rates[i].mMinimum,
-        rates[i].mMaximum);
-    if (rates[i].mMinimum == rates[i].mMaximum) {
-      /* For now, we only support these in this form. If there are none
-       * in this form, we use the first (only) as a range. */
-      foundFixedRate = TRUE;
-
-      g_value_set_int (&rate_v, rates[i].mMinimum);
-      gst_value_list_append_value (&rates_v, &rate_v);
-    }
-  }
-
-  g_value_unset (&rate_v);
-
-  if (foundFixedRate) {
-    gst_structure_set_value (structure, "rate", &rates_v);
-  } else {
-    gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE,
-        rates[0].mMinimum, rates[0].mMaximum, NULL);
-  }
-
-  g_value_unset (&rates_v);
-
-done:
-  if (rates)
-    g_free (rates);
-
-  return caps;
-}
-
-/* GstBaseAudioSink vmethod implementations */
 static GstRingBuffer *
 gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
 {
@@ -340,35 +246,57 @@ gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
   GST_DEBUG ("osx sink 0x%p element 0x%p  ioproc 0x%p", osxsink,
       GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink),
       (void *) gst_osx_audio_sink_io_proc);
+
+  gst_osx_audio_sink_set_volume (osxsink);
+
   ringbuffer->element = GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink);
   ringbuffer->device_id = osxsink->device_id;
-  ringbuffer->stream_id = osxsink->stream_id;
 
   return GST_RING_BUFFER (ringbuffer);
 }
 
-OSStatus
-gst_osx_audio_sink_io_proc (AudioDeviceID inDevice,
-    const AudioTimeStamp * inNow, const AudioBufferList * inInputData,
-    const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData,
-    const AudioTimeStamp * inOutputTime, void *inClientData)
+/* HALOutput AudioUnit will request fairly arbitrarily-sized chunks of data,
+ * not of a fixed size. So, we keep track of where in the current ringbuffer
+ * segment we are, and only advance the segment once we've read the whole
+ * thing */
+static OSStatus
+gst_osx_audio_sink_io_proc (GstOsxRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList)
 {
-  GstOsxRingBuffer *buf = GST_OSX_RING_BUFFER (inClientData);
-
   guint8 *readptr;
   gint readseg;
   gint len;
+  gint remaining = bufferList->mBuffers[0].mDataByteSize;
+  gint offset = 0;
+
+  while (remaining) {
+    if (!gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf),
+            &readseg, &readptr, &len))
+      return 0;
 
-  if (gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf), &readseg, &readptr,
-          &len)) {
-    outOutputData->mBuffers[0].mDataByteSize = len;
-    memcpy ((char *) outOutputData->mBuffers[0].mData, readptr, len);
+    len -= buf->segoffset;
 
-    /* clear written samples */
-    gst_ring_buffer_clear (GST_RING_BUFFER (buf), readseg);
+    if (len > remaining)
+      len = remaining;
 
-    /* we wrote one segment */
-    gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1);
+    memcpy ((char *) bufferList->mBuffers[0].mData + offset,
+        readptr + buf->segoffset, len);
+
+    buf->segoffset += len;
+    offset += len;
+    remaining -= len;
+
+    if ((gint) buf->segoffset == GST_RING_BUFFER (buf)->spec.segsize) {
+      /* clear written samples */
+      gst_ring_buffer_clear (GST_RING_BUFFER (buf), readseg);
+
+      /* we wrote one segment */
+      gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1);
+
+      buf->segoffset = 0;
+    }
   }
   return 0;
 }
@@ -378,9 +306,18 @@ gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data)
 {
   GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface;
 
-  iface->io_proc = gst_osx_audio_sink_io_proc;
+  iface->io_proc = (AURenderCallback) gst_osx_audio_sink_io_proc;
 }
 
+static void
+gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink)
+{
+  if (!sink->audiounit)
+    return;
+
+  AudioUnitSetParameter (sink->audiounit, kHALOutputParam_Volume,
+      kAudioUnitScope_Global, 0, (float) sink->volume, 0);
+}
 
 static void
 gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink)
@@ -389,67 +326,27 @@ gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink)
   UInt32 propertySize;
 
   if (osxsink->device_id == kAudioDeviceUnknown) {
+    /* If no specific device has been selected by the user, then pick the
+     * default device */
     GST_DEBUG_OBJECT (osxsink, "Selecting device for OSXAudioSink");
     propertySize = sizeof (osxsink->device_id);
     status =
         AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
         &propertySize, &osxsink->device_id);
 
-    if (status)
+    if (status) {
       GST_WARNING_OBJECT (osxsink,
           "AudioHardwareGetProperty returned %d", (int) status);
-    else
+    } else {
       GST_DEBUG_OBJECT (osxsink, "AudioHardwareGetProperty returned 0");
+    }
 
-    if (osxsink->device_id == kAudioDeviceUnknown)
+    if (osxsink->device_id == kAudioDeviceUnknown) {
       GST_WARNING_OBJECT (osxsink,
           "AudioHardwareGetProperty: device_id is kAudioDeviceUnknown");
+    }
 
     GST_DEBUG_OBJECT (osxsink, "AudioHardwareGetProperty: device_id is %lu",
         (long) osxsink->device_id);
   }
-
-  if (osxsink->stream_id == kAudioStreamUnknown) {
-    AudioStreamID *streams;
-
-    GST_DEBUG_OBJECT (osxsink, "Getting streamid");
-    status = AudioDeviceGetPropertyInfo (osxsink->device_id, 0, /* Master channel */
-        FALSE,                  /* isInput */
-        kAudioDevicePropertyStreams, &propertySize, NULL);
-
-    if (status) {
-      GST_WARNING_OBJECT (osxsink,
-          "AudioDeviceGetProperty returned %d", (int) status);
-      return;
-    }
-
-    GST_DEBUG_OBJECT (osxsink,
-        "Getting available streamids from %d (%d bytes)",
-        (int) (propertySize / sizeof (AudioStreamID)),
-        (unsigned int) propertySize);
-    streams = g_malloc (propertySize);
-    status = AudioDeviceGetProperty (osxsink->device_id, 0,     /* Master channel */
-        FALSE,                  /* isInput */
-        kAudioDevicePropertyStreams, &propertySize, streams);
-
-    if (status) {
-      GST_WARNING_OBJECT (osxsink,
-          "AudioDeviceGetProperty returned %d", (int) status);
-      g_free (streams);
-      return;
-    }
-
-    GST_DEBUG_OBJECT (osxsink, "Getting streamid from %d (%d bytes)",
-        (int) (propertySize / sizeof (AudioStreamID)),
-        (unsigned int) propertySize);
-
-    if (propertySize >= sizeof (AudioStreamID)) {
-      osxsink->stream_id = streams[0];
-      GST_DEBUG_OBJECT (osxsink, "Selected stream %d of %d: %d", 0,
-          (int) (propertySize / sizeof (AudioStreamID)),
-          (int) osxsink->stream_id);
-    }
-
-    g_free (streams);
-  }
 }
index a46d244..aac9719 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * GStreamer
- * Copyright 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
- * Copyright 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
- * 
+ * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2007 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
  * License along with this library; if not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
- * 
- *  The development of this code was made possible due to the involvement of Pioneers of
- *  the Inevitable, the creators of the Songbird Music player
  *
-
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player
+ *
  */
 
 #ifndef __GST_OSXAUDIOSINK_H__
@@ -56,7 +55,6 @@
 
 G_BEGIN_DECLS
 
-/* #defines don't like whitespacey bits */
 #define GST_TYPE_OSX_AUDIO_SINK \
   (gst_osx_audio_sink_get_type())
 #define GST_OSX_AUDIO_SINK(obj) \
@@ -64,7 +62,7 @@ G_BEGIN_DECLS
 #define GST_OSX_AUDIO_SINK_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SINK,GstOsxAudioSinkClass))
 
-typedef struct _GstOsxAudioSink      GstOsxAudioSink;
+typedef struct _GstOsxAudioSink GstOsxAudioSink;
 typedef struct _GstOsxAudioSinkClass GstOsxAudioSinkClass;
 
 struct _GstOsxAudioSink
@@ -72,7 +70,8 @@ struct _GstOsxAudioSink
   GstBaseAudioSink sink;
 
   AudioDeviceID device_id;
-  AudioStreamID stream_id;
+  AudioUnit audiounit;
+  double volume;
 };
 
 struct _GstOsxAudioSinkClass 
index c89bcdb..1d99e8d 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * GStreamer
- * Copyright 2005,2006 Zaheer Abbas Merali  <zaheerabbas at merali dot org>
- *                2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
- * 
+ * Copyright (C) 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -61,6 +61,7 @@
 
 #include <gst/gst.h>
 #include <CoreAudio/CoreAudio.h>
+#include <CoreAudio/AudioHardware.h>
 #include "gstosxaudiosrc.h"
 #include "gstosxaudioelement.h"
 
@@ -94,7 +95,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
         "signed = (boolean) { TRUE }, "
         "width = (int) 32, "
         "depth = (int) 32, "
-        "rate = (int) [1, MAX], " "channels = (int) [1, 2]")
+        "rate = (int) [1, MAX], " "channels = (int) [1, MAX]")
     );
 
 static void gst_osx_audio_src_set_property (GObject * object, guint prop_id,
@@ -102,19 +103,20 @@ static void gst_osx_audio_src_set_property (GObject * object, guint prop_id,
 static void gst_osx_audio_src_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
+static GstCaps *gst_osx_audio_src_get_caps (GstBaseSrc * src);
 
 static GstRingBuffer *gst_osx_audio_src_create_ringbuffer (GstBaseAudioSrc *
     src);
 static void gst_osx_audio_src_osxelement_init (gpointer g_iface,
     gpointer iface_data);
-OSStatus gst_osx_audio_src_io_proc (AudioDeviceID inDevice,
-    const AudioTimeStamp * inNow, const AudioBufferList * inInputData,
-    const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData,
-    const AudioTimeStamp * inOutputTime, void *inClientData);
+static OSStatus gst_osx_audio_src_io_proc (GstOsxRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber,
+    UInt32 inNumberFrames, AudioBufferList * bufferList);
 static void gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc);
 
 static void
-gst_osx_audio_src_osxelement_do_init (GType type)
+gst_osx_audio_src_do_init (GType type)
 {
   static const GInterfaceInfo osxelement_info = {
     gst_osx_audio_src_osxelement_init,
@@ -130,8 +132,7 @@ gst_osx_audio_src_osxelement_do_init (GType type)
 }
 
 GST_BOILERPLATE_FULL (GstOsxAudioSrc, gst_osx_audio_src, GstBaseAudioSrc,
-    GST_TYPE_BASE_AUDIO_SRC, gst_osx_audio_src_osxelement_do_init);
-
+    GST_TYPE_BASE_AUDIO_SRC, gst_osx_audio_src_do_init);
 
 static void
 gst_osx_audio_src_base_init (gpointer g_class)
@@ -144,16 +145,17 @@ gst_osx_audio_src_base_init (gpointer g_class)
   gst_element_class_set_details (element_class, &gst_osx_audio_src_details);
 }
 
-/* initialize the plugin's class */
 static void
 gst_osx_audio_src_class_init (GstOsxAudioSrcClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
+  GstBaseSrcClass *gstbasesrc_class;
   GstBaseAudioSrcClass *gstbaseaudiosrc_class;
 
   gobject_class = (GObjectClass *) klass;
   gstelement_class = (GstElementClass *) klass;
+  gstbasesrc_class = (GstBaseSrcClass *) klass;
   gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
 
   parent_class = g_type_class_peek_parent (klass);
@@ -163,28 +165,23 @@ gst_osx_audio_src_class_init (GstOsxAudioSrcClass * klass)
   gobject_class->get_property =
       GST_DEBUG_FUNCPTR (gst_osx_audio_src_get_property);
 
+  gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_src_get_caps);
+
   g_object_class_install_property (gobject_class, ARG_DEVICE,
       g_param_spec_int ("device", "Device ID", "Device ID of input device",
           0, G_MAXINT, 0, G_PARAM_READWRITE));
 
   gstbaseaudiosrc_class->create_ringbuffer =
       GST_DEBUG_FUNCPTR (gst_osx_audio_src_create_ringbuffer);
-
 }
 
-/* initialize the new element
- * instantiate pads and add them to element
- * set functions
- * initialize structure
- */
 static void
 gst_osx_audio_src_init (GstOsxAudioSrc * src, GstOsxAudioSrcClass * gclass)
 {
-/*  GstElementClass *klass = GST_ELEMENT_GET_CLASS (src); */
   gst_base_src_set_live (GST_BASE_SRC (src), TRUE);
 
   src->device_id = kAudioDeviceUnknown;
-  src->stream_id = kAudioStreamUnknown;
+  src->deviceChannels = -1;
 }
 
 static void
@@ -219,10 +216,43 @@ gst_osx_audio_src_get_property (GObject * object, guint prop_id,
   }
 }
 
-/* GstElement vmethod implementations */
+static GstCaps *
+gst_osx_audio_src_get_caps (GstBaseSrc * src)
+{
+  GstElementClass *gstelement_class;
+  GstOsxAudioSrc *osxsrc;
+  GstPadTemplate *pad_template;
+  GstCaps *caps;
+  GstStructure *structure;
+  gint min, max;
+
+  gstelement_class = GST_ELEMENT_GET_CLASS (src);
+  osxsrc = GST_OSX_AUDIO_SRC (src);
+
+  if (osxsrc->deviceChannels == -1) {
+    /* -1 means we don't know the number of channels yet.  for now, return
+     * template caps.
+     */
+    return NULL;
+  }
+
+  max = osxsrc->deviceChannels;
+  if (max < 1)
+    max = 1;                    /* 0 channels means 1 channel? */
 
+  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));
+
+  structure = gst_caps_get_structure (caps, 0);
+  gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, min, max, NULL);
+
+  return caps;
+}
 
-/* GstBaseAudioSrc vmethod implementations */
 static GstRingBuffer *
 gst_osx_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
 {
@@ -235,42 +265,63 @@ gst_osx_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
 
   GST_DEBUG ("Creating ringbuffer");
   ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL);
-
-  /* change the device to the Default Input Device */
   GST_DEBUG ("osx src 0x%p element 0x%p  ioproc 0x%p", osxsrc,
       GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc),
       (void *) gst_osx_audio_src_io_proc);
 
   ringbuffer->element = GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc);
+  ringbuffer->is_src = TRUE;
   ringbuffer->device_id = osxsrc->device_id;
-  ringbuffer->stream_id = osxsrc->stream_id;
 
   return GST_RING_BUFFER (ringbuffer);
 }
 
-OSStatus
-gst_osx_audio_src_io_proc (AudioDeviceID inDevice, const AudioTimeStamp * inNow,
-    const AudioBufferList * inInputData, const AudioTimeStamp * inInputTime,
-    AudioBufferList * outOutputData, const AudioTimeStamp * inOutputTime,
-    void *inClientData)
+static OSStatus
+gst_osx_audio_src_io_proc (GstOsxRingBuffer * buf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * bufferList)
 {
-  GstOsxRingBuffer *buf = GST_OSX_RING_BUFFER (inClientData);
-
+  OSStatus status;
   guint8 *writeptr;
   gint writeseg;
   gint len;
-  gint bytesToCopy;
+  gint remaining;
+  gint offset = 0;
+
+  status = AudioUnitRender (buf->audiounit, ioActionFlags, inTimeStamp,
+      inBusNumber, inNumberFrames, buf->recBufferList);
+
+  if (status) {
+    GST_WARNING_OBJECT (buf, "AudioUnitRender returned %d", (int) status);
+    return status;
+  }
+
+  remaining = buf->recBufferList->mBuffers[0].mDataByteSize;
 
-  if (gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf), &writeseg, &writeptr,
-          &len)) {
-    bytesToCopy = inInputData->mBuffers[0].mDataByteSize;
-    memcpy (writeptr, (char *) inInputData->mBuffers[0].mData, bytesToCopy);
+  while (remaining) {
+    if (!gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf),
+            &writeseg, &writeptr, &len))
+      return 0;
 
-    /* clear written samples */
-    /*gst_ring_buffer_clear (GST_RING_BUFFER(buf), writeseg); */
+    len -= buf->segoffset;
 
-    /* we wrote one segment */
-    gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1);
+    if (len > remaining)
+      len = remaining;
+
+    memcpy (writeptr + buf->segoffset,
+        (char *) buf->recBufferList->mBuffers[0].mData + offset, len);
+
+    buf->segoffset += len;
+    offset += len;
+    remaining -= len;
+
+    if ((gint) buf->segoffset == GST_RING_BUFFER (buf)->spec.segsize) {
+      /* we wrote one segment */
+      gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1);
+
+      buf->segoffset = 0;
+    }
   }
   return 0;
 }
@@ -280,7 +331,7 @@ gst_osx_audio_src_osxelement_init (gpointer g_iface, gpointer iface_data)
 {
   GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface;
 
-  iface->io_proc = gst_osx_audio_src_io_proc;
+  iface->io_proc = (AURenderCallback) gst_osx_audio_src_io_proc;
 }
 
 static void
@@ -290,66 +341,26 @@ gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc)
   UInt32 propertySize;
 
   if (osxsrc->device_id == kAudioDeviceUnknown) {
+    /* If no specific device has been selected by the user, then pick the
+     * default device */
     GST_DEBUG_OBJECT (osxsrc, "Selecting device for OSXAudioSrc");
     propertySize = sizeof (osxsrc->device_id);
     status = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultInputDevice,
         &propertySize, &osxsrc->device_id);
 
-    if (status)
+    if (status) {
       GST_WARNING_OBJECT (osxsrc,
           "AudioHardwareGetProperty returned %d", (int) status);
-    else
+    } else {
       GST_DEBUG_OBJECT (osxsrc, "AudioHardwareGetProperty returned 0");
+    }
 
-    if (osxsrc->device_id == kAudioDeviceUnknown)
+    if (osxsrc->device_id == kAudioDeviceUnknown) {
       GST_WARNING_OBJECT (osxsrc,
           "AudioHardwareGetProperty: device_id is kAudioDeviceUnknown");
+    }
 
     GST_DEBUG_OBJECT (osxsrc, "AudioHardwareGetProperty: device_id is %lu",
         (long) osxsrc->device_id);
   }
-
-  if (osxsrc->stream_id == kAudioStreamUnknown) {
-    AudioStreamID *streams;
-
-    GST_DEBUG_OBJECT (osxsrc, "Getting streamid");
-    status = AudioDeviceGetPropertyInfo (osxsrc->device_id, 0,  /* Master channel */
-        FALSE,                  /* isInput */
-        kAudioDevicePropertyStreams, &propertySize, NULL);
-
-    if (status) {
-      GST_WARNING_OBJECT (osxsrc,
-          "AudioDeviceGetProperty returned %d", (int) status);
-      return;
-    }
-
-    GST_DEBUG_OBJECT (osxsrc,
-        "Getting available streamids from %d (%d bytes)",
-        (int) (propertySize / sizeof (AudioStreamID)),
-        (unsigned int) propertySize);
-    streams = g_malloc (propertySize);
-    status = AudioDeviceGetProperty (osxsrc->device_id, 0,      /* Master channel */
-        FALSE,                  /* isInput */
-        kAudioDevicePropertyStreams, &propertySize, streams);
-
-    if (status) {
-      GST_WARNING_OBJECT (osxsrc,
-          "AudioDeviceGetProperty returned %d", (int) status);
-      g_free (streams);
-      return;
-    }
-
-    GST_DEBUG_OBJECT (osxsrc, "Getting streamid from %d (%d bytes)",
-        (int) (propertySize / sizeof (AudioStreamID)),
-        (unsigned int) propertySize);
-
-    if (propertySize >= sizeof (AudioStreamID)) {
-      osxsrc->stream_id = streams[0];
-      GST_DEBUG_OBJECT (osxsrc, "Selected stream %d of %d: %d", 0,
-          (int) (propertySize / sizeof (AudioStreamID)),
-          (int) osxsrc->stream_id);
-    }
-
-    g_free (streams);
-  }
 }
index 7336c82..a812d9e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * GStreamer
- * Copyright 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
- * 
+ * Copyright (C) 2005-2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
@@ -50,7 +50,6 @@
 
 G_BEGIN_DECLS
 
-/* #defines don't like whitespacey bits */
 #define GST_TYPE_OSX_AUDIO_SRC \
   (gst_osx_audio_src_get_type())
 #define GST_OSX_AUDIO_SRC(obj) \
@@ -58,7 +57,7 @@ G_BEGIN_DECLS
 #define GST_OSX_AUDIO_SRC_CLASS(klass) \
   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_AUDIO_SRC,GstOsxAudioSrcClass))
 
-typedef struct _GstOsxAudioSrc      GstOsxAudioSrc;
+typedef struct _GstOsxAudioSrc GstOsxAudioSrc;
 typedef struct _GstOsxAudioSrcClass GstOsxAudioSrcClass;
 
 struct _GstOsxAudioSrc
@@ -66,7 +65,9 @@ struct _GstOsxAudioSrc
   GstBaseAudioSrc src;
 
   AudioDeviceID device_id;
-  AudioStreamID stream_id;
+
+  /* actual number of channels reported by input device */
+  int deviceChannels;
 };
 
 struct _GstOsxAudioSrcClass 
index c99e3f3..f6fd2e5 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * GStreamer
- * Copyright 2006 Zaheer Abbas Merali  <zaheerabbas at merali dot org>
- * 
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
 
 #include <CoreAudio/CoreAudio.h>
 #include <gst/gst.h>
+#include <gst/audio/multichannel.h>
 #include "gstosxringbuffer.h"
+#include "gstosxaudiosink.h"
+#include "gstosxaudiosrc.h"
 
 GST_DEBUG_CATEGORY_STATIC (osx_audio_debug);
 #define GST_CAT_DEFAULT osx_audio_debug
 
-static void gst_osx_ring_buffer_class_init (GstOsxRingBufferClass * klass);
-static void gst_osx_ring_buffer_init (GstOsxRingBuffer * ringbuffer,
-    GstOsxRingBufferClass * g_class);
 static void gst_osx_ring_buffer_dispose (GObject * object);
 static void gst_osx_ring_buffer_finalize (GObject * object);
 static gboolean gst_osx_ring_buffer_open_device (GstRingBuffer * buf);
@@ -60,43 +61,34 @@ static gboolean gst_osx_ring_buffer_acquire (GstRingBuffer * buf,
     GstRingBufferSpec * spec);
 static gboolean gst_osx_ring_buffer_release (GstRingBuffer * buf);
 
-/* static gboolean gst_osx_ring_buffer_device_is_acquired (GstRingBuffer * buf); */
-
 static gboolean gst_osx_ring_buffer_start (GstRingBuffer * buf);
 static gboolean gst_osx_ring_buffer_pause (GstRingBuffer * buf);
 static gboolean gst_osx_ring_buffer_stop (GstRingBuffer * buf);
 static guint gst_osx_ring_buffer_delay (GstRingBuffer * buf);
 static GstRingBufferClass *ring_parent_class = NULL;
 
-/* ringbuffer abstract base class */
+static OSStatus gst_osx_ring_buffer_render_notify (GstOsxRingBuffer * osxbuf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp, unsigned int inBusNumber,
+    unsigned int inNumberFrames, AudioBufferList * ioData);
+
+static AudioBufferList *buffer_list_alloc (int channels, int size);
+static void buffer_list_free (AudioBufferList * list);
 
-GType
-gst_osx_ring_buffer_get_type (void)
+static void
+gst_osx_ring_buffer_do_init (GType type)
 {
-  static GType ringbuffer_type = 0;
-
-  if (!ringbuffer_type) {
-    static const GTypeInfo ringbuffer_info = {
-      sizeof (GstOsxRingBufferClass),
-      NULL,
-      NULL,
-      (GClassInitFunc) gst_osx_ring_buffer_class_init,
-      NULL,
-      NULL,
-      sizeof (GstOsxRingBuffer),
-      0,
-      (GInstanceInitFunc) gst_osx_ring_buffer_init,
-      NULL
-    };
-    GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0,
-        "OSX Audio Elements");
-    GST_DEBUG ("Creating osx ring buffer type");
-
-    ringbuffer_type =
-        g_type_register_static (GST_TYPE_RING_BUFFER, "GstOsxRingBuffer",
-        &ringbuffer_info, 0);
-  }
-  return ringbuffer_type;
+  GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0,
+      "OSX Audio Elements");
+}
+
+GST_BOILERPLATE_FULL (GstOsxRingBuffer, gst_osx_ring_buffer, GstRingBuffer,
+    GST_TYPE_RING_BUFFER, gst_osx_ring_buffer_do_init);
+
+static void
+gst_osx_ring_buffer_base_init (gpointer g_class)
+{
+  /* Nothing to do right now */
 }
 
 static void
@@ -152,159 +144,463 @@ gst_osx_ring_buffer_finalize (GObject * object)
   G_OBJECT_CLASS (ring_parent_class)->finalize (object);
 }
 
+static AudioUnit
+gst_osx_ring_buffer_create_audio_unit (GstOsxRingBuffer * osxbuf,
+    gboolean input, AudioDeviceID device_id)
+{
+  ComponentDescription desc;
+  Component comp;
+  OSStatus status;
+  AudioUnit unit;
+  UInt32 enableIO;
+
+  /* Create a HALOutput AudioUnit.
+   * This is the lowest-level output API that is actually sensibly usable
+   * (the lower level ones require that you do channel-remapping yourself,
+   * and the CoreAudio channel mapping is sufficiently complex that doing
+   * so would be very difficult)
+   *
+   * Note that for input we request an output unit even though we will do
+   * input with it: http://developer.apple.com/technotes/tn2002/tn2091.html
+   */
+  desc.componentType = kAudioUnitType_Output;
+  desc.componentSubType = kAudioUnitSubType_HALOutput;
+  desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+  desc.componentFlags = 0;
+  desc.componentFlagsMask = 0;
+
+  comp = FindNextComponent (NULL, &desc);
+  if (comp == NULL) {
+    GST_WARNING_OBJECT (osxbuf, "Couldn't find HALOutput component");
+    return NULL;
+  }
+
+  status = OpenAComponent (comp, &unit);
+
+  if (status) {
+    GST_WARNING_OBJECT (osxbuf, "Couldn't open HALOutput component");
+    return NULL;
+  }
+
+  if (input) {
+    /* enable input */
+    enableIO = 1;
+    status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1,   /* 1 = input element */
+        &enableIO, sizeof (enableIO));
+
+    if (status) {
+      CloseComponent (unit);
+      GST_WARNING_OBJECT (osxbuf, "Failed to enable input: %lx", status);
+      return NULL;
+    }
+
+    /* disable output */
+    enableIO = 0;
+    status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0,  /* 0 = output element */
+        &enableIO, sizeof (enableIO));
+
+    if (status) {
+      CloseComponent (unit);
+      GST_WARNING_OBJECT (osxbuf, "Failed to disable output: %lx", status);
+      return NULL;
+    }
+  }
+
+  /* Specify which device we're using. */
+  GST_DEBUG_OBJECT (osxbuf, "Setting device to %d", (int) device_id);
+  status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0,       /* N/A for global */
+      &device_id, sizeof (AudioDeviceID));
+
+  if (status) {
+    CloseComponent (unit);
+    GST_WARNING_OBJECT (osxbuf, "Failed to set device: %lx", status);
+    return NULL;
+  }
+
+  GST_DEBUG_OBJECT (osxbuf, "Create HALOutput AudioUnit: %p", unit);
+
+  return unit;
+}
+
 static gboolean
 gst_osx_ring_buffer_open_device (GstRingBuffer * buf)
 {
-  /* stub, we need to open device..maybe do nothing */
+  GstOsxRingBuffer *osxbuf;
+  GstOsxAudioSink *sink;
+  GstOsxAudioSrc *src;
+  AudioStreamBasicDescription asbd_in;
+  OSStatus status;
+  UInt32 propertySize;
+
+  osxbuf = GST_OSX_RING_BUFFER (buf);
+  sink = NULL;
+  src = NULL;
+
+  osxbuf->audiounit = gst_osx_ring_buffer_create_audio_unit (osxbuf,
+      osxbuf->is_src, osxbuf->device_id);
+
+  if (osxbuf->is_src) {
+    src = GST_OSX_AUDIO_SRC (GST_OBJECT_PARENT (buf));
+
+    propertySize = sizeof (asbd_in);
+    status = AudioUnitGetProperty (osxbuf->audiounit,
+        kAudioUnitProperty_StreamFormat,
+        kAudioUnitScope_Input, 1, &asbd_in, &propertySize);
+
+    if (status) {
+      CloseComponent (osxbuf->audiounit);
+      osxbuf->audiounit = NULL;
+      GST_WARNING_OBJECT (osxbuf, "Unable to obtain device properties: %lx",
+          status);
+      return FALSE;
+    }
+
+    src->deviceChannels = asbd_in.mChannelsPerFrame;
+  } else {
+    sink = GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (buf));
+
+    /* needed for the sink's volume control */
+    sink->audiounit = osxbuf->audiounit;
+  }
+
   return TRUE;
 }
 
 static gboolean
 gst_osx_ring_buffer_close_device (GstRingBuffer * buf)
 {
-  /* stub, we need to close device..maybe do nothing */
+  GstOsxRingBuffer *osxbuf;
+  osxbuf = GST_OSX_RING_BUFFER (buf);
+
+  CloseComponent (osxbuf->audiounit);
+  osxbuf->audiounit = NULL;
+
   return TRUE;
 }
 
+static AudioChannelLabel
+gst_audio_channel_position_to_coreaudio_channel_label (GstAudioChannelPosition
+    position, int channel)
+{
+  switch (position) {
+    case GST_AUDIO_CHANNEL_POSITION_NONE:
+      return kAudioChannelLabel_Discrete_0 | channel;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO:
+      return kAudioChannelLabel_Mono;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT:
+      return kAudioChannelLabel_Left;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT:
+      return kAudioChannelLabel_Right;
+    case GST_AUDIO_CHANNEL_POSITION_REAR_CENTER:
+      return kAudioChannelLabel_CenterSurround;
+    case GST_AUDIO_CHANNEL_POSITION_REAR_LEFT:
+      return kAudioChannelLabel_LeftSurround;
+    case GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT:
+      return kAudioChannelLabel_RightSurround;
+    case GST_AUDIO_CHANNEL_POSITION_LFE:
+      return kAudioChannelLabel_LFEScreen;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER:
+      return kAudioChannelLabel_Center;
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
+      return kAudioChannelLabel_Center; // ???
+    case GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
+      return kAudioChannelLabel_Center; // ???
+    case GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT:
+      return kAudioChannelLabel_LeftSurroundDirect;
+    case GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT:
+      return kAudioChannelLabel_RightSurroundDirect;
+    default:
+      return kAudioChannelLabel_Unknown;
+  }
+}
+
 static gboolean
 gst_osx_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
 {
   /* Configure the output stream and allocate ringbuffer memory */
   GstOsxRingBuffer *osxbuf;
-  AudioStreamBasicDescription asbd;
+  AudioStreamBasicDescription format;
+  AudioChannelLayout *layout = NULL;
   OSStatus status;
-  UInt32 buffer_len;
   UInt32 propertySize;
+  int layoutSize;
+  int element;
+  int i;
+  AudioUnitScope scope;
+  gboolean ret = FALSE;
+  GstStructure *structure;
+  GstAudioChannelPosition *positions;
+  UInt32 frameSize;
 
   osxbuf = GST_OSX_RING_BUFFER (buf);
 
   /* Fill out the audio description we're going to be using */
-  asbd.mFormatID = kAudioFormatLinearPCM;
-  asbd.mSampleRate = (double) spec->rate;
-  asbd.mChannelsPerFrame = spec->channels;
-  asbd.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
-  asbd.mBytesPerFrame = spec->channels * sizeof (float);
-  asbd.mBitsPerChannel = sizeof (float) * 8;
-  asbd.mBytesPerPacket = spec->channels * sizeof (float);
-  asbd.mFramesPerPacket = 1;
-  asbd.mReserved = 0;
+  format.mFormatID = kAudioFormatLinearPCM;
+  format.mSampleRate = (double) spec->rate;
+  format.mChannelsPerFrame = spec->channels;
+  format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+  format.mBytesPerFrame = spec->channels * sizeof (float);
+  format.mBitsPerChannel = sizeof (float) * 8;
+  format.mBytesPerPacket = spec->channels * sizeof (float);
+  format.mFramesPerPacket = 1;
+  format.mReserved = 0;
+
+  /* Describe channels */
+  layoutSize = sizeof (AudioChannelLayout) +
+      spec->channels * sizeof (AudioChannelDescription);
+  layout = g_malloc (layoutSize);
+
+  structure = gst_caps_get_structure (spec->caps, 0);
+  positions = gst_audio_get_channel_positions (structure);
+
+  layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+  layout->mChannelBitmap = 0;   /* Not used */
+  layout->mNumberChannelDescriptions = spec->channels;
+  for (i = 0; i < spec->channels; i++) {
+    if (positions) {
+      layout->mChannelDescriptions[i].mChannelLabel =
+          gst_audio_channel_position_to_coreaudio_channel_label (positions[i],
+          i);
+    } else {
+      /* Discrete channel numbers are ORed into this */
+      layout->mChannelDescriptions[i].mChannelLabel =
+          kAudioChannelLabel_Discrete_0 | i;
+    }
+
+    /* Others unused */
+    layout->mChannelDescriptions[i].mChannelFlags = 0;
+    layout->mChannelDescriptions[i].mCoordinates[0] = 0.f;
+    layout->mChannelDescriptions[i].mCoordinates[1] = 0.f;
+    layout->mChannelDescriptions[i].mCoordinates[2] = 0.f;
+  }
+
+  if (positions) {
+    g_free (positions);
+    positions = NULL;
+  }
 
   GST_LOG_OBJECT (osxbuf, "Format: %x, %f, %u, %x, %d, %d, %d, %d, %d",
-      (unsigned int) asbd.mFormatID,
-      asbd.mSampleRate,
-      (unsigned int) asbd.mChannelsPerFrame,
-      (unsigned int) asbd.mFormatFlags,
-      (unsigned int) asbd.mBytesPerFrame,
-      (unsigned int) asbd.mBitsPerChannel,
-      (unsigned int) asbd.mBytesPerPacket,
-      (unsigned int) asbd.mFramesPerPacket, (unsigned int) asbd.mReserved);
-
-  GST_DEBUG_OBJECT (osxbuf, "Using stream_id %d, setting output format",
-      (int) osxbuf->stream_id);
-
-  propertySize = sizeof (asbd);
-  status = AudioStreamSetProperty (osxbuf->stream_id, NULL,     /* Change immediately */
-      0,                        /* Master channel */
-      kAudioStreamPropertyVirtualFormat, propertySize, &asbd);
+      (unsigned int) format.mFormatID,
+      format.mSampleRate,
+      (unsigned int) format.mChannelsPerFrame,
+      (unsigned int) format.mFormatFlags,
+      (unsigned int) format.mBytesPerFrame,
+      (unsigned int) format.mBitsPerChannel,
+      (unsigned int) format.mBytesPerPacket,
+      (unsigned int) format.mFramesPerPacket, (unsigned int) format.mReserved);
+
+  GST_DEBUG_OBJECT (osxbuf, "Setting format for AudioUnit");
+
+  scope = osxbuf->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input;
+  element = osxbuf->is_src ? 1 : 0;
+
+  propertySize = sizeof (format);
+  status = AudioUnitSetProperty (osxbuf->audiounit,
+      kAudioUnitProperty_StreamFormat, scope, element, &format, propertySize);
 
   if (status) {
-    GST_WARNING_OBJECT (osxbuf, "Failed to set output description: %lx",
+    GST_WARNING_OBJECT (osxbuf, "Failed to set audio description: %lx", status);
+    goto done;
+  }
+
+  status = AudioUnitSetProperty (osxbuf->audiounit,
+      kAudioUnitProperty_AudioChannelLayout,
+      scope, element, layout, layoutSize);
+  if (status) {
+    GST_WARNING_OBJECT (osxbuf, "Failed to set output channel layout: %lx",
         status);
-    return FALSE;
+    goto done;
   }
 
-  /* get requested buffer length to use */
-  propertySize = sizeof (buffer_len);
-  status = AudioDeviceGetProperty (osxbuf->device_id, 0, false, /* TODO, this should be true for the source element */
-      kAudioDevicePropertyBufferSize, &propertySize, &buffer_len);
+  spec->segsize = 4096;
+  spec->segtotal = 16;
 
+  /* create AudioBufferList needed for recording */
+  if (osxbuf->is_src) {
+    propertySize = sizeof (frameSize);
+    status = AudioUnitGetProperty (osxbuf->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0,   /* N/A for global */
+        &frameSize, &propertySize);
+
+    if (status) {
+      GST_WARNING_OBJECT (osxbuf, "Failed to get frame size: %lx", status);
+      goto done;
+    }
+
+    osxbuf->recBufferList = buffer_list_alloc (format.mChannelsPerFrame,
+        frameSize * format.mBytesPerFrame);
+  }
+
+  buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
+  memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
+
+  status = AudioUnitInitialize (osxbuf->audiounit);
   if (status) {
+    gst_buffer_unref (buf->data);
+    buf->data = NULL;
+
+    if (osxbuf->recBufferList) {
+      buffer_list_free (osxbuf->recBufferList);
+      osxbuf->recBufferList = NULL;
+    }
+
     GST_WARNING_OBJECT (osxbuf,
-        "AudioDeviceGetProperty returned %d when getting "
-        "kAudioDevicePropertyBufferSize", (int) status);
+        "Failed to initialise AudioUnit: %d", (int) status);
+    goto done;
   }
-  GST_DEBUG_OBJECT (osxbuf, "%5d osxbuf->buffer_len", (int) buffer_len);
-  spec->segsize = buffer_len;
-  spec->segtotal = 16;
 
   GST_DEBUG_OBJECT (osxbuf, "osx ring buffer acquired");
 
-  buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
-  memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
+  ret = TRUE;
 
-  return TRUE;
+done:
+  g_free (layout);
+  return ret;
 }
 
 static gboolean
 gst_osx_ring_buffer_release (GstRingBuffer * buf)
 {
-  /* stub, we need to deallocate ringbuffer memory */
   GstOsxRingBuffer *osxbuf;
 
   osxbuf = GST_OSX_RING_BUFFER (buf);
 
+  AudioUnitUninitialize (osxbuf->audiounit);
+
   gst_buffer_unref (buf->data);
   buf->data = NULL;
 
+  if (osxbuf->recBufferList) {
+    buffer_list_free (osxbuf->recBufferList);
+    osxbuf->recBufferList = NULL;
+  }
+
   return TRUE;
 }
 
+static void
+gst_osx_ring_buffer_remove_render_callback (GstOsxRingBuffer * osxbuf)
+{
+  AURenderCallbackStruct input;
+  OSStatus status;
+
+  /* Deactivate the render callback by calling SetRenderCallback with a NULL
+   * inputProc.
+   */
+  input.inputProc = NULL;
+  input.inputProcRefCon = NULL;
+
+  status = AudioUnitSetProperty (osxbuf->audiounit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0,    /* N/A for global */
+      &input, sizeof (input));
+
+  if (status) {
+    GST_WARNING_OBJECT (osxbuf, "Failed to remove render callback");
+  }
+
+  /* Remove the RenderNotify too */
+  status = AudioUnitRemoveRenderNotify (osxbuf->audiounit,
+      (AURenderCallback) gst_osx_ring_buffer_render_notify, osxbuf);
+
+  if (status) {
+    GST_WARNING_OBJECT (osxbuf, "Failed to remove render notify callback");
+  }
+
+  /* We're deactivated.. */
+  osxbuf->io_proc_needs_deactivation = FALSE;
+  osxbuf->io_proc_active = FALSE;
+}
+
+static OSStatus
+gst_osx_ring_buffer_render_notify (GstOsxRingBuffer * osxbuf,
+    AudioUnitRenderActionFlags * ioActionFlags,
+    const AudioTimeStamp * inTimeStamp,
+    unsigned int inBusNumber,
+    unsigned int inNumberFrames, AudioBufferList * ioData)
+{
+  /* Before rendering a frame, we get the PreRender notification.
+   * Here, we detach the RenderCallback if we've been paused.
+   *
+   * This is necessary (rather than just directly detaching it) to work
+   * around some thread-safety issues in CoreAudio
+   */
+  if ((*ioActionFlags) & kAudioUnitRenderAction_PreRender) {
+    if (osxbuf->io_proc_needs_deactivation) {
+      gst_osx_ring_buffer_remove_render_callback (osxbuf);
+    }
+  }
+
+  return noErr;
+}
+
 static gboolean
 gst_osx_ring_buffer_start (GstRingBuffer * buf)
 {
-  /* stub */
   OSStatus status;
   GstOsxRingBuffer *osxbuf;
+  AURenderCallbackStruct input;
+  AudioUnitPropertyID callback_type;
 
   osxbuf = GST_OSX_RING_BUFFER (buf);
 
   GST_DEBUG ("osx ring buffer start ioproc: 0x%p device_id %lu",
       osxbuf->element->io_proc, osxbuf->device_id);
   if (!osxbuf->io_proc_active) {
-    status =
-        AudioDeviceAddIOProc (osxbuf->device_id, osxbuf->element->io_proc,
-        osxbuf);
+    callback_type = osxbuf->is_src ?
+        kAudioOutputUnitProperty_SetInputCallback :
+        kAudioUnitProperty_SetRenderCallback;
+
+    input.inputProc = (AURenderCallback) osxbuf->element->io_proc;
+    input.inputProcRefCon = osxbuf;
+
+    status = AudioUnitSetProperty (osxbuf->audiounit, callback_type, kAudioUnitScope_Global, 0, /* N/A for global */
+        &input, sizeof (input));
+
+    if (status) {
+      GST_WARNING ("AudioUnitSetProperty returned %d", (int) status);
+      return FALSE;
+    }
+    // ### does it make sense to do this notify stuff for input mode?
+    status = AudioUnitAddRenderNotify (osxbuf->audiounit,
+        (AURenderCallback) gst_osx_ring_buffer_render_notify, osxbuf);
 
     if (status) {
-      GST_WARNING ("AudioDeviceAddIOProc returned %" GST_FOURCC_FORMAT,
-          GST_FOURCC_ARGS (status));
+      GST_WARNING ("AudioUnitAddRenderNotify returned %d", (int) status);
       return FALSE;
     }
+
     osxbuf->io_proc_active = TRUE;
-  }
+  } else
+    osxbuf->io_proc_needs_deactivation = FALSE;
 
-  status = AudioDeviceStart (osxbuf->device_id, osxbuf->element->io_proc);
+  status = AudioOutputUnitStart (osxbuf->audiounit);
   if (status) {
-    GST_WARNING ("AudioDeviceStart returned %d", (int) status);
+    GST_WARNING ("AudioOutputUnitStart returned %d", (int) status);
     return FALSE;
   }
   return TRUE;
 }
 
+// ###
 static gboolean
 gst_osx_ring_buffer_pause (GstRingBuffer * buf)
 {
-  /* stub */
-  /* stop callback */
-  OSErr status;
   GstOsxRingBuffer *osxbuf = GST_OSX_RING_BUFFER (buf);
 
   GST_DEBUG ("osx ring buffer pause ioproc: 0x%p device_id %lu",
       osxbuf->element->io_proc, osxbuf->device_id);
   if (osxbuf->io_proc_active) {
-    status =
-        AudioDeviceRemoveIOProc (osxbuf->device_id, osxbuf->element->io_proc);
-    if (status)
-      GST_WARNING ("AudioDeviceRemoveIOProc " "returned %d", (int) status);
-    osxbuf->io_proc_active = FALSE;
+    /* CoreAudio isn't threadsafe enough to do this here; we must deactivate
+     * the render callback elsewhere. See:
+     *   http://lists.apple.com/archives/Coreaudio-api/2006/Mar/msg00010.html
+     */
+    osxbuf->io_proc_needs_deactivation = TRUE;
   }
   return TRUE;
 }
 
+// ###
 static gboolean
 gst_osx_ring_buffer_stop (GstRingBuffer * buf)
 {
-  /* stub */
   OSErr status;
   GstOsxRingBuffer *osxbuf;
 
@@ -312,17 +608,14 @@ gst_osx_ring_buffer_stop (GstRingBuffer * buf)
 
   GST_DEBUG ("osx ring buffer stop ioproc: 0x%p device_id %lu",
       osxbuf->element->io_proc, osxbuf->device_id);
-  /* stop callback */
-  status = AudioDeviceStop (osxbuf->device_id, osxbuf->element->io_proc);
+
+  status = AudioOutputUnitStop (osxbuf->audiounit);
   if (status)
-    GST_WARNING ("AudioDeviceStop returned %d", (int) status);
+    GST_WARNING ("AudioOutputUnitStop returned %d", (int) status);
 
+  // ###: why is it okay to directly remove from here but not from pause() ?
   if (osxbuf->io_proc_active) {
-    status =
-        AudioDeviceRemoveIOProc (osxbuf->device_id, osxbuf->element->io_proc);
-    if (status)
-      GST_WARNING ("AudioDeviceRemoveIOProc " "returned %d", (int) status);
-    osxbuf->io_proc_active = FALSE;
+    gst_osx_ring_buffer_remove_render_callback (osxbuf);
   }
   return TRUE;
 }
@@ -330,6 +623,57 @@ gst_osx_ring_buffer_stop (GstRingBuffer * buf)
 static guint
 gst_osx_ring_buffer_delay (GstRingBuffer * buf)
 {
-  /* stub */
-  return 0;
+  double latency;
+  UInt32 size = sizeof (double);
+  GstOsxRingBuffer *osxbuf;
+  OSStatus status;
+  guint samples;
+
+  osxbuf = GST_OSX_RING_BUFFER (buf);
+
+  status = AudioUnitGetProperty (osxbuf->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0,      /* N/A for global */
+      &latency, &size);
+
+  if (status) {
+    GST_WARNING_OBJECT (buf, "Failed to get latency: %d", (int) status);
+    return 0;
+  }
+
+  samples = latency * GST_RING_BUFFER (buf)->spec.rate;
+  GST_DEBUG_OBJECT (buf, "Got latency: %f seconds -> %d samples", latency,
+      samples);
+  return samples;
+}
+
+static AudioBufferList *
+buffer_list_alloc (int channels, int size)
+{
+  AudioBufferList *list;
+  int total_size;
+  int n;
+
+  total_size = sizeof (AudioBufferList) + 1 * sizeof (AudioBuffer);
+  list = (AudioBufferList *) g_malloc (total_size);
+
+  list->mNumberBuffers = 1;
+  for (n = 0; n < (int) list->mNumberBuffers; ++n) {
+    list->mBuffers[n].mNumberChannels = channels;
+    list->mBuffers[n].mDataByteSize = size;
+    list->mBuffers[n].mData = g_malloc (size);
+  }
+
+  return list;
+}
+
+static void
+buffer_list_free (AudioBufferList * list)
+{
+  int n;
+
+  for (n = 0; n < (int) list->mNumberBuffers; ++n) {
+    if (list->mBuffers[n].mData)
+      g_free (list->mBuffers[n].mData);
+  }
+
+  g_free (list);
 }
index 40a299f..5e6dbe4 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * GStreamer
- * Copyright 2006 Zaheer Abbas Merali  <zaheerabbas at merali dot org>
- * 
+ * Copyright (C) 2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  * to deal in the Software without restriction, including without limitation
 #include <gst/gst.h>
 #include <gst/audio/gstringbuffer.h>
 #include <CoreAudio/CoreAudio.h>
-
 #include "gstosxaudioelement.h"
 
 G_BEGIN_DECLS
 
-#define GST_TYPE_OSX_RING_BUFFER            (gst_osx_ring_buffer_get_type())
-#define GST_OSX_RING_BUFFER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBuffer))
-#define GST_OSX_RING_BUFFER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBufferClass))
-#define GST_OSX_RING_BUFFER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBufferClass))
-#define GST_IS_OSX_RING_BUFFER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_RING_BUFFER))
-#define GST_IS_OSX_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSX_RING_BUFFER))
+#define GST_TYPE_OSX_RING_BUFFER \
+  (gst_osx_ring_buffer_get_type())
+#define GST_OSX_RING_BUFFER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBuffer))
+#define GST_OSX_RING_BUFFER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBufferClass))
+#define GST_OSX_RING_BUFFER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OSX_RING_BUFFER,GstOsxRingBufferClass))
+#define GST_IS_OSX_RING_BUFFER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSX_RING_BUFFER))
+#define GST_IS_OSX_RING_BUFFER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSX_RING_BUFFER))
 
 typedef struct _GstOsxRingBuffer GstOsxRingBuffer;
 typedef struct _GstOsxRingBufferClass GstOsxRingBufferClass;
 
+struct _GstOsxRingBuffer
+{
+  GstRingBuffer object;
 
-struct _GstOsxRingBuffer {
-       GstRingBuffer         object;
-       
-       AudioDeviceID  device_id;
-    AudioStreamID  stream_id;
-       gboolean io_proc_active;
-       guint buffer_len;
-       GstOsxAudioElementInterface* element;
+  gboolean is_src;
+  AudioUnit audiounit;
+  AudioDeviceID device_id;
+  gboolean io_proc_active;
+  gboolean io_proc_needs_deactivation;
+  guint buffer_len;
+  guint segoffset;
+  AudioBufferList * recBufferList;
+  GstOsxAudioElementInterface * element;
 };
 
-struct _GstOsxRingBufferClass {
-       GstRingBufferClass    parent_class;
+struct _GstOsxRingBufferClass
+{
+  GstRingBufferClass parent_class;
 };
 
 GType gst_osx_ring_buffer_get_type (void);
+
 G_END_DECLS
 
-#endif
+#endif /* __GST_OSX_RING_BUFFER_H__ */