summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Karnegas <justin@affinix.com>2009-01-02 20:39:34 +0000
committerMichael Smith <msmith@xiph.org>2009-01-02 20:39:34 +0000
commit17bb67f873a0bd3c4e631ed510a15799c253fc18 (patch)
tree710ea439dbb43826a10e0037ee144b6133f30b70
parent996fb72681d3da4fce8cb2e94957fe72aa832d8b (diff)
sys/osxaudio/: Rewrite osxaudio to work more flexibly and more reliably, using a different abstraction layer of corea...
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.
-rw-r--r--ChangeLog18
-rw-r--r--sys/osxaudio/gstosxaudio.c14
-rw-r--r--sys/osxaudio/gstosxaudioelement.c18
-rw-r--r--sys/osxaudio/gstosxaudioelement.h43
-rw-r--r--sys/osxaudio/gstosxaudiosink.c273
-rw-r--r--sys/osxaudio/gstosxaudiosink.h19
-rw-r--r--sys/osxaudio/gstosxaudiosrc.c189
-rw-r--r--sys/osxaudio/gstosxaudiosrc.h11
-rw-r--r--sys/osxaudio/gstosxringbuffer.c556
-rw-r--r--sys/osxaudio/gstosxringbuffer.h51
10 files changed, 741 insertions, 451 deletions
diff --git a/ChangeLog b/ChangeLog
index bdfdaedf..ff7a3706 100644
--- 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:
diff --git a/sys/osxaudio/gstosxaudio.c b/sys/osxaudio/gstosxaudio.c
index 9d639297..262c7d91 100644
--- a/sys/osxaudio/gstosxaudio.c
+++ b/sys/osxaudio/gstosxaudio.c
@@ -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
@@ -16,10 +17,10 @@
* 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
- *
+ *
*/
/**
@@ -42,12 +43,10 @@
* 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;
diff --git a/sys/osxaudio/gstosxaudioelement.c b/sys/osxaudio/gstosxaudioelement.c
index c3c28336..ceff749e 100644
--- a/sys/osxaudio/gstosxaudioelement.c
+++ b/sys/osxaudio/gstosxaudioelement.c
@@ -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
@@ -40,9 +40,10 @@
* 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;
-
}
diff --git a/sys/osxaudio/gstosxaudioelement.h b/sys/osxaudio/gstosxaudioelement.h
index 1ab487a2..b5d90c0c 100644
--- a/sys/osxaudio/gstosxaudioelement.h
+++ b/sys/osxaudio/gstosxaudioelement.h
@@ -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__
@@ -50,22 +51,34 @@
#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__ */
diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c
index 46d229b5..aec8874d 100644
--- a/sys/osxaudio/gstosxaudiosink.c
+++ b/sys/osxaudio/gstosxaudiosink.c
@@ -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);
- }
}
diff --git a/sys/osxaudio/gstosxaudiosink.h b/sys/osxaudio/gstosxaudiosink.h
index a46d2448..aac9719f 100644
--- a/sys/osxaudio/gstosxaudiosink.h
+++ b/sys/osxaudio/gstosxaudiosink.h
@@ -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
@@ -40,11 +40,10 @@
* 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
diff --git a/sys/osxaudio/gstosxaudiosrc.c b/sys/osxaudio/gstosxaudiosrc.c
index c89bcdb2..1d99e8d8 100644
--- a/sys/osxaudio/gstosxaudiosrc.c
+++ b/sys/osxaudio/gstosxaudiosrc.c
@@ -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);
- }
}
diff --git a/sys/osxaudio/gstosxaudiosrc.h b/sys/osxaudio/gstosxaudiosrc.h
index 7336c82f..a812d9ef 100644
--- a/sys/osxaudio/gstosxaudiosrc.h
+++ b/sys/osxaudio/gstosxaudiosrc.h
@@ -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
diff --git a/sys/osxaudio/gstosxringbuffer.c b/sys/osxaudio/gstosxringbuffer.c
index c99e3f37..f6fd2e52 100644
--- a/sys/osxaudio/gstosxringbuffer.c
+++ b/sys/osxaudio/gstosxringbuffer.c
@@ -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
@@ -43,14 +44,14 @@
#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);
}
diff --git a/sys/osxaudio/gstosxringbuffer.h b/sys/osxaudio/gstosxringbuffer.h
index 40a299ff..5e6dbe41 100644
--- a/sys/osxaudio/gstosxringbuffer.h
+++ b/sys/osxaudio/gstosxringbuffer.h
@@ -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
@@ -47,37 +47,48 @@
#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__ */