summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndoni Morales Alastruey <ylatuya@gmail.com>2013-03-05 21:17:52 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2013-03-08 12:12:03 +0100
commit89e4fb894f16d3fb04c1d3220bc953776fa65e22 (patch)
tree4400e330e6d30a863a93169d404895b917679412
parent87d7a0f91065b89f3d3c8f0b23b5274b2e9b4d3e (diff)
osxaudio: add a façade for the CoreAudio API
-rw-r--r--sys/osxaudio/Makefile.am6
-rw-r--r--sys/osxaudio/gstosxaudiosink.c118
-rw-r--r--sys/osxaudio/gstosxaudiosrc.c45
-rw-r--r--sys/osxaudio/gstosxcoreaudio.c218
-rw-r--r--sys/osxaudio/gstosxcoreaudio.h681
-rw-r--r--sys/osxaudio/gstosxcoreaudiocommon.c431
-rw-r--r--sys/osxaudio/gstosxcoreaudiocommon.h65
-rw-r--r--sys/osxaudio/gstosxcoreaudiohal.c1281
-rw-r--r--sys/osxaudio/gstosxringbuffer.c985
-rw-r--r--sys/osxaudio/gstosxringbuffer.h30
10 files changed, 2176 insertions, 1684 deletions
diff --git a/sys/osxaudio/Makefile.am b/sys/osxaudio/Makefile.am
index 80549d323..8a32bce7a 100644
--- a/sys/osxaudio/Makefile.am
+++ b/sys/osxaudio/Makefile.am
@@ -4,6 +4,8 @@ libgstosxaudio_la_SOURCES = gstosxringbuffer.c \
gstosxaudioelement.c \
gstosxaudiosink.c \
gstosxaudiosrc.c \
+ gstosxcoreaudiocommon.c \
+ gstosxcoreaudio.c \
gstosxaudio.c
libgstosxaudio_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \
@@ -21,7 +23,9 @@ noinst_HEADERS = gstosxaudiosink.h \
gstosxaudioelement.h \
gstosxringbuffer.h \
gstosxaudiosrc.h \
- gstosxcoreaudio.h
+ gstosxcoreaudiocommon.h \
+ gstosxcoreaudio.h \
+ gstosxcoreaudiohal.c
diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c
index 85ccf7655..2fc6be500 100644
--- a/sys/osxaudio/gstosxaudiosink.c
+++ b/sys/osxaudio/gstosxaudiosink.c
@@ -69,8 +69,6 @@
#include <gst/gst.h>
#include <gst/audio/multichannel.h>
#include <gst/audio/gstaudioiec61937.h>
-#include <CoreAudio/CoreAudio.h>
-#include <CoreAudio/AudioHardware.h>
#include "gstosxaudiosink.h"
#include "gstosxaudioelement.h"
@@ -171,6 +169,7 @@ gst_osx_audio_sink_do_init (GType type)
GST_DEBUG_CATEGORY_INIT (osx_audiosink_debug, "osxaudiosink", 0,
"OSX Audio Sink");
+ gst_core_audio_init_debug ();
GST_DEBUG ("Adding static interface");
g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE,
&osxelement_info);
@@ -423,19 +422,22 @@ gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
osxsink = GST_OSX_AUDIO_SINK (sink);
if (!gst_osx_audio_sink_select_device (osxsink)) {
+ GST_ERROR_OBJECT (sink, "Could not select device");
return NULL;
}
- GST_DEBUG ("Creating ringbuffer");
+ GST_DEBUG_OBJECT (sink, "Creating ringbuffer");
ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL);
- GST_DEBUG ("osx sink %p element %p ioproc %p", osxsink,
+ GST_DEBUG_OBJECT (sink, "osx sink %p element %p ioproc %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->core_audio->element =
+ GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink);
+ ringbuffer->core_audio->device_id = osxsink->device_id;
+ ringbuffer->core_audio->is_src = FALSE;
return GST_RING_BUFFER (ringbuffer);
}
@@ -453,7 +455,7 @@ gst_osx_audio_sink_io_proc (GstOsxRingBuffer * buf,
guint8 *readptr;
gint readseg;
gint len;
- gint stream_idx = buf->stream_idx;
+ gint stream_idx = buf->core_audio->stream_idx;
gint remaining = bufferList->mBuffers[stream_idx].mDataByteSize;
gint offset = 0;
@@ -498,35 +500,13 @@ gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data)
static void
gst_osx_audio_sink_set_volume (GstOsxAudioSink * sink)
{
- if (!sink->audiounit)
- return;
+ GstOsxRingBuffer *osxbuf;
- AudioUnitSetParameter (sink->audiounit, kHALOutputParam_Volume,
- kAudioUnitScope_Global, 0, (float) sink->volume, 0);
-}
+ osxbuf = GST_OSX_RING_BUFFER (GST_BASE_AUDIO_SINK (sink)->ringbuffer);
+ if (!osxbuf)
+ return;
-static inline void
-_dump_channel_layout (AudioChannelLayout * channel_layout)
-{
- UInt32 i;
-
- GST_DEBUG ("mChannelLayoutTag: 0x%lx",
- (unsigned long) channel_layout->mChannelLayoutTag);
- GST_DEBUG ("mChannelBitmap: 0x%lx",
- (unsigned long) channel_layout->mChannelBitmap);
- GST_DEBUG ("mNumberChannelDescriptions: %lu",
- (unsigned long) channel_layout->mNumberChannelDescriptions);
- for (i = 0; i < channel_layout->mNumberChannelDescriptions; i++) {
- AudioChannelDescription *channel_desc =
- &channel_layout->mChannelDescriptions[i];
- GST_DEBUG (" mChannelLabel: 0x%lx mChannelFlags: 0x%lx "
- "mCoordinates[0]: %f mCoordinates[1]: %f "
- "mCoordinates[2]: %f",
- (unsigned long) channel_desc->mChannelLabel,
- (unsigned long) channel_desc->mChannelFlags,
- channel_desc->mCoordinates[0], channel_desc->mCoordinates[1],
- channel_desc->mCoordinates[2]);
- }
+ gst_core_audio_set_volume (osxbuf->core_audio, sink->volume);
}
static gboolean
@@ -552,14 +532,14 @@ gst_osx_audio_sink_allowed_caps (GstOsxAudioSink * osxsink)
};
/* First collect info about the HW capabilites and preferences */
- spdif_allowed = _audio_device_is_spdif_avail (osxsink->device_id);
- layout = _audio_device_get_channel_layout (osxsink->device_id);
+ spdif_allowed =
+ gst_core_audio_audio_device_is_spdif_avail (osxsink->device_id);
+ layout = gst_core_audio_audio_device_get_channel_layout (osxsink->device_id);
GST_DEBUG_OBJECT (osxsink, "Selected device ID: %u SPDIF allowed: %d",
(unsigned) osxsink->device_id, spdif_allowed);
if (layout) {
- _dump_channel_layout (layout);
max_channels = layout->mNumberChannelDescriptions;
} else {
GST_WARNING_OBJECT (osxsink, "This driver does not support "
@@ -654,71 +634,11 @@ gst_osx_audio_sink_allowed_caps (GstOsxAudioSink * osxsink)
static gboolean
gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink)
{
- AudioDeviceID *devices = NULL;
- AudioDeviceID default_device_id = 0;
- AudioChannelLayout *channel_layout;
- gint i, ndevices = 0;
gboolean res = FALSE;
- devices = _audio_system_get_devices (&ndevices);
-
- if (ndevices < 1) {
- GST_ERROR_OBJECT (osxsink, "no audio output devices found");
- goto done;
- }
-
- GST_DEBUG_OBJECT (osxsink, "found %d audio device(s)", ndevices);
-
- for (i = 0; i < ndevices; i++) {
- gchar *device_name;
-
- if ((device_name = _audio_device_get_name (devices[i]))) {
- if (!_audio_device_has_output (devices[i])) {
- GST_DEBUG_OBJECT (osxsink, "Input Device ID: %u Name: %s",
- (unsigned) devices[i], device_name);
- } else {
- GST_DEBUG_OBJECT (osxsink, "Output Device ID: %u Name: %s",
- (unsigned) devices[i], device_name);
-
- channel_layout = _audio_device_get_channel_layout (devices[i]);
- if (channel_layout) {
- _dump_channel_layout (channel_layout);
- g_free (channel_layout);
- }
- }
-
- g_free (device_name);
- }
- }
-
- /* Find the ID of the default output device */
- default_device_id = _audio_system_get_default_output ();
-
- /* Here we decide if selected device is valid or autoselect
- * the default one when required */
- if (osxsink->device_id == kAudioDeviceUnknown) {
- if (default_device_id != kAudioDeviceUnknown) {
- osxsink->device_id = default_device_id;
- res = TRUE;
- }
- } else {
- for (i = 0; i < ndevices; i++) {
- if (osxsink->device_id == devices[i]) {
- res = TRUE;
- }
- }
-
- if (res && !_audio_device_is_alive (osxsink->device_id)) {
- GST_ERROR_OBJECT (osxsink, "Requested device not usable");
- res = FALSE;
- goto done;
- }
- }
-
+ if (!gst_core_audio_select_device (&osxsink->device_id))
+ return FALSE;
res = gst_osx_audio_sink_allowed_caps (osxsink);
-done:
- g_free (devices);
-
return res;
}
diff --git a/sys/osxaudio/gstosxaudiosrc.c b/sys/osxaudio/gstosxaudiosrc.c
index 7e9ad245b..31e30800a 100644
--- a/sys/osxaudio/gstosxaudiosrc.c
+++ b/sys/osxaudio/gstosxaudiosrc.c
@@ -60,8 +60,6 @@
#endif
#include <gst/gst.h>
-#include <CoreAudio/CoreAudio.h>
-#include <CoreAudio/AudioHardware.h>
#include "gstosxaudiosrc.h"
#include "gstosxaudioelement.h"
@@ -265,9 +263,10 @@ gst_osx_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
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->core_audio->element =
+ GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsrc);
+ ringbuffer->core_audio->is_src = TRUE;
+ ringbuffer->core_audio->device_id = osxsrc->device_id;
return GST_RING_BUFFER (ringbuffer);
}
@@ -285,15 +284,15 @@ gst_osx_audio_src_io_proc (GstOsxRingBuffer * buf,
gint remaining;
gint offset = 0;
- status = AudioUnitRender (buf->audiounit, ioActionFlags, inTimeStamp,
- inBusNumber, inNumberFrames, buf->recBufferList);
+ status = AudioUnitRender (buf->core_audio->audiounit, ioActionFlags,
+ inTimeStamp, inBusNumber, inNumberFrames, buf->core_audio->recBufferList);
if (status) {
GST_WARNING_OBJECT (buf, "AudioUnitRender returned %d", (int) status);
return status;
}
- remaining = buf->recBufferList->mBuffers[0].mDataByteSize;
+ remaining = buf->core_audio->recBufferList->mBuffers[0].mDataByteSize;
while (remaining) {
if (!gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf),
@@ -306,7 +305,8 @@ gst_osx_audio_src_io_proc (GstOsxRingBuffer * buf,
len = remaining;
memcpy (writeptr + buf->segoffset,
- (char *) buf->recBufferList->mBuffers[0].mData + offset, len);
+ (char *) buf->core_audio->recBufferList->mBuffers[0].mData + offset,
+ len);
buf->segoffset += len;
offset += len;
@@ -333,30 +333,5 @@ gst_osx_audio_src_osxelement_init (gpointer g_iface, gpointer iface_data)
static void
gst_osx_audio_src_select_device (GstOsxAudioSrc * osxsrc)
{
- OSStatus status;
- 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) {
- GST_WARNING_OBJECT (osxsrc,
- "AudioHardwareGetProperty returned %d", (int) status);
- } else {
- GST_DEBUG_OBJECT (osxsrc, "AudioHardwareGetProperty returned 0");
- }
-
- 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);
- }
+ gst_core_audio_select_source_device (&osxsrc->device_id);
}
diff --git a/sys/osxaudio/gstosxcoreaudio.c b/sys/osxaudio/gstosxcoreaudio.c
new file mode 100644
index 000000000..aa08223c6
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudio.c
@@ -0,0 +1,218 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ * Authors: Josep Torra Vallès <josep@fluendo.com>
+ * Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "gstosxcoreaudio.h"
+#include "gstosxcoreaudiocommon.h"
+#include "gstosxaudiosrc.h"
+
+GST_DEBUG_CATEGORY_STATIC (osx_audio_debug);
+#define GST_CAT_DEFAULT osx_audio_debug
+
+G_DEFINE_TYPE (GstCoreAudio, gst_core_audio, G_TYPE_OBJECT);
+
+#include "gstosxcoreaudiohal.c"
+
+
+static void
+gst_core_audio_class_init (GstCoreAudioClass * klass)
+{
+}
+
+static void
+gst_core_audio_init (GstCoreAudio * core_audio)
+{
+ core_audio->is_passthrough = FALSE;
+ core_audio->device_id = kAudioDeviceUnknown;
+ core_audio->is_src = FALSE;
+ core_audio->audiounit = NULL;
+#ifndef HAVE_IOS
+ core_audio->hog_pid = -1;
+ core_audio->disabled_mixing = FALSE;
+#endif
+}
+
+/**************************
+ * Public API *
+ *************************/
+
+GstCoreAudio *
+gst_core_audio_new (GstObject * osxbuf)
+{
+ GstCoreAudio *core_audio;
+
+ core_audio = g_object_new (GST_TYPE_CORE_AUDIO, NULL);
+ core_audio->osxbuf = osxbuf;
+ return core_audio;
+}
+
+gboolean
+gst_core_audio_close (GstCoreAudio * core_audio)
+{
+ AudioComponentInstanceDispose (core_audio->audiounit);
+ core_audio->audiounit = NULL;
+ return TRUE;
+}
+
+gboolean
+gst_core_audio_open (GstCoreAudio * core_audio)
+{
+
+ if (!gst_core_audio_open_impl (core_audio))
+ return FALSE;
+
+ if (core_audio->is_src) {
+ AudioStreamBasicDescription asbd_in;
+ UInt32 propertySize;
+ OSStatus status;
+
+ GstOsxAudioSrc *src =
+ GST_OSX_AUDIO_SRC (GST_OBJECT_PARENT (core_audio->osxbuf));
+
+ propertySize = sizeof (asbd_in);
+ status = AudioUnitGetProperty (core_audio->audiounit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input, 1, &asbd_in, &propertySize);
+
+ if (status) {
+ AudioComponentInstanceDispose (core_audio->audiounit);
+ core_audio->audiounit = NULL;
+ GST_WARNING_OBJECT (core_audio,
+ "Unable to obtain device properties: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;
+ } else {
+ src->deviceChannels = asbd_in.mChannelsPerFrame;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+gst_core_audio_start_processing (GstCoreAudio * core_audio)
+{
+ return gst_core_audio_start_processing_impl (core_audio);
+}
+
+gboolean
+gst_core_audio_pause_processing (GstCoreAudio * core_audio)
+{
+ return gst_core_audio_pause_processing_impl (core_audio);
+}
+
+gboolean
+gst_core_audio_stop_processing (GstCoreAudio * core_audio)
+{
+ return gst_core_audio_stop_processing_impl (core_audio);
+}
+
+gboolean
+gst_core_audio_get_samples_and_latency (GstCoreAudio * core_audio,
+ gdouble rate, guint * samples, gdouble * latency)
+{
+ return gst_core_audio_get_samples_and_latency_impl (core_audio, rate,
+ samples, latency);
+}
+
+gboolean
+gst_core_audio_initialize (GstCoreAudio * core_audio,
+ AudioStreamBasicDescription format, GstCaps * caps, gboolean is_passthrough)
+{
+ guint32 frame_size;
+ OSStatus status;
+
+ GST_DEBUG_OBJECT (core_audio,
+ "Initializing: passthrough:%d caps:%" GST_PTR_FORMAT, is_passthrough,
+ caps);
+
+ if (!gst_core_audio_initialize_impl (core_audio, format, caps,
+ is_passthrough, &frame_size)) {
+ goto error;
+ }
+
+ if (core_audio->is_src) {
+ /* create AudioBufferList needed for recording */
+ core_audio->recBufferList =
+ buffer_list_alloc (format.mChannelsPerFrame,
+ frame_size * format.mBytesPerFrame);
+ }
+
+ /* Initialize the AudioUnit */
+ status = AudioUnitInitialize (core_audio->audiounit);
+ if (status) {
+ GST_ERROR_OBJECT (core_audio, "Failed to initialise AudioUnit: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ goto error;
+ }
+ return TRUE;
+
+error:
+ if (core_audio->is_src && core_audio->recBufferList) {
+ buffer_list_free (core_audio->recBufferList);
+ core_audio->recBufferList = NULL;
+ }
+ return FALSE;
+}
+
+void
+gst_core_audio_unitialize (GstCoreAudio * core_audio)
+{
+ AudioUnitUninitialize (core_audio->audiounit);
+
+ if (core_audio->recBufferList) {
+ buffer_list_free (core_audio->recBufferList);
+ core_audio->recBufferList = NULL;
+ }
+}
+
+void
+gst_core_audio_set_volume (GstCoreAudio * core_audio, gfloat volume)
+{
+ AudioUnitSetParameter (core_audio->audiounit, kHALOutputParam_Volume,
+ kAudioUnitScope_Global, 0, (float) volume, 0);
+}
+
+gboolean
+gst_core_audio_select_device (AudioDeviceID * device_id)
+{
+ return gst_core_audio_select_device_impl (device_id);
+}
+
+gboolean
+gst_core_audio_select_source_device (AudioDeviceID * device_id)
+{
+ return gst_core_audio_select_source_device_impl (device_id);
+}
+
+void
+gst_core_audio_init_debug (void)
+{
+ GST_DEBUG_CATEGORY_INIT (osx_audio_debug, "osxaudio", 0,
+ "OSX Audio Elements");
+}
+
+gboolean
+gst_core_audio_audio_device_is_spdif_avail (AudioDeviceID device_id)
+{
+ return gst_core_audio_audio_device_is_spdif_avail_impl (device_id);
+}
diff --git a/sys/osxaudio/gstosxcoreaudio.h b/sys/osxaudio/gstosxcoreaudio.h
index 8876115cf..71fcfa65c 100644
--- a/sys/osxaudio/gstosxcoreaudio.h
+++ b/sys/osxaudio/gstosxcoreaudio.h
@@ -2,29 +2,6 @@
* GStreamer
* Copyright (C) 2012 Fluendo S.A. <support@fluendo.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
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Alternatively, the contents of this file may be used under the
- * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
- * which case the following provisions apply instead of the ones
- * mentioned above:
- *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
@@ -40,567 +17,135 @@
* 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
- *
*/
+#ifndef __GST_CORE_AUDIO_H__
+#define __GST_CORE_AUDIO_H__
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gst/gst.h>
+#ifdef HAVE_IOS
+ #include <CoreAudio/CoreAudioTypes.h>
+ #define AudioDeviceID gint
+ #define kAudioDeviceUnknown 0
+#else
+ #include <CoreAudio/CoreAudio.h>
+ #include <AudioToolbox/AudioToolbox.h>
+ #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5
+ #include <CoreServices/CoreServices.h>
+ #define AudioComponentFindNext FindNextComponent
+ #define AudioComponentInstanceNew OpenAComponent
+ #define AudioComponentInstanceDispose CloseComponent
+ #define AudioComponent Component
+ #define AudioComponentDescription ComponentDescription
+ #endif
+#endif
+#include <AudioUnit/AudioUnit.h>
+#include "gstosxaudioelement.h"
+
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_CORE_AUDIO \
+ (gst_core_audio_get_type())
+#define GST_CORE_AUDIO(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CORE_AUDIO,GstCoreAudio))
+#define GST_CORE_AUDIO_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CORE_AUDIO,GstCoreAudioClass))
+#define GST_CORE_AUDIO_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_CORE_AUDIO,GstCoreAudioClass))
+#define GST_IS_CORE_AUDIO(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CORE_AUDIO))
+#define GST_IS_CORE_AUDIO_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CORE_AUDIO))
+
+#define CORE_AUDIO_FORMAT_IS_SPDIF(f) ((f).mFormat.mFormatID == 'IAC3' || (f).mFormat.mFormatID == 'iac3' || (f).mFormat.mFormatID == kAudioFormat60958AC3 || (f).mFormat.mFormatID == kAudioFormatAC3)
+
#define CORE_AUDIO_FORMAT "FormatID: %" GST_FOURCC_FORMAT " rate: %f flags: 0x%x BytesPerPacket: %u FramesPerPacket: %u BytesPerFrame: %u ChannelsPerFrame: %u BitsPerChannel: %u"
#define CORE_AUDIO_FORMAT_ARGS(f) GST_FOURCC_ARGS((f).mFormatID),(f).mSampleRate,(unsigned)(f).mFormatFlags,(unsigned)(f).mBytesPerPacket,(unsigned)(f).mFramesPerPacket,(unsigned)(f).mBytesPerFrame,(unsigned)(f).mChannelsPerFrame,(unsigned)(f).mBitsPerChannel
-#define CORE_AUDIO_FORMAT_IS_SPDIF(f) ((f).mFormat.mFormatID == 'IAC3' || (f).mFormat.mFormatID == 'iac3' || (f).mFormat.mFormatID == kAudioFormat60958AC3 || (f).mFormat.mFormatID == kAudioFormatAC3)
+typedef struct _GstCoreAudio GstCoreAudio;
+typedef struct _GstCoreAudioClass GstCoreAudioClass;
-static inline gboolean
-_audio_system_set_runloop (CFRunLoopRef runLoop)
-{
- OSStatus status = noErr;
-
- gboolean res = FALSE;
-
- AudioObjectPropertyAddress runloopAddress = {
- kAudioHardwarePropertyRunLoop,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectSetPropertyData (kAudioObjectSystemObject,
- &runloopAddress, 0, NULL, sizeof (CFRunLoopRef), &runLoop);
- if (status == noErr) {
- res = TRUE;
- } else {
- GST_ERROR ("failed to set runloop to %p: %" GST_FOURCC_FORMAT,
- runLoop, GST_FOURCC_ARGS (status));
- }
-
- return res;
-}
-
-static inline AudioDeviceID
-_audio_system_get_default_output (void)
+struct _GstCoreAudio
{
- OSStatus status = noErr;
- UInt32 propertySize = sizeof (AudioDeviceID);
- AudioDeviceID device_id = kAudioDeviceUnknown;
-
- AudioObjectPropertyAddress defaultDeviceAddress = {
- kAudioHardwarePropertyDefaultOutputDevice,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
- &defaultDeviceAddress, 0, NULL, &propertySize, &device_id);
- if (status != noErr) {
- GST_ERROR ("failed getting default output device: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- }
-
- return device_id;
-}
-
-static inline AudioDeviceID *
-_audio_system_get_devices (gint * ndevices)
-{
- OSStatus status = noErr;
- UInt32 propertySize = 0;
- AudioDeviceID *devices = NULL;
-
- AudioObjectPropertyAddress audioDevicesAddress = {
- kAudioHardwarePropertyDevices,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyDataSize (kAudioObjectSystemObject,
- &audioDevicesAddress, 0, NULL, &propertySize);
- if (status != noErr) {
- GST_WARNING ("failed getting number of devices: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return NULL;
- }
-
- *ndevices = propertySize / sizeof (AudioDeviceID);
-
- devices = (AudioDeviceID *) g_malloc (propertySize);
- if (devices) {
- status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
- &audioDevicesAddress, 0, NULL, &propertySize, devices);
- if (status != noErr) {
- GST_WARNING ("failed getting the list of devices: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- g_free (devices);
- *ndevices = 0;
- return NULL;
- }
- }
- return devices;
-}
-
-static inline gboolean
-_audio_device_is_alive (AudioDeviceID device_id)
-{
- OSStatus status = noErr;
- int alive = FALSE;
- UInt32 propertySize = sizeof (alive);
-
- AudioObjectPropertyAddress audioDeviceAliveAddress = {
- kAudioDevicePropertyDeviceIsAlive,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyData (device_id,
- &audioDeviceAliveAddress, 0, NULL, &propertySize, &alive);
- if (status != noErr) {
- alive = FALSE;
- }
-
- return alive;
-}
-
-static inline guint
-_audio_device_get_latency (AudioDeviceID device_id)
-{
- OSStatus status = noErr;
- UInt32 latency = 0;
- UInt32 propertySize = sizeof (latency);
-
- AudioObjectPropertyAddress audioDeviceLatencyAddress = {
- kAudioDevicePropertyLatency,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyData (device_id,
- &audioDeviceLatencyAddress, 0, NULL, &propertySize, &latency);
- if (status != noErr) {
- GST_ERROR ("failed to get latency: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- latency = -1;
- }
-
- return latency;
-}
-
-static inline pid_t
-_audio_device_get_hog (AudioDeviceID device_id)
-{
- OSStatus status = noErr;
+ GObject object;
+
+ GstObject *osxbuf;
+ GstOsxAudioElementInterface *element;
+
+ gboolean is_src;
+ gboolean is_passthrough;
+ AudioDeviceID device_id;
+ AudioStreamBasicDescription stream_format;
+ gint stream_idx;
+ gboolean io_proc_active;
+ gboolean io_proc_needs_deactivation;
+
+ /* For LPCM in/out */
+ AudioUnit audiounit;
+ AudioBufferList *recBufferList;
+
+#ifndef HAVE_IOS
+ /* For SPDIF out */
pid_t hog_pid;
- UInt32 propertySize = sizeof (hog_pid);
-
- AudioObjectPropertyAddress audioDeviceHogModeAddress = {
- kAudioDevicePropertyHogMode,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyData (device_id,
- &audioDeviceHogModeAddress, 0, NULL, &propertySize, &hog_pid);
- if (status != noErr) {
- GST_ERROR ("failed to get hog: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- hog_pid = -1;
- }
-
- return hog_pid;
-}
-
-static inline gboolean
-_audio_device_set_hog (AudioDeviceID device_id, pid_t hog_pid)
-{
- OSStatus status = noErr;
- UInt32 propertySize = sizeof (hog_pid);
- gboolean res = FALSE;
-
- AudioObjectPropertyAddress audioDeviceHogModeAddress = {
- kAudioDevicePropertyHogMode,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectSetPropertyData (device_id,
- &audioDeviceHogModeAddress, 0, NULL, propertySize, &hog_pid);
-
- if (status == noErr) {
- res = TRUE;
- } else {
- GST_ERROR ("failed to set hog: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
-
- return res;
-}
-
-static inline gboolean
-_audio_device_set_mixing (AudioDeviceID device_id, gboolean enable_mix)
-{
- OSStatus status = noErr;
- UInt32 propertySize = 0, can_mix = enable_mix;
- Boolean writable = FALSE;
- gboolean res = FALSE;
-
- AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = {
- kAudioDevicePropertySupportsMixing,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- if (AudioObjectHasProperty (device_id, &audioDeviceSupportsMixingAddress)) {
- /* Set mixable to false if we are allowed to */
- status = AudioObjectIsPropertySettable (device_id,
- &audioDeviceSupportsMixingAddress, &writable);
- if (status) {
- GST_DEBUG ("AudioObjectIsPropertySettable: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
- status = AudioObjectGetPropertyDataSize (device_id,
- &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize);
- if (status) {
- GST_DEBUG ("AudioObjectGetPropertyDataSize: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
- status = AudioObjectGetPropertyData (device_id,
- &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize, &can_mix);
- if (status) {
- GST_DEBUG ("AudioObjectGetPropertyData: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
-
- if (status == noErr && writable) {
- can_mix = enable_mix;
- status = AudioObjectSetPropertyData (device_id,
- &audioDeviceSupportsMixingAddress, 0, NULL, propertySize, &can_mix);
- res = TRUE;
- }
-
- if (status != noErr) {
- GST_ERROR ("failed to set mixmode: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
- } else {
- GST_DEBUG ("property not found, mixing coudln't be changed");
- }
-
- return res;
-}
-
-static inline gchar *
-_audio_device_get_name (AudioDeviceID device_id)
-{
- OSStatus status = noErr;
- UInt32 propertySize = 0;
- gchar *device_name = NULL;
-
- AudioObjectPropertyAddress deviceNameAddress = {
- kAudioDevicePropertyDeviceName,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- /* Get the length of the device name */
- status = AudioObjectGetPropertyDataSize (device_id,
- &deviceNameAddress, 0, NULL, &propertySize);
- if (status != noErr) {
- goto beach;
- }
-
- /* Get the name of the device */
- device_name = (gchar *) g_malloc (propertySize);
- status = AudioObjectGetPropertyData (device_id,
- &deviceNameAddress, 0, NULL, &propertySize, device_name);
- if (status != noErr) {
- g_free (device_name);
- device_name = NULL;
- }
-
-beach:
- return device_name;
-}
-
-static inline gboolean
-_audio_device_has_output (AudioDeviceID device_id)
-{
- OSStatus status = noErr;
- UInt32 propertySize;
-
- AudioObjectPropertyAddress streamsAddress = {
- kAudioDevicePropertyStreams,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyDataSize (device_id,
- &streamsAddress, 0, NULL, &propertySize);
- if (status != noErr) {
- return FALSE;
- }
- if (propertySize == 0) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-static inline AudioChannelLayout *
-_audio_device_get_channel_layout (AudioDeviceID device_id)
-{
- OSStatus status = noErr;
- UInt32 propertySize = 0;
- AudioChannelLayout *layout = NULL;
-
- AudioObjectPropertyAddress channelLayoutAddress = {
- kAudioDevicePropertyPreferredChannelLayout,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- /* Get the length of the default channel layout structure */
- status = AudioObjectGetPropertyDataSize (device_id,
- &channelLayoutAddress, 0, NULL, &propertySize);
- if (status != noErr) {
- GST_ERROR ("failed to get prefered layout: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- goto beach;
- }
-
- /* Get the default channel layout of the device */
- layout = (AudioChannelLayout *) g_malloc (propertySize);
- status = AudioObjectGetPropertyData (device_id,
- &channelLayoutAddress, 0, NULL, &propertySize, layout);
- if (status != noErr) {
- GST_ERROR ("failed to get prefered layout: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- goto failed;
- }
-
- if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
- /* bitmap defined channellayout */
- status =
- AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForBitmap,
- sizeof (UInt32), &layout->mChannelBitmap, &propertySize, layout);
- if (status != noErr) {
- GST_ERROR ("failed to get layout for bitmap: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- goto failed;
- }
- } else if (layout->mChannelLayoutTag !=
- kAudioChannelLayoutTag_UseChannelDescriptions) {
- /* layouttags defined channellayout */
- status = AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForTag,
- sizeof(AudioChannelLayoutTag), &layout->mChannelLayoutTag,
- &propertySize, layout);
- if (status != noErr) {
- GST_ERROR ("failed to get layout for tag: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- goto failed;
- }
- }
-
-beach:
- return layout;
-
-failed:
- g_free (layout);
- return NULL;
-}
-
-static inline AudioStreamID *
-_audio_device_get_streams (AudioDeviceID device_id, gint * nstreams)
-{
- OSStatus status = noErr;
- UInt32 propertySize = 0;
- AudioStreamID *streams = NULL;
-
- AudioObjectPropertyAddress streamsAddress = {
- kAudioDevicePropertyStreams,
- kAudioDevicePropertyScopeOutput,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyDataSize (device_id,
- &streamsAddress, 0, NULL, &propertySize);
- if (status != noErr) {
- GST_WARNING ("failed getting number of streams: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return NULL;
- }
-
- *nstreams = propertySize / sizeof (AudioStreamID);
- streams = (AudioStreamID *) g_malloc (propertySize);
-
- if (streams) {
- status = AudioObjectGetPropertyData (device_id,
- &streamsAddress, 0, NULL, &propertySize, streams);
- if (status != noErr) {
- GST_WARNING ("failed getting the list of streams: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- g_free (streams);
- *nstreams = 0;
- return NULL;
- }
- }
-
- return streams;
-}
-
-static inline guint
-_audio_stream_get_latency (AudioStreamID stream_id)
-{
- OSStatus status = noErr;
- UInt32 latency;
- UInt32 propertySize = sizeof (latency);
-
- AudioObjectPropertyAddress latencyAddress = {
- kAudioStreamPropertyLatency,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyData (stream_id,
- &latencyAddress, 0, NULL, &propertySize, &latency);
- if (status != noErr) {
- GST_ERROR ("failed to get latency: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- latency = -1;
- }
-
- return latency;
-}
-
-static inline gboolean
-_audio_stream_get_current_format (AudioStreamID stream_id,
- AudioStreamBasicDescription * format)
-{
- OSStatus status = noErr;
- UInt32 propertySize = sizeof (AudioStreamBasicDescription);
-
- AudioObjectPropertyAddress formatAddress = {
- kAudioStreamPropertyPhysicalFormat,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyData (stream_id,
- &formatAddress, 0, NULL, &propertySize, format);
- if (status != noErr) {
- GST_ERROR ("failed to get current format: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static inline gboolean
-_audio_stream_set_current_format (AudioStreamID stream_id,
- AudioStreamBasicDescription format)
-{
- OSStatus status = noErr;
- UInt32 propertySize = sizeof (AudioStreamBasicDescription);
-
- AudioObjectPropertyAddress formatAddress = {
- kAudioStreamPropertyPhysicalFormat,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectSetPropertyData (stream_id,
- &formatAddress, 0, NULL, propertySize, &format);
- if (status != noErr) {
- GST_ERROR ("failed to set current format: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static inline AudioStreamRangedDescription *
-_audio_stream_get_formats (AudioStreamID stream_id, gint * nformats)
-{
- OSStatus status = noErr;
- UInt32 propertySize = 0;
- AudioStreamRangedDescription *formats = NULL;
-
- AudioObjectPropertyAddress formatsAddress = {
- kAudioStreamPropertyAvailablePhysicalFormats,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- status = AudioObjectGetPropertyDataSize (stream_id,
- &formatsAddress, 0, NULL, &propertySize);
- if (status != noErr) {
- GST_WARNING ("failed getting number of stream formats: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return NULL;
- }
-
- *nformats = propertySize / sizeof (AudioStreamRangedDescription);
-
- formats = (AudioStreamRangedDescription *) g_malloc (propertySize);
- if (formats) {
- status = AudioObjectGetPropertyData (stream_id,
- &formatsAddress, 0, NULL, &propertySize, formats);
- if (status != noErr) {
- GST_WARNING ("failed getting the list of stream formats: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- g_free (formats);
- *nformats = 0;
- return NULL;
- }
- }
- return formats;
-}
-
-static inline gboolean
-_audio_stream_is_spdif_avail (AudioStreamID stream_id)
+ gboolean disabled_mixing;
+ AudioStreamID stream_id;
+ gboolean revert_format;
+ AudioStreamBasicDescription original_format;
+ AudioDeviceIOProcID procID;
+#endif
+};
+
+struct _GstCoreAudioClass
{
- AudioStreamRangedDescription *formats;
- gint i, nformats = 0;
- gboolean res = FALSE;
+ GObjectClass parent_class;
+};
- formats = _audio_stream_get_formats (stream_id, &nformats);
- GST_DEBUG ("found %d stream formats", nformats);
+GType gst_core_audio_get_type (void);
- if (formats) {
- GST_DEBUG ("formats supported on stream ID: %u",
- (unsigned) stream_id);
+void gst_core_audio_init_debug (void);
- for (i = 0; i < nformats; i++) {
- GST_DEBUG (" " CORE_AUDIO_FORMAT,
- CORE_AUDIO_FORMAT_ARGS (formats[i].mFormat));
+GstCoreAudio * gst_core_audio_new (GstObject *osxbuf);
- if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[i])) {
- res = TRUE;
- }
- }
- g_free (formats);
- }
+gboolean gst_core_audio_open (GstCoreAudio *core_audio);
- return res;
-}
+gboolean gst_core_audio_close (GstCoreAudio *core_audio);
-static inline gboolean
-_audio_device_is_spdif_avail (AudioDeviceID device_id)
-{
- AudioStreamID *streams = NULL;
- gint i, nstreams = 0;
- gboolean res = FALSE;
+gboolean gst_core_audio_initialize (GstCoreAudio *core_audio,
+ AudioStreamBasicDescription format,
+ GstCaps *caps,
+ gboolean is_passthrough);
+
+void gst_core_audio_unitialize (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_start_processing (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_pause_processing (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_stop_processing (GstCoreAudio *core_audio);
+
+gboolean gst_core_audio_get_samples_and_latency (GstCoreAudio * core_audio,
+ gdouble rate,
+ guint *samples,
+ gdouble *latency);
+
+void gst_core_audio_set_volume (GstCoreAudio *core_audio,
+ gfloat volume);
+
+gboolean gst_core_audio_audio_device_is_spdif_avail (AudioDeviceID device_id);
+
+
+gboolean gst_core_audio_select_device (AudioDeviceID *device_id);
+
+gboolean gst_core_audio_select_source_device (AudioDeviceID *device_id);
- streams = _audio_device_get_streams (device_id, &nstreams);
- GST_DEBUG ("found %d streams", nstreams);
- if (streams) {
- for (i = 0; i < nstreams; i++) {
- if (_audio_stream_is_spdif_avail (streams[i])) {
- res = TRUE;
- }
- }
+AudioChannelLayout * gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id);
- g_free (streams);
- }
- return res;
-}
+G_END_DECLS
+#endif /* __GST_CORE_AUDIO_H__ */
diff --git a/sys/osxaudio/gstosxcoreaudiocommon.c b/sys/osxaudio/gstosxcoreaudiocommon.c
new file mode 100644
index 000000000..5200b2ea1
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudiocommon.c
@@ -0,0 +1,431 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ * Authors: Josep Torra Vallès <josep@fluendo.com>
+ * Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "gstosxcoreaudiocommon.h"
+
+void
+gst_core_audio_remove_render_callback (GstCoreAudio * core_audio)
+{
+ AURenderCallbackStruct input;
+ OSStatus status;
+
+ /* Deactivate the render callback by calling SetRenderCallback
+ * with a NULL inputProc.
+ */
+ input.inputProc = NULL;
+ input.inputProcRefCon = NULL;
+
+ status = AudioUnitSetProperty (core_audio->audiounit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, /* N/A for global */
+ &input, sizeof (input));
+
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to remove render callback %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ }
+
+ /* Remove the RenderNotify too */
+ status = AudioUnitRemoveRenderNotify (core_audio->audiounit,
+ (AURenderCallback) gst_core_audio_render_notify, core_audio);
+
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf,
+ "Failed to remove render notify callback %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+
+ /* We're deactivated.. */
+ core_audio->io_proc_needs_deactivation = FALSE;
+ core_audio->io_proc_active = FALSE;
+}
+
+OSStatus
+gst_core_audio_render_notify (GstCoreAudio * core_audio,
+ 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 (core_audio->io_proc_needs_deactivation) {
+ gst_core_audio_remove_render_callback (core_audio);
+ }
+ }
+
+ return noErr;
+}
+
+gboolean
+gst_core_audio_io_proc_start (GstCoreAudio * core_audio)
+{
+ OSStatus status;
+ AURenderCallbackStruct input;
+ AudioUnitPropertyID callback_type;
+
+ GST_DEBUG_OBJECT (core_audio->osxbuf,
+ "osx ring buffer start ioproc: %p device_id %lu",
+ core_audio->element->io_proc, (gulong) core_audio->device_id);
+ if (!core_audio->io_proc_active) {
+ callback_type = core_audio->is_src ?
+ kAudioOutputUnitProperty_SetInputCallback :
+ kAudioUnitProperty_SetRenderCallback;
+
+ input.inputProc = (AURenderCallback) core_audio->element->io_proc;
+ input.inputProcRefCon = core_audio->osxbuf;
+
+ status = AudioUnitSetProperty (core_audio->audiounit, callback_type, kAudioUnitScope_Global, 0, /* N/A for global */
+ &input, sizeof (input));
+
+ if (status) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioUnitSetProperty failed: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ // ### does it make sense to do this notify stuff for input mode?
+ status = AudioUnitAddRenderNotify (core_audio->audiounit,
+ (AURenderCallback) gst_core_audio_render_notify, core_audio);
+
+ if (status) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioUnitAddRenderNotify failed %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ core_audio->io_proc_active = TRUE;
+ }
+
+ core_audio->io_proc_needs_deactivation = FALSE;
+
+ status = AudioOutputUnitStart (core_audio->audiounit);
+ if (status) {
+ GST_ERROR_OBJECT (core_audio->osxbuf, "AudioOutputUnitStart failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+gboolean
+gst_core_audio_io_proc_stop (GstCoreAudio * core_audio)
+{
+ OSErr status;
+
+ GST_DEBUG_OBJECT (core_audio->osxbuf,
+ "osx ring buffer stop ioproc: %p device_id %lu",
+ core_audio->element->io_proc, (gulong) core_audio->device_id);
+
+ status = AudioOutputUnitStop (core_audio->audiounit);
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf,
+ "AudioOutputUnitStop failed: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+ // ###: why is it okay to directly remove from here but not from pause() ?
+ if (core_audio->io_proc_active) {
+ gst_core_audio_remove_render_callback (core_audio);
+ }
+ return TRUE;
+}
+
+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;
+}
+
+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);
+}
+
+gboolean
+gst_core_audio_bind_device (GstCoreAudio * core_audio)
+{
+ OSStatus status;
+
+ /* Specify which device we're using. */
+ GST_DEBUG_OBJECT (core_audio->osxbuf, "Bind AudioUnit to device %d",
+ (int) core_audio->device_id);
+ status = AudioUnitSetProperty (core_audio->audiounit,
+ kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0,
+ &core_audio->device_id, sizeof (AudioDeviceID));
+ if (status) {
+ GST_ERROR_OBJECT (core_audio->osxbuf, "Failed binding to device: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ goto audiounit_error;
+ }
+ return TRUE;
+
+audiounit_error:
+ if (core_audio->recBufferList) {
+ buffer_list_free (core_audio->recBufferList);
+ core_audio->recBufferList = NULL;
+ }
+ return FALSE;
+}
+
+gboolean
+gst_core_audio_set_channels_layout (GstCoreAudio * core_audio,
+ gint channels, GstCaps * caps)
+{
+ /* Configure the output stream and allocate ringbuffer memory */
+ AudioChannelLayout *layout = NULL;
+ OSStatus status;
+ int layoutSize, element, i;
+ AudioUnitScope scope;
+ GstStructure *structure;
+ GstAudioChannelPosition *positions;
+
+ /* Describe channels */
+ layoutSize = sizeof (AudioChannelLayout) +
+ channels * sizeof (AudioChannelDescription);
+ layout = g_malloc (layoutSize);
+
+ structure = gst_caps_get_structure (caps, 0);
+ positions = gst_audio_get_channel_positions (structure);
+
+ layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
+ layout->mChannelBitmap = 0; /* Not used */
+ layout->mNumberChannelDescriptions = channels;
+ for (i = 0; i < 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;
+ }
+
+ scope = core_audio->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input;
+ element = core_audio->is_src ? 1 : 0;
+
+ if (layoutSize) {
+ status = AudioUnitSetProperty (core_audio->audiounit,
+ kAudioUnitProperty_AudioChannelLayout,
+ scope, element, layout, layoutSize);
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf,
+ "Failed to set output channel layout: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ }
+
+ g_free (layout);
+ return TRUE;
+}
+
+gboolean
+gst_core_audio_set_format (GstCoreAudio * core_audio,
+ AudioStreamBasicDescription format)
+{
+ /* Configure the output stream and allocate ringbuffer memory */
+ OSStatus status;
+ UInt32 propertySize;
+ int element;
+ AudioUnitScope scope;
+
+ GST_DEBUG_OBJECT (core_audio->osxbuf, "Setting format for AudioUnit");
+
+ scope = core_audio->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input;
+ element = core_audio->is_src ? 1 : 0;
+
+ propertySize = sizeof (AudioStreamBasicDescription);
+ status = AudioUnitSetProperty (core_audio->audiounit,
+ kAudioUnitProperty_StreamFormat, scope, element, &format, propertySize);
+
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf,
+ "Failed to set audio description: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;;
+ }
+
+ return TRUE;
+}
+
+gboolean
+gst_core_audio_open_device (GstCoreAudio * core_audio, OSType sub_type,
+ const gchar * adesc)
+{
+ AudioComponentDescription desc;
+ AudioComponent comp;
+ OSStatus status;
+ AudioUnit unit;
+ UInt32 enableIO;
+
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = sub_type;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+
+ comp = AudioComponentFindNext (NULL, &desc);
+
+ if (comp == NULL) {
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Couldn't find %s component",
+ adesc);
+ return FALSE;
+ }
+
+ status = AudioComponentInstanceNew (comp, &unit);
+
+ if (status) {
+ GST_ERROR_OBJECT (core_audio->osxbuf, "Couldn't open %s component %"
+ GST_FOURCC_FORMAT, adesc, GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+
+ if (core_audio->is_src) {
+ /* enable input */
+ enableIO = 1;
+ status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, /* 1 = input element */
+ &enableIO, sizeof (enableIO));
+
+ if (status) {
+ AudioComponentInstanceDispose (unit);
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to enable input: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+
+ /* disable output */
+ enableIO = 0;
+ status = AudioUnitSetProperty (unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, /* 0 = output element */
+ &enableIO, sizeof (enableIO));
+
+ if (status) {
+ AudioComponentInstanceDispose (unit);
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to disable output: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ }
+
+ GST_DEBUG_OBJECT (core_audio->osxbuf, "Created %s AudioUnit: %p", adesc,
+ unit);
+ core_audio->audiounit = unit;
+ return TRUE;
+}
+
+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;
+ }
+}
+
+void
+gst_core_audio_dump_channel_layout (AudioChannelLayout * channel_layout)
+{
+ UInt32 i;
+
+ GST_DEBUG ("mChannelLayoutTag: 0x%lx",
+ (unsigned long) channel_layout->mChannelLayoutTag);
+ GST_DEBUG ("mChannelBitmap: 0x%lx",
+ (unsigned long) channel_layout->mChannelBitmap);
+ GST_DEBUG ("mNumberChannelDescriptions: %lu",
+ (unsigned long) channel_layout->mNumberChannelDescriptions);
+ for (i = 0; i < channel_layout->mNumberChannelDescriptions; i++) {
+ AudioChannelDescription *channel_desc =
+ &channel_layout->mChannelDescriptions[i];
+ GST_DEBUG (" mChannelLabel: 0x%lx mChannelFlags: 0x%lx "
+ "mCoordinates[0]: %f mCoordinates[1]: %f "
+ "mCoordinates[2]: %f",
+ (unsigned long) channel_desc->mChannelLabel,
+ (unsigned long) channel_desc->mChannelFlags,
+ channel_desc->mCoordinates[0], channel_desc->mCoordinates[1],
+ channel_desc->mCoordinates[2]);
+ }
+}
diff --git a/sys/osxaudio/gstosxcoreaudiocommon.h b/sys/osxaudio/gstosxcoreaudiocommon.h
new file mode 100644
index 000000000..f644757e4
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudiocommon.h
@@ -0,0 +1,65 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ * Authors: Josep Torra Vallès <josep@fluendo.com>
+ * Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <gst/audio/multichannel.h>
+#include "gstosxcoreaudio.h"
+
+typedef struct
+{
+ GMutex *lock;
+ GCond *cond;
+} PropertyMutex;
+
+gboolean gst_core_audio_bind_device (GstCoreAudio *core_audio);
+
+void gst_core_audio_dump_channel_layout (AudioChannelLayout * channel_layout);
+
+void gst_core_audio_remove_render_callback (GstCoreAudio * core_audio);
+
+gboolean gst_core_audio_io_proc_start (GstCoreAudio * core_audio);
+
+gboolean gst_core_audio_io_proc_stop (GstCoreAudio * core_audio);
+
+AudioBufferList * buffer_list_alloc (int channels, int size);
+
+void buffer_list_free (AudioBufferList * list);
+
+gboolean gst_core_audio_set_format (GstCoreAudio * core_audio,
+ AudioStreamBasicDescription format);
+
+gboolean gst_core_audio_set_channels_layout (GstCoreAudio * core_audio,
+ gint channels, GstCaps * caps);
+
+gboolean gst_core_audio_open_device (GstCoreAudio *core_audio,
+ OSType sub_type,
+ const gchar *adesc);
+
+OSStatus gst_core_audio_render_notify (GstCoreAudio * core_audio,
+ AudioUnitRenderActionFlags * ioActionFlags,
+ const AudioTimeStamp * inTimeStamp,
+ unsigned int inBusNumber,
+ unsigned int inNumberFrames,
+ AudioBufferList * ioData);
+
+AudioChannelLabel gst_audio_channel_position_to_coreaudio_channel_label (GstAudioChannelPosition position, int channel);
+
diff --git a/sys/osxaudio/gstosxcoreaudiohal.c b/sys/osxaudio/gstosxcoreaudiohal.c
new file mode 100644
index 000000000..e018c03c9
--- /dev/null
+++ b/sys/osxaudio/gstosxcoreaudiohal.c
@@ -0,0 +1,1281 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012-2013 Fluendo S.A. <support@fluendo.com>
+ * Authors: Josep Torra Vallès <josep@fluendo.com>
+ * Andoni Morales Alastruey <amorales@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "gstosxaudiosink.h"
+
+static inline gboolean
+_audio_system_set_runloop (CFRunLoopRef runLoop)
+{
+ OSStatus status = noErr;
+
+ gboolean res = FALSE;
+
+ AudioObjectPropertyAddress runloopAddress = {
+ kAudioHardwarePropertyRunLoop,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectSetPropertyData (kAudioObjectSystemObject,
+ &runloopAddress, 0, NULL, sizeof (CFRunLoopRef), &runLoop);
+ if (status == noErr) {
+ res = TRUE;
+ } else {
+ GST_ERROR ("failed to set runloop to %p: %" GST_FOURCC_FORMAT,
+ runLoop, GST_FOURCC_ARGS (status));
+ }
+
+ return res;
+}
+
+static inline AudioDeviceID
+_audio_system_get_default_output (void)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = sizeof (AudioDeviceID);
+ AudioDeviceID device_id = kAudioDeviceUnknown;
+
+ AudioObjectPropertyAddress defaultDeviceAddress = {
+ kAudioHardwarePropertyDefaultOutputDevice,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
+ &defaultDeviceAddress, 0, NULL, &propertySize, &device_id);
+ if (status != noErr) {
+ GST_ERROR ("failed getting default output device: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ }
+
+ return device_id;
+}
+
+static inline AudioDeviceID *
+_audio_system_get_devices (gint * ndevices)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = 0;
+ AudioDeviceID *devices = NULL;
+
+ AudioObjectPropertyAddress audioDevicesAddress = {
+ kAudioHardwarePropertyDevices,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyDataSize (kAudioObjectSystemObject,
+ &audioDevicesAddress, 0, NULL, &propertySize);
+ if (status != noErr) {
+ GST_WARNING ("failed getting number of devices: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return NULL;
+ }
+
+ *ndevices = propertySize / sizeof (AudioDeviceID);
+
+ devices = (AudioDeviceID *) g_malloc (propertySize);
+ if (devices) {
+ status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
+ &audioDevicesAddress, 0, NULL, &propertySize, devices);
+ if (status != noErr) {
+ GST_WARNING ("failed getting the list of devices: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ g_free (devices);
+ *ndevices = 0;
+ return NULL;
+ }
+ }
+ return devices;
+}
+
+static inline gboolean
+_audio_device_is_alive (AudioDeviceID device_id)
+{
+ OSStatus status = noErr;
+ int alive = FALSE;
+ UInt32 propertySize = sizeof (alive);
+
+ AudioObjectPropertyAddress audioDeviceAliveAddress = {
+ kAudioDevicePropertyDeviceIsAlive,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyData (device_id,
+ &audioDeviceAliveAddress, 0, NULL, &propertySize, &alive);
+ if (status != noErr) {
+ alive = FALSE;
+ }
+
+ return alive;
+}
+
+static inline guint
+_audio_device_get_latency (AudioDeviceID device_id)
+{
+ OSStatus status = noErr;
+ UInt32 latency = 0;
+ UInt32 propertySize = sizeof (latency);
+
+ AudioObjectPropertyAddress audioDeviceLatencyAddress = {
+ kAudioDevicePropertyLatency,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyData (device_id,
+ &audioDeviceLatencyAddress, 0, NULL, &propertySize, &latency);
+ if (status != noErr) {
+ GST_ERROR ("failed to get latency: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ latency = -1;
+ }
+
+ return latency;
+}
+
+static inline pid_t
+_audio_device_get_hog (AudioDeviceID device_id)
+{
+ OSStatus status = noErr;
+ pid_t hog_pid;
+ UInt32 propertySize = sizeof (hog_pid);
+
+ AudioObjectPropertyAddress audioDeviceHogModeAddress = {
+ kAudioDevicePropertyHogMode,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyData (device_id,
+ &audioDeviceHogModeAddress, 0, NULL, &propertySize, &hog_pid);
+ if (status != noErr) {
+ GST_ERROR ("failed to get hog: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ hog_pid = -1;
+ }
+
+ return hog_pid;
+}
+
+static inline gboolean
+_audio_device_set_hog (AudioDeviceID device_id, pid_t hog_pid)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = sizeof (hog_pid);
+ gboolean res = FALSE;
+
+ AudioObjectPropertyAddress audioDeviceHogModeAddress = {
+ kAudioDevicePropertyHogMode,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectSetPropertyData (device_id,
+ &audioDeviceHogModeAddress, 0, NULL, propertySize, &hog_pid);
+
+ if (status == noErr) {
+ res = TRUE;
+ } else {
+ GST_ERROR ("failed to set hog: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+
+ return res;
+}
+
+static inline gboolean
+_audio_device_set_mixing (AudioDeviceID device_id, gboolean enable_mix)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = 0, can_mix = enable_mix;
+ Boolean writable = FALSE;
+ gboolean res = FALSE;
+
+ AudioObjectPropertyAddress audioDeviceSupportsMixingAddress = {
+ kAudioDevicePropertySupportsMixing,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ if (AudioObjectHasProperty (device_id, &audioDeviceSupportsMixingAddress)) {
+ /* Set mixable to false if we are allowed to */
+ status = AudioObjectIsPropertySettable (device_id,
+ &audioDeviceSupportsMixingAddress, &writable);
+ if (status) {
+ GST_DEBUG ("AudioObjectIsPropertySettable: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+ status = AudioObjectGetPropertyDataSize (device_id,
+ &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize);
+ if (status) {
+ GST_DEBUG ("AudioObjectGetPropertyDataSize: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+ status = AudioObjectGetPropertyData (device_id,
+ &audioDeviceSupportsMixingAddress, 0, NULL, &propertySize, &can_mix);
+ if (status) {
+ GST_DEBUG ("AudioObjectGetPropertyData: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+
+ if (status == noErr && writable) {
+ can_mix = enable_mix;
+ status = AudioObjectSetPropertyData (device_id,
+ &audioDeviceSupportsMixingAddress, 0, NULL, propertySize, &can_mix);
+ res = TRUE;
+ }
+
+ if (status != noErr) {
+ GST_ERROR ("failed to set mixmode: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+ } else {
+ GST_DEBUG ("property not found, mixing coudln't be changed");
+ }
+
+ return res;
+}
+
+static inline gchar *
+_audio_device_get_name (AudioDeviceID device_id)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = 0;
+ gchar *device_name = NULL;
+
+ AudioObjectPropertyAddress deviceNameAddress = {
+ kAudioDevicePropertyDeviceName,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ /* Get the length of the device name */
+ status = AudioObjectGetPropertyDataSize (device_id,
+ &deviceNameAddress, 0, NULL, &propertySize);
+ if (status != noErr) {
+ goto beach;
+ }
+
+ /* Get the name of the device */
+ device_name = (gchar *) g_malloc (propertySize);
+ status = AudioObjectGetPropertyData (device_id,
+ &deviceNameAddress, 0, NULL, &propertySize, device_name);
+ if (status != noErr) {
+ g_free (device_name);
+ device_name = NULL;
+ }
+
+beach:
+ return device_name;
+}
+
+static inline gboolean
+_audio_device_has_output (AudioDeviceID device_id)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize;
+
+ AudioObjectPropertyAddress streamsAddress = {
+ kAudioDevicePropertyStreams,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyDataSize (device_id,
+ &streamsAddress, 0, NULL, &propertySize);
+ if (status != noErr) {
+ return FALSE;
+ }
+ if (propertySize == 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+AudioChannelLayout *
+gst_core_audio_audio_device_get_channel_layout (AudioDeviceID device_id)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = 0;
+ AudioChannelLayout *layout = NULL;
+
+ AudioObjectPropertyAddress channelLayoutAddress = {
+ kAudioDevicePropertyPreferredChannelLayout,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ /* Get the length of the default channel layout structure */
+ status = AudioObjectGetPropertyDataSize (device_id,
+ &channelLayoutAddress, 0, NULL, &propertySize);
+ if (status != noErr) {
+ GST_ERROR ("failed to get prefered layout: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ goto beach;
+ }
+
+ /* Get the default channel layout of the device */
+ layout = (AudioChannelLayout *) g_malloc (propertySize);
+ status = AudioObjectGetPropertyData (device_id,
+ &channelLayoutAddress, 0, NULL, &propertySize, layout);
+ if (status != noErr) {
+ GST_ERROR ("failed to get prefered layout: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ goto failed;
+ }
+
+ if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelBitmap) {
+ /* bitmap defined channellayout */
+ status =
+ AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForBitmap,
+ sizeof (UInt32), &layout->mChannelBitmap, &propertySize, layout);
+ if (status != noErr) {
+ GST_ERROR ("failed to get layout for bitmap: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ goto failed;
+ }
+ } else if (layout->mChannelLayoutTag !=
+ kAudioChannelLayoutTag_UseChannelDescriptions) {
+ /* layouttags defined channellayout */
+ status = AudioFormatGetProperty (kAudioFormatProperty_ChannelLayoutForTag,
+ sizeof (AudioChannelLayoutTag), &layout->mChannelLayoutTag,
+ &propertySize, layout);
+ if (status != noErr) {
+ GST_ERROR ("failed to get layout for tag: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ goto failed;
+ }
+ }
+
+beach:
+ gst_core_audio_dump_channel_layout (layout);
+ return layout;
+
+failed:
+ g_free (layout);
+ return NULL;
+}
+
+static inline AudioStreamID *
+_audio_device_get_streams (AudioDeviceID device_id, gint * nstreams)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = 0;
+ AudioStreamID *streams = NULL;
+
+ AudioObjectPropertyAddress streamsAddress = {
+ kAudioDevicePropertyStreams,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyDataSize (device_id,
+ &streamsAddress, 0, NULL, &propertySize);
+ if (status != noErr) {
+ GST_WARNING ("failed getting number of streams: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return NULL;
+ }
+
+ *nstreams = propertySize / sizeof (AudioStreamID);
+ streams = (AudioStreamID *) g_malloc (propertySize);
+
+ if (streams) {
+ status = AudioObjectGetPropertyData (device_id,
+ &streamsAddress, 0, NULL, &propertySize, streams);
+ if (status != noErr) {
+ GST_WARNING ("failed getting the list of streams: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ g_free (streams);
+ *nstreams = 0;
+ return NULL;
+ }
+ }
+
+ return streams;
+}
+
+static inline guint
+_audio_stream_get_latency (AudioStreamID stream_id)
+{
+ OSStatus status = noErr;
+ UInt32 latency;
+ UInt32 propertySize = sizeof (latency);
+
+ AudioObjectPropertyAddress latencyAddress = {
+ kAudioStreamPropertyLatency,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyData (stream_id,
+ &latencyAddress, 0, NULL, &propertySize, &latency);
+ if (status != noErr) {
+ GST_ERROR ("failed to get latency: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ latency = -1;
+ }
+
+ return latency;
+}
+
+static inline gboolean
+_audio_stream_get_current_format (AudioStreamID stream_id,
+ AudioStreamBasicDescription * format)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = sizeof (AudioStreamBasicDescription);
+
+ AudioObjectPropertyAddress formatAddress = {
+ kAudioStreamPropertyPhysicalFormat,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyData (stream_id,
+ &formatAddress, 0, NULL, &propertySize, format);
+ if (status != noErr) {
+ GST_ERROR ("failed to get current format: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline gboolean
+_audio_stream_set_current_format (AudioStreamID stream_id,
+ AudioStreamBasicDescription format)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = sizeof (AudioStreamBasicDescription);
+
+ AudioObjectPropertyAddress formatAddress = {
+ kAudioStreamPropertyPhysicalFormat,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectSetPropertyData (stream_id,
+ &formatAddress, 0, NULL, propertySize, &format);
+ if (status != noErr) {
+ GST_ERROR ("failed to set current format: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static inline AudioStreamRangedDescription *
+_audio_stream_get_formats (AudioStreamID stream_id, gint * nformats)
+{
+ OSStatus status = noErr;
+ UInt32 propertySize = 0;
+ AudioStreamRangedDescription *formats = NULL;
+
+ AudioObjectPropertyAddress formatsAddress = {
+ kAudioStreamPropertyAvailablePhysicalFormats,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ status = AudioObjectGetPropertyDataSize (stream_id,
+ &formatsAddress, 0, NULL, &propertySize);
+ if (status != noErr) {
+ GST_WARNING ("failed getting number of stream formats: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return NULL;
+ }
+
+ *nformats = propertySize / sizeof (AudioStreamRangedDescription);
+
+ formats = (AudioStreamRangedDescription *) g_malloc (propertySize);
+ if (formats) {
+ status = AudioObjectGetPropertyData (stream_id,
+ &formatsAddress, 0, NULL, &propertySize, formats);
+ if (status != noErr) {
+ GST_WARNING ("failed getting the list of stream formats: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ g_free (formats);
+ *nformats = 0;
+ return NULL;
+ }
+ }
+ return formats;
+}
+
+static inline gboolean
+_audio_stream_is_spdif_avail (AudioStreamID stream_id)
+{
+ AudioStreamRangedDescription *formats;
+ gint i, nformats = 0;
+ gboolean res = FALSE;
+
+ formats = _audio_stream_get_formats (stream_id, &nformats);
+ GST_DEBUG ("found %d stream formats", nformats);
+
+ if (formats) {
+ GST_DEBUG ("formats supported on stream ID: %u", (unsigned) stream_id);
+
+ for (i = 0; i < nformats; i++) {
+ GST_DEBUG (" " CORE_AUDIO_FORMAT,
+ CORE_AUDIO_FORMAT_ARGS (formats[i].mFormat));
+
+ if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[i])) {
+ res = TRUE;
+ }
+ }
+ g_free (formats);
+ }
+
+ return res;
+}
+
+static OSStatus
+_audio_stream_format_listener (AudioObjectID inObjectID,
+ UInt32 inNumberAddresses,
+ const AudioObjectPropertyAddress inAddresses[], void *inClientData)
+{
+ OSStatus status = noErr;
+ guint i;
+ PropertyMutex *prop_mutex = inClientData;
+
+ for (i = 0; i < inNumberAddresses; i++) {
+ if (inAddresses[i].mSelector == kAudioStreamPropertyPhysicalFormat) {
+ g_mutex_lock (prop_mutex->lock);
+ g_cond_signal (prop_mutex->cond);
+ g_mutex_unlock (prop_mutex->lock);
+ break;
+ }
+ }
+ return (status);
+}
+
+static gboolean
+_audio_stream_change_format (AudioStreamID stream_id,
+ AudioStreamBasicDescription format)
+{
+ OSStatus status = noErr;
+ gint i;
+ gboolean ret = FALSE;
+ AudioStreamBasicDescription cformat;
+ PropertyMutex prop_mutex;
+
+ AudioObjectPropertyAddress formatAddress = {
+ kAudioStreamPropertyPhysicalFormat,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ GST_DEBUG ("setting stream format: " CORE_AUDIO_FORMAT,
+ CORE_AUDIO_FORMAT_ARGS (format));
+
+ /* Condition because SetProperty is asynchronous */
+ prop_mutex.lock = g_mutex_new ();
+ prop_mutex.cond = g_cond_new ();
+
+ g_mutex_lock (prop_mutex.lock);
+
+ /* Install the property listener to serialize the operations */
+ status = AudioObjectAddPropertyListener (stream_id, &formatAddress,
+ _audio_stream_format_listener, (void *) &prop_mutex);
+ if (status != noErr) {
+ GST_ERROR ("AudioObjectAddPropertyListener failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ goto done;
+ }
+
+ /* Change the format */
+ if (!_audio_stream_set_current_format (stream_id, format)) {
+ goto done;
+ }
+
+ /* The AudioObjectSetProperty is not only asynchronous
+ * it is also not atomic in its behaviour.
+ * Therefore we check 4 times before we really give up. */
+ for (i = 0; i < 4; i++) {
+ GTimeVal timeout;
+
+ g_get_current_time (&timeout);
+ g_time_val_add (&timeout, 250000);
+
+ if (!g_cond_timed_wait (prop_mutex.cond, prop_mutex.lock, &timeout)) {
+ GST_LOG ("timeout...");
+ }
+
+ if (_audio_stream_get_current_format (stream_id, &cformat)) {
+ GST_DEBUG ("current stream format: " CORE_AUDIO_FORMAT,
+ CORE_AUDIO_FORMAT_ARGS (cformat));
+
+ if (cformat.mSampleRate == format.mSampleRate &&
+ cformat.mFormatID == format.mFormatID &&
+ cformat.mFramesPerPacket == format.mFramesPerPacket) {
+ /* The right format is now active */
+ break;
+ }
+ }
+ }
+
+ if (cformat.mSampleRate != format.mSampleRate ||
+ cformat.mFormatID != format.mFormatID ||
+ cformat.mFramesPerPacket != format.mFramesPerPacket) {
+ goto done;
+ }
+
+ ret = TRUE;
+
+done:
+ /* Removing the property listener */
+ status = AudioObjectRemovePropertyListener (stream_id,
+ &formatAddress, _audio_stream_format_listener, (void *) &prop_mutex);
+ if (status != noErr) {
+ GST_ERROR ("AudioObjectRemovePropertyListener failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ }
+ /* Destroy the lock and condition */
+ g_mutex_unlock (prop_mutex.lock);
+ g_mutex_free (prop_mutex.lock);
+ g_cond_free (prop_mutex.cond);
+
+ return ret;
+}
+
+static OSStatus
+_audio_stream_hardware_changed_listener (AudioObjectID inObjectID,
+ UInt32 inNumberAddresses,
+ const AudioObjectPropertyAddress inAddresses[], void *inClientData)
+{
+ OSStatus status = noErr;
+ guint i;
+ GstCoreAudio *core_audio = inClientData;
+
+ for (i = 0; i < inNumberAddresses; i++) {
+ if (inAddresses[i].mSelector == kAudioDevicePropertyDeviceHasChanged) {
+ if (!gst_core_audio_audio_device_is_spdif_avail (core_audio->device_id)) {
+ GstOsxAudioSink *sink =
+ GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (core_audio->osxbuf));
+ GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
+ ("SPDIF output no longer available"),
+ ("Audio device is reporting that SPDIF output isn't available"));
+ }
+ break;
+ }
+ }
+ return (status);
+}
+
+static inline gboolean
+_monitorize_spdif (GstCoreAudio * core_audio)
+{
+ OSStatus status = noErr;
+ gboolean ret = TRUE;
+
+ AudioObjectPropertyAddress propAddress = {
+ kAudioDevicePropertyDeviceHasChanged,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ /* Install the property listener */
+ status = AudioObjectAddPropertyListener (core_audio->device_id,
+ &propAddress, _audio_stream_hardware_changed_listener,
+ (void *) core_audio);
+ if (status != noErr) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioObjectAddPropertyListener failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+static inline gboolean
+_unmonitorize_spdif (GstCoreAudio * core_audio)
+{
+ OSStatus status = noErr;
+ gboolean ret = TRUE;
+
+ AudioObjectPropertyAddress propAddress = {
+ kAudioDevicePropertyDeviceHasChanged,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+
+ /* Remove the property listener */
+ status = AudioObjectRemovePropertyListener (core_audio->device_id,
+ &propAddress, _audio_stream_hardware_changed_listener,
+ (void *) core_audio);
+ if (status != noErr) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioObjectRemovePropertyListener failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+static inline gboolean
+_open_spdif (GstCoreAudio * core_audio)
+{
+ gboolean res = FALSE;
+ pid_t hog_pid, own_pid = getpid ();
+
+ /* We need the device in exclusive and disable the mixing */
+ hog_pid = _audio_device_get_hog (core_audio->device_id);
+
+ if (hog_pid != -1 && hog_pid != own_pid) {
+ GST_DEBUG_OBJECT (core_audio,
+ "device is currently in use by another application");
+ goto done;
+ }
+
+ if (_audio_device_set_hog (core_audio->device_id, own_pid)) {
+ core_audio->hog_pid = own_pid;
+ }
+
+ if (_audio_device_set_mixing (core_audio->device_id, FALSE)) {
+ GST_DEBUG_OBJECT (core_audio, "disabled mixing on the device");
+ core_audio->disabled_mixing = TRUE;
+ }
+
+ res = TRUE;
+done:
+ return res;
+}
+
+static inline gboolean
+_close_spdif (GstCoreAudio * core_audio)
+{
+ pid_t hog_pid;
+
+ _unmonitorize_spdif (core_audio);
+
+ if (core_audio->revert_format) {
+ if (!_audio_stream_change_format (core_audio->stream_id,
+ core_audio->original_format)) {
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Format revert failed");
+ }
+ core_audio->revert_format = FALSE;
+ }
+
+ if (core_audio->disabled_mixing) {
+ _audio_device_set_mixing (core_audio->device_id, TRUE);
+ core_audio->disabled_mixing = FALSE;
+ }
+
+ if (core_audio->hog_pid != -1) {
+ hog_pid = _audio_device_get_hog (core_audio->device_id);
+ if (hog_pid == getpid ()) {
+ if (_audio_device_set_hog (core_audio->device_id, -1)) {
+ core_audio->hog_pid = -1;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static OSStatus
+_io_proc_spdif (AudioDeviceID inDevice,
+ const AudioTimeStamp * inNow,
+ const void *inInputData,
+ const AudioTimeStamp * inTimestamp,
+ AudioBufferList * bufferList,
+ const AudioTimeStamp * inOutputTime, GstCoreAudio * core_audio)
+{
+ OSStatus status;
+
+ status = core_audio->element->io_proc (core_audio->osxbuf, NULL, inTimestamp,
+ 0, 0, bufferList);
+
+ return status;
+}
+
+static inline gboolean
+_acquire_spdif (GstCoreAudio * core_audio, AudioStreamBasicDescription format)
+{
+ AudioStreamID *streams = NULL;
+ gint i, j, nstreams = 0;
+ gboolean ret = FALSE;
+
+ if (!_open_spdif (core_audio))
+ goto done;
+
+ streams = _audio_device_get_streams (core_audio->device_id, &nstreams);
+
+ for (i = 0; i < nstreams; i++) {
+ AudioStreamRangedDescription *formats = NULL;
+ gint nformats = 0;
+
+ formats = _audio_stream_get_formats (streams[i], &nformats);
+
+ if (formats) {
+ gboolean is_spdif = FALSE;
+
+ /* Check if one of the supported formats is a digital format */
+ for (j = 0; j < nformats; j++) {
+ if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) {
+ is_spdif = TRUE;
+ break;
+ }
+ }
+
+ if (is_spdif) {
+ /* if this stream supports a digital (cac3) format,
+ * then go set it. */
+ gint requested_rate_format = -1;
+ gint current_rate_format = -1;
+ gint backup_rate_format = -1;
+
+ core_audio->stream_id = streams[i];
+ core_audio->stream_idx = i;
+
+ if (!core_audio->revert_format) {
+ if (!_audio_stream_get_current_format (core_audio->stream_id,
+ &core_audio->original_format)) {
+ GST_WARNING_OBJECT (core_audio->osxbuf,
+ "format could not be saved");
+ g_free (formats);
+ continue;
+ }
+ core_audio->revert_format = TRUE;
+ }
+
+ for (j = 0; j < nformats; j++) {
+ if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) {
+ GST_LOG_OBJECT (core_audio->osxbuf,
+ "found stream format: " CORE_AUDIO_FORMAT,
+ CORE_AUDIO_FORMAT_ARGS (formats[j].mFormat));
+
+ if (formats[j].mFormat.mSampleRate == format.mSampleRate) {
+ requested_rate_format = j;
+ break;
+ } else if (formats[j].mFormat.mSampleRate ==
+ core_audio->original_format.mSampleRate) {
+ current_rate_format = j;
+ } else {
+ if (backup_rate_format < 0 ||
+ formats[j].mFormat.mSampleRate >
+ formats[backup_rate_format].mFormat.mSampleRate) {
+ backup_rate_format = j;
+ }
+ }
+ }
+ }
+
+ if (requested_rate_format >= 0) {
+ /* We prefer to output at the rate of the original audio */
+ core_audio->stream_format = formats[requested_rate_format].mFormat;
+ } else if (current_rate_format >= 0) {
+ /* If not possible, we will try to use the current rate */
+ core_audio->stream_format = formats[current_rate_format].mFormat;
+ } else {
+ /* And if we have to, any digital format will be just
+ * fine (highest rate possible) */
+ core_audio->stream_format = formats[backup_rate_format].mFormat;
+ }
+ }
+ g_free (formats);
+ }
+ }
+ g_free (streams);
+
+ GST_DEBUG_OBJECT (core_audio,
+ "original stream format: " CORE_AUDIO_FORMAT,
+ CORE_AUDIO_FORMAT_ARGS (core_audio->original_format));
+
+ if (!_audio_stream_change_format (core_audio->stream_id,
+ core_audio->stream_format))
+ goto done;
+
+ ret = TRUE;
+
+done:
+ return ret;
+}
+
+static inline void
+_remove_render_spdif_callback (GstCoreAudio * core_audio)
+{
+ OSStatus status;
+
+ /* Deactivate the render callback by calling
+ * AudioDeviceDestroyIOProcID */
+ status =
+ AudioDeviceDestroyIOProcID (core_audio->device_id, core_audio->procID);
+ if (status != noErr) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioDeviceDestroyIOProcID failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ }
+
+ GST_DEBUG_OBJECT (core_audio,
+ "osx ring buffer removed ioproc ID: %p device_id %lu",
+ core_audio->procID, (gulong) core_audio->device_id);
+
+ /* We're deactivated.. */
+ core_audio->procID = 0;
+ core_audio->io_proc_needs_deactivation = FALSE;
+ core_audio->io_proc_active = FALSE;
+}
+
+static inline gboolean
+_io_proc_spdif_start (GstCoreAudio * core_audio)
+{
+ OSErr status;
+
+ GST_DEBUG_OBJECT (core_audio,
+ "osx ring buffer start ioproc ID: %p device_id %lu",
+ core_audio->procID, (gulong) core_audio->device_id);
+
+ if (!core_audio->io_proc_active) {
+ /* Add IOProc callback */
+ status = AudioDeviceCreateIOProcID (core_audio->device_id,
+ (AudioDeviceIOProc) _io_proc_spdif,
+ (void *) core_audio, &core_audio->procID);
+ if (status != noErr) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ ":AudioDeviceCreateIOProcID failed: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ core_audio->io_proc_active = TRUE;
+ }
+
+ core_audio->io_proc_needs_deactivation = FALSE;
+
+ /* Start device */
+ status = AudioDeviceStart (core_audio->device_id, core_audio->procID);
+ if (status != noErr) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioDeviceStart failed: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static inline gboolean
+_io_proc_spdif_stop (GstCoreAudio * core_audio)
+{
+ OSErr status;
+
+ /* Stop device */
+ status = AudioDeviceStop (core_audio->device_id, core_audio->procID);
+ if (status != noErr) {
+ GST_ERROR_OBJECT (core_audio->osxbuf,
+ "AudioDeviceStop failed: %" GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (status));
+ }
+
+ GST_DEBUG_OBJECT (core_audio,
+ "osx ring buffer stop ioproc ID: %p device_id %lu",
+ core_audio->procID, (gulong) core_audio->device_id);
+
+ if (core_audio->io_proc_active) {
+ _remove_render_spdif_callback (core_audio);
+ }
+
+ _close_spdif (core_audio);
+
+ return TRUE;
+}
+
+
+/***********************
+ * Implementation *
+ **********************/
+
+static gboolean
+gst_core_audio_open_impl (GstCoreAudio * core_audio)
+{
+ /* The following is needed to instruct HAL to create their own
+ * thread to handle the notifications. */
+ _audio_system_set_runloop (NULL);
+
+ /* 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
+ */
+ return gst_core_audio_open_device (core_audio, kAudioUnitSubType_HALOutput,
+ "HALOutput");
+}
+
+static gboolean
+gst_core_audio_start_processing_impl (GstCoreAudio * core_audio)
+{
+ if (core_audio->is_passthrough) {
+ return _io_proc_spdif_start (core_audio);
+ } else {
+ return gst_core_audio_io_proc_start (core_audio);
+ }
+}
+
+static gboolean
+gst_core_audio_pause_processing_impl (GstCoreAudio * core_audio)
+{
+ if (core_audio->is_passthrough) {
+ GST_DEBUG_OBJECT (core_audio,
+ "osx ring buffer pause ioproc ID: %p device_id %lu",
+ core_audio->procID, (gulong) core_audio->device_id);
+
+ if (core_audio->io_proc_active) {
+ _remove_render_spdif_callback (core_audio);
+ }
+ } else {
+ GST_DEBUG_OBJECT (core_audio,
+ "osx ring buffer pause ioproc: %p device_id %lu",
+ core_audio->element->io_proc, (gulong) core_audio->device_id);
+ if (core_audio->io_proc_active) {
+ /* 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
+ */
+ core_audio->io_proc_needs_deactivation = TRUE;
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_core_audio_stop_processing_impl (GstCoreAudio * core_audio)
+{
+ if (core_audio->is_passthrough) {
+ _io_proc_spdif_stop (core_audio);
+ } else {
+ gst_core_audio_io_proc_stop (core_audio);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gst_core_audio_get_samples_and_latency_impl (GstCoreAudio * core_audio,
+ gdouble rate, guint * samples, gdouble * latency)
+{
+ OSStatus status;
+ UInt32 size = sizeof (double);
+
+ if (core_audio->is_passthrough) {
+ *samples = _audio_device_get_latency (core_audio->device_id);
+ *samples += _audio_stream_get_latency (core_audio->stream_id);
+ *latency = (double) *samples / rate;
+ } else {
+ status = AudioUnitGetProperty (core_audio->audiounit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, /* N/A for global */
+ latency, &size);
+
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to get latency: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ *samples = 0;
+ return FALSE;
+ }
+
+ *samples = *latency * rate;
+ }
+ return TRUE;
+}
+
+static gboolean
+gst_core_audio_initialize_impl (GstCoreAudio * core_audio,
+ AudioStreamBasicDescription format, GstCaps * caps,
+ gboolean is_passthrough, guint32 * frame_size)
+{
+ gboolean ret = FALSE;
+
+ core_audio->is_passthrough = is_passthrough;
+ if (is_passthrough) {
+ if (!_acquire_spdif (core_audio, format))
+ goto done;
+ _monitorize_spdif (core_audio);
+ } else {
+ OSStatus status;
+ UInt32 propertySize;
+
+ core_audio->stream_idx = 0;
+ if (!gst_core_audio_set_format (core_audio, format))
+ goto done;
+
+ if (!gst_core_audio_set_channels_layout (core_audio,
+ format.mChannelsPerFrame, caps))
+ goto done;
+
+ if (!gst_core_audio_bind_device (core_audio))
+ goto done;
+
+ if (core_audio->is_src) {
+ propertySize = sizeof (*frame_size);
+ status = AudioUnitGetProperty (core_audio->audiounit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, 0, /* N/A for global */
+ frame_size, &propertySize);
+
+ if (status) {
+ GST_WARNING_OBJECT (core_audio->osxbuf, "Failed to get frame size: %"
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
+ goto done;
+ }
+ }
+ }
+
+ ret = TRUE;
+
+done:
+ if (ret) {
+ GST_DEBUG_OBJECT (core_audio, "osxbuf ring buffer acquired");
+ }
+ return ret;
+}
+
+static gboolean
+gst_core_audio_select_device_impl (AudioDeviceID * device_id)
+{
+ AudioDeviceID *devices = NULL;
+ AudioDeviceID default_device_id = 0;
+ AudioChannelLayout *channel_layout;
+ gint i, ndevices = 0;
+ gboolean res = FALSE;
+
+ devices = _audio_system_get_devices (&ndevices);
+
+ if (ndevices < 1) {
+ GST_ERROR ("no audio output devices found");
+ goto done;
+ }
+
+ GST_DEBUG ("found %d audio device(s)", ndevices);
+
+ for (i = 0; i < ndevices; i++) {
+ gchar *device_name;
+
+ if ((device_name = _audio_device_get_name (devices[i]))) {
+ if (!_audio_device_has_output (devices[i])) {
+ GST_DEBUG ("Input Device ID: %u Name: %s",
+ (unsigned) devices[i], device_name);
+ } else {
+ GST_DEBUG ("Output Device ID: %u Name: %s",
+ (unsigned) devices[i], device_name);
+
+ channel_layout =
+ gst_core_audio_audio_device_get_channel_layout (devices[i]);
+ if (channel_layout) {
+ gst_core_audio_dump_channel_layout (channel_layout);
+ g_free (channel_layout);
+ }
+ }
+
+ g_free (device_name);
+ }
+ }
+
+ /* Find the ID of the default output device */
+ default_device_id = _audio_system_get_default_output ();
+
+ /* Here we decide if selected device is valid or autoselect
+ * the default one when required */
+ if (*device_id == kAudioDeviceUnknown) {
+ if (default_device_id != kAudioDeviceUnknown) {
+ *device_id = default_device_id;
+ res = TRUE;
+ }
+ } else {
+ for (i = 0; i < ndevices; i++) {
+ if (*device_id == devices[i]) {
+ res = TRUE;
+ }
+ }
+
+ if (res && !_audio_device_is_alive (*device_id)) {
+ GST_ERROR ("Requested device not usable");
+ res = FALSE;
+ goto done;
+ }
+ }
+
+done:
+ g_free (devices);
+ return res;
+}
+
+static gboolean
+gst_core_audio_audio_device_is_spdif_avail_impl (AudioDeviceID device_id)
+{
+ AudioStreamID *streams = NULL;
+ gint i, nstreams = 0;
+ gboolean res = FALSE;
+
+ streams = _audio_device_get_streams (device_id, &nstreams);
+ GST_DEBUG ("found %d streams", nstreams);
+ if (streams) {
+ for (i = 0; i < nstreams; i++) {
+ if (_audio_stream_is_spdif_avail (streams[i])) {
+ res = TRUE;
+ }
+ }
+
+ g_free (streams);
+ }
+
+ return res;
+}
+
+static gboolean
+gst_core_audio_select_source_device_impl (AudioDeviceID * device_id)
+{
+ OSStatus status;
+ UInt32 propertySize;
+
+ if (*device_id == kAudioDeviceUnknown) {
+ /* If no specific device has been selected by the user, then pick the
+ * default device */
+ GST_DEBUG ("Selecting device for OSXAudioSrc");
+ propertySize = sizeof (*device_id);
+ status = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultInputDevice,
+ &propertySize, device_id);
+
+ if (status) {
+ GST_WARNING ("AudioHardwareGetProperty returned %d", (int) status);
+ } else {
+ GST_DEBUG ("AudioHardwareGetProperty returned 0");
+ }
+
+ if (*device_id == kAudioDeviceUnknown) {
+ GST_WARNING ("AudioHardwareGetProperty: device_id is "
+ "kAudioDeviceUnknown");
+ }
+
+ GST_DEBUG ("AudioHardwareGetProperty: device_id is %lu", (long) *device_id);
+ }
+
+ return TRUE;
+}
diff --git a/sys/osxaudio/gstosxringbuffer.c b/sys/osxaudio/gstosxringbuffer.c
index f43a055e5..82da79913 100644
--- a/sys/osxaudio/gstosxringbuffer.c
+++ b/sys/osxaudio/gstosxringbuffer.c
@@ -43,8 +43,10 @@
* Boston, MA 02111-1307, USA.
*/
-#include <CoreAudio/CoreAudio.h>
-#include <CoreServices/CoreServices.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include <gst/gst.h>
#include <gst/audio/multichannel.h>
#include "gstosxringbuffer.h"
@@ -73,9 +75,6 @@ static gboolean gst_osx_ring_buffer_stop (GstRingBuffer * buf);
static guint gst_osx_ring_buffer_delay (GstRingBuffer * buf);
static GstRingBufferClass *ring_parent_class = NULL;
-static void gst_osx_ring_buffer_remove_render_callback (GstOsxRingBuffer *
- osxbuf);
-
static void
gst_osx_ring_buffer_do_init (GType type)
{
@@ -130,15 +129,20 @@ static void
gst_osx_ring_buffer_init (GstOsxRingBuffer * ringbuffer,
GstOsxRingBufferClass * g_class)
{
- /* Nothing to do right now */
- ringbuffer->is_passthrough = FALSE;
- ringbuffer->hog_pid = -1;
- ringbuffer->disabled_mixing = FALSE;
+ ringbuffer->core_audio = gst_core_audio_new (GST_OBJECT (ringbuffer));
}
static void
gst_osx_ring_buffer_dispose (GObject * object)
{
+ GstOsxRingBuffer *osxbuf;
+
+ osxbuf = GST_OSX_RING_BUFFER (object);
+
+ if (osxbuf->core_audio) {
+ g_object_unref (osxbuf->core_audio);
+ osxbuf->core_audio = NULL;
+ }
G_OBJECT_CLASS (ring_parent_class)->dispose (object);
}
@@ -148,103 +152,6 @@ 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;
- AudioStreamBasicDescription asbd_in;
- UInt32 propertySize;
-
- /* 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_ERROR_OBJECT (osxbuf, "Couldn't open HALOutput component %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- 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: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (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: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return NULL;
- }
- }
-
- GST_DEBUG_OBJECT (osxbuf, "Created HALOutput AudioUnit: %p", unit);
-
- if (input) {
- GstOsxAudioSrc *src = GST_OSX_AUDIO_SRC (GST_OBJECT_PARENT (osxbuf));
-
- propertySize = sizeof (asbd_in);
- status = AudioUnitGetProperty (unit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input, 1, &asbd_in, &propertySize);
-
- if (status) {
- CloseComponent (unit);
- GST_WARNING_OBJECT (osxbuf,
- "Unable to obtain device properties: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- return NULL;
- }
-
- src->deviceChannels = asbd_in.mChannelsPerFrame;
- } else {
- GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (osxbuf));
-
- /* needed for the sink's volume control */
- sink->audiounit = unit;
- }
-
- return unit;
-}
-
static gboolean
gst_osx_ring_buffer_open_device (GstRingBuffer * buf)
{
@@ -252,18 +159,7 @@ gst_osx_ring_buffer_open_device (GstRingBuffer * buf)
osxbuf = GST_OSX_RING_BUFFER (buf);
- /* The following is needed to instruct HAL to create their own
- * thread to handle the notifications. */
- _audio_system_set_runloop (NULL);
-
- osxbuf->audiounit = gst_osx_ring_buffer_create_audio_unit (osxbuf,
- osxbuf->is_src, osxbuf->device_id);
-
- if (!osxbuf->audiounit) {
- return FALSE;
- }
-
- return TRUE;
+ return gst_core_audio_open (osxbuf->core_audio);
}
static gboolean
@@ -272,581 +168,13 @@ gst_osx_ring_buffer_close_device (GstRingBuffer * buf)
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 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);
-}
-
-typedef struct
-{
- GMutex *lock;
- GCond *cond;
-} PropertyMutex;
-
-static OSStatus
-_audio_stream_format_listener (AudioObjectID inObjectID,
- UInt32 inNumberAddresses,
- const AudioObjectPropertyAddress inAddresses[], void *inClientData)
-{
- OSStatus status = noErr;
- guint i;
- PropertyMutex *prop_mutex = inClientData;
-
- for (i = 0; i < inNumberAddresses; i++) {
- if (inAddresses[i].mSelector == kAudioStreamPropertyPhysicalFormat) {
- g_mutex_lock (prop_mutex->lock);
- g_cond_signal (prop_mutex->cond);
- g_mutex_unlock (prop_mutex->lock);
- break;
- }
- }
- return (status);
-}
-
-static gboolean
-_audio_stream_change_format (AudioStreamID stream_id,
- AudioStreamBasicDescription format)
-{
- OSStatus status = noErr;
- gint i;
- gboolean ret = FALSE;
- AudioStreamBasicDescription cformat;
- PropertyMutex prop_mutex;
-
- AudioObjectPropertyAddress formatAddress = {
- kAudioStreamPropertyPhysicalFormat,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- GST_DEBUG ("setting stream format: " CORE_AUDIO_FORMAT,
- CORE_AUDIO_FORMAT_ARGS (format));
-
- /* Condition because SetProperty is asynchronous */
- prop_mutex.lock = g_mutex_new ();
- prop_mutex.cond = g_cond_new ();
-
- g_mutex_lock (prop_mutex.lock);
-
- /* Install the property listener to serialize the operations */
- status = AudioObjectAddPropertyListener (stream_id, &formatAddress,
- _audio_stream_format_listener, (void *) &prop_mutex);
- if (status != noErr) {
- GST_ERROR ("AudioObjectAddPropertyListener failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- goto done;
- }
-
- /* Change the format */
- if (!_audio_stream_set_current_format (stream_id, format)) {
- goto done;
- }
-
- /* The AudioObjectSetProperty is not only asynchronous
- * it is also not atomic in its behaviour.
- * Therefore we check 4 times before we really give up. */
- for (i = 0; i < 4; i++) {
- GTimeVal timeout;
-
- g_get_current_time (&timeout);
- g_time_val_add (&timeout, 250000);
-
- if (!g_cond_timed_wait (prop_mutex.cond, prop_mutex.lock, &timeout)) {
- GST_LOG ("timeout...");
- }
-
- if (_audio_stream_get_current_format (stream_id, &cformat)) {
- GST_DEBUG ("current stream format: " CORE_AUDIO_FORMAT,
- CORE_AUDIO_FORMAT_ARGS (cformat));
-
- if (cformat.mSampleRate == format.mSampleRate &&
- cformat.mFormatID == format.mFormatID &&
- cformat.mFramesPerPacket == format.mFramesPerPacket) {
- /* The right format is now active */
- break;
- }
- }
- }
-
- if (cformat.mSampleRate != format.mSampleRate ||
- cformat.mFormatID != format.mFormatID ||
- cformat.mFramesPerPacket != format.mFramesPerPacket) {
- goto done;
- }
-
- ret = TRUE;
-
-done:
- /* Removing the property listener */
- status = AudioObjectRemovePropertyListener (stream_id,
- &formatAddress, _audio_stream_format_listener, (void *) &prop_mutex);
- if (status != noErr) {
- GST_ERROR ("AudioObjectRemovePropertyListener failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- }
- /* Destroy the lock and condition */
- g_mutex_unlock (prop_mutex.lock);
- g_mutex_free (prop_mutex.lock);
- g_cond_free (prop_mutex.cond);
-
- return ret;
-}
-
-static OSStatus
-_audio_stream_hardware_changed_listener (AudioObjectID inObjectID,
- UInt32 inNumberAddresses,
- const AudioObjectPropertyAddress inAddresses[], void *inClientData)
-{
- OSStatus status = noErr;
- guint i;
- GstOsxRingBuffer *osxbuf = inClientData;
-
- for (i = 0; i < inNumberAddresses; i++) {
- if (inAddresses[i].mSelector == kAudioDevicePropertyDeviceHasChanged) {
- if (!_audio_device_is_spdif_avail (osxbuf->device_id)) {
- GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (GST_OBJECT_PARENT (osxbuf));
- GST_ELEMENT_ERROR (sink, RESOURCE, FAILED,
- ("SPDIF output no longer available"),
- ("Audio device is reporting that SPDIF output isn't available"));
- }
- break;
- }
- }
- return (status);
-}
-
-static gboolean
-gst_osx_ring_buffer_monitorize_spdif (GstOsxRingBuffer * osxbuf)
-{
- OSStatus status = noErr;
- gboolean ret = TRUE;
-
- AudioObjectPropertyAddress propAddress = {
- kAudioDevicePropertyDeviceHasChanged,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- /* Install the property listener */
- status = AudioObjectAddPropertyListener (osxbuf->device_id,
- &propAddress, _audio_stream_hardware_changed_listener, (void *) osxbuf);
- if (status != noErr) {
- GST_ERROR ("AudioObjectAddPropertyListener failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- ret = FALSE;
- }
-
- return ret;
-}
-
-static gboolean
-gst_osx_ring_buffer_unmonitorize_spdif (GstOsxRingBuffer * osxbuf)
-{
- OSStatus status = noErr;
- gboolean ret = TRUE;
-
- AudioObjectPropertyAddress propAddress = {
- kAudioDevicePropertyDeviceHasChanged,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster
- };
-
- /* Remove the property listener */
- status = AudioObjectRemovePropertyListener (osxbuf->device_id,
- &propAddress, _audio_stream_hardware_changed_listener, (void *) osxbuf);
- if (status != noErr) {
- GST_ERROR ("AudioObjectRemovePropertyListener failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- ret = FALSE;
- }
-
- return ret;
-}
-
-static gboolean
-gst_osx_ring_buffer_open_spdif (GstOsxRingBuffer * osxbuf)
-{
- gboolean res = FALSE;
- pid_t hog_pid, own_pid = getpid ();
-
- /* We need the device in exclusive and disable the mixing */
- hog_pid = _audio_device_get_hog (osxbuf->device_id);
-
- if (hog_pid != -1 && hog_pid != own_pid) {
- GST_DEBUG_OBJECT (osxbuf,
- "device is currently in use by another application");
- goto done;
- }
-
- if (_audio_device_set_hog (osxbuf->device_id, own_pid)) {
- osxbuf->hog_pid = own_pid;
- }
-
- if (_audio_device_set_mixing (osxbuf->device_id, FALSE)) {
- GST_DEBUG_OBJECT (osxbuf, "disabled mixing on the device");
- osxbuf->disabled_mixing = TRUE;
- }
-
- res = TRUE;
-done:
- return res;
-}
-
-static gboolean
-gst_osx_ring_buffer_close_spdif (GstOsxRingBuffer * osxbuf)
-{
- pid_t hog_pid;
-
- gst_osx_ring_buffer_unmonitorize_spdif (osxbuf);
-
- if (osxbuf->revert_format) {
- if (!_audio_stream_change_format (osxbuf->stream_id,
- osxbuf->original_format)) {
- GST_WARNING ("Format revert failed");
- }
- osxbuf->revert_format = FALSE;
- }
-
- if (osxbuf->disabled_mixing) {
- _audio_device_set_mixing (osxbuf->device_id, TRUE);
- osxbuf->disabled_mixing = FALSE;
- }
-
- if (osxbuf->hog_pid != -1) {
- hog_pid = _audio_device_get_hog (osxbuf->device_id);
- if (hog_pid == getpid ()) {
- if (_audio_device_set_hog (osxbuf->device_id, -1)) {
- osxbuf->hog_pid = -1;
- }
- }
- }
-
- return TRUE;
-}
-
-static OSStatus
-gst_osx_ring_buffer_io_proc_spdif (AudioDeviceID inDevice,
- const AudioTimeStamp * inNow,
- const void *inInputData,
- const AudioTimeStamp * inTimestamp,
- AudioBufferList * bufferList,
- const AudioTimeStamp * inOutputTime, GstOsxRingBuffer * osxbuf)
-{
- OSStatus status;
-
- status = osxbuf->element->io_proc (osxbuf, NULL, inTimestamp, 0, 0,
- bufferList);
-
- return status;
-}
-
-static gboolean
-gst_osx_ring_buffer_acquire_spdif (GstOsxRingBuffer * osxbuf,
- AudioStreamBasicDescription format)
-{
- AudioStreamID *streams = NULL;
- gint i, j, nstreams = 0;
- gboolean ret = FALSE;
-
- if (!gst_osx_ring_buffer_open_spdif (osxbuf))
- goto done;
-
- streams = _audio_device_get_streams (osxbuf->device_id, &nstreams);
-
- for (i = 0; i < nstreams; i++) {
- AudioStreamRangedDescription *formats = NULL;
- gint nformats = 0;
-
- formats = _audio_stream_get_formats (streams[i], &nformats);
-
- if (formats) {
- gboolean is_spdif = FALSE;
-
- /* Check if one of the supported formats is a digital format */
- for (j = 0; j < nformats; j++) {
- if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) {
- is_spdif = TRUE;
- break;
- }
- }
-
- if (is_spdif) {
- /* if this stream supports a digital (cac3) format,
- * then go set it. */
- gint requested_rate_format = -1;
- gint current_rate_format = -1;
- gint backup_rate_format = -1;
-
- osxbuf->stream_id = streams[i];
- osxbuf->stream_idx = i;
-
- if (!osxbuf->revert_format) {
- if (!_audio_stream_get_current_format (osxbuf->stream_id,
- &osxbuf->original_format)) {
- GST_WARNING ("format could not be saved");
- g_free (formats);
- continue;
- }
- osxbuf->revert_format = TRUE;
- }
-
- for (j = 0; j < nformats; j++) {
- if (CORE_AUDIO_FORMAT_IS_SPDIF (formats[j])) {
- GST_LOG ("found stream format: " CORE_AUDIO_FORMAT,
- CORE_AUDIO_FORMAT_ARGS (formats[j].mFormat));
-
- if (formats[j].mFormat.mSampleRate == format.mSampleRate) {
- requested_rate_format = j;
- break;
- } else if (formats[j].mFormat.mSampleRate ==
- osxbuf->original_format.mSampleRate) {
- current_rate_format = j;
- } else {
- if (backup_rate_format < 0 ||
- formats[j].mFormat.mSampleRate >
- formats[backup_rate_format].mFormat.mSampleRate) {
- backup_rate_format = j;
- }
- }
- }
- }
-
- if (requested_rate_format >= 0) {
- /* We prefer to output at the rate of the original audio */
- osxbuf->stream_format = formats[requested_rate_format].mFormat;
- } else if (current_rate_format >= 0) {
- /* If not possible, we will try to use the current rate */
- osxbuf->stream_format = formats[current_rate_format].mFormat;
- } else {
- /* And if we have to, any digital format will be just
- * fine (highest rate possible) */
- osxbuf->stream_format = formats[backup_rate_format].mFormat;
- }
- }
- g_free (formats);
- }
- }
- g_free (streams);
-
- GST_DEBUG ("original stream format: " CORE_AUDIO_FORMAT,
- CORE_AUDIO_FORMAT_ARGS (osxbuf->original_format));
-
- if (!_audio_stream_change_format (osxbuf->stream_id, osxbuf->stream_format))
- goto done;
-
- GST_DEBUG_OBJECT (osxbuf, "osx ring buffer acquired");
-
- ret = TRUE;
-
-done:
- return ret;
-}
-
-static gboolean
-gst_osx_ring_buffer_acquire_analog (GstOsxRingBuffer * osxbuf,
- AudioStreamBasicDescription format, GstCaps * caps)
-{
- /* Configure the output stream and allocate ringbuffer memory */
- AudioChannelLayout *layout = NULL;
- OSStatus status;
- UInt32 propertySize;
- int channels = format.mChannelsPerFrame;
- int layoutSize;
- int element;
- int i;
- AudioUnitScope scope;
- gboolean ret = FALSE;
- GstStructure *structure;
- GstAudioChannelPosition *positions;
- UInt32 frameSize;
-
- /* Describe channels */
- layoutSize = sizeof (AudioChannelLayout) +
- channels * sizeof (AudioChannelDescription);
- layout = g_malloc (layoutSize);
-
- structure = gst_caps_get_structure (caps, 0);
- positions = gst_audio_get_channel_positions (structure);
-
- layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
- layout->mChannelBitmap = 0; /* Not used */
- layout->mNumberChannelDescriptions = channels;
- for (i = 0; i < 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_DEBUG_OBJECT (osxbuf, "Setting format for AudioUnit");
-
- scope = osxbuf->is_src ? kAudioUnitScope_Output : kAudioUnitScope_Input;
- element = osxbuf->is_src ? 1 : 0;
-
- propertySize = sizeof (AudioStreamBasicDescription);
- status = AudioUnitSetProperty (osxbuf->audiounit,
- kAudioUnitProperty_StreamFormat, scope, element, &format, propertySize);
-
- if (status) {
- GST_WARNING_OBJECT (osxbuf,
- "Failed to set audio description: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- goto done;
- }
-
- if (layoutSize) {
- status = AudioUnitSetProperty (osxbuf->audiounit,
- kAudioUnitProperty_AudioChannelLayout,
- scope, element, layout, layoutSize);
- if (status) {
- GST_WARNING_OBJECT (osxbuf,
- "Failed to set output channel layout: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- goto done;
- }
- }
-
- /* 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: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- goto done;
- }
-
- osxbuf->recBufferList = buffer_list_alloc (channels,
- frameSize * format.mBytesPerFrame);
- }
-
- /* Specify which device we're using. */
- GST_DEBUG_OBJECT (osxbuf, "Bind AudioUnit to device %d",
- (int) osxbuf->device_id);
- status = AudioUnitSetProperty (osxbuf->audiounit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, /* N/A for global */
- &osxbuf->device_id, sizeof (AudioDeviceID));
- if (status) {
- GST_ERROR_OBJECT (osxbuf, "Failed binding to device: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- goto audiounit_error;
- }
-
- /* Initialize the AudioUnit */
- status = AudioUnitInitialize (osxbuf->audiounit);
- if (status) {
- GST_ERROR_OBJECT (osxbuf, "Failed to initialise AudioUnit: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- goto audiounit_error;
- }
-
- GST_DEBUG_OBJECT (osxbuf, "osx ring buffer acquired");
-
- ret = TRUE;
-
-done:
- g_free (layout);
- return ret;
-
-audiounit_error:
- if (osxbuf->recBufferList) {
- buffer_list_free (osxbuf->recBufferList);
- osxbuf->recBufferList = NULL;
- }
- return ret;
+ return gst_core_audio_close (osxbuf->core_audio);
}
static gboolean
gst_osx_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{
- gboolean ret = FALSE;
+ gboolean ret = FALSE, is_passthrough = FALSE;
GstOsxRingBuffer *osxbuf;
AudioStreamBasicDescription format;
@@ -865,7 +193,7 @@ gst_osx_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
format.mReserved = 0;
spec->segsize = 6144;
spec->segtotal = 10;
- osxbuf->is_passthrough = TRUE;
+ is_passthrough = TRUE;
} else {
int width, depth;
/* Fill out the audio description we're going to be using */
@@ -897,8 +225,7 @@ gst_osx_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
(spec->latency_time * spec->rate / G_USEC_PER_SEC) *
spec->bytes_per_sample;
spec->segtotal = spec->buffer_time / spec->latency_time;
- osxbuf->stream_idx = 0;
- osxbuf->is_passthrough = FALSE;
+ is_passthrough = FALSE;
}
GST_DEBUG_OBJECT (osxbuf, "Format: " CORE_AUDIO_FORMAT,
@@ -907,14 +234,8 @@ gst_osx_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
- if (osxbuf->is_passthrough) {
- ret = gst_osx_ring_buffer_acquire_spdif (osxbuf, format);
- if (ret) {
- gst_osx_ring_buffer_monitorize_spdif (osxbuf);
- }
- } else {
- ret = gst_osx_ring_buffer_acquire_analog (osxbuf, format, spec->caps);
- }
+ ret = gst_core_audio_initialize (osxbuf->core_audio, format, spec->caps,
+ is_passthrough);
if (!ret) {
gst_buffer_unref (buf->data);
@@ -933,221 +254,11 @@ gst_osx_ring_buffer_release (GstRingBuffer * buf)
osxbuf = GST_OSX_RING_BUFFER (buf);
- AudioUnitUninitialize (osxbuf->audiounit);
+ gst_core_audio_unitialize (osxbuf->core_audio);
gst_buffer_unref (buf->data);
buf->data = NULL;
- if (osxbuf->recBufferList) {
- buffer_list_free (osxbuf->recBufferList);
- osxbuf->recBufferList = NULL;
- }
-
- return TRUE;
-}
-
-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 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 %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- }
-
- /* 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 %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
-
- /* We're deactivated.. */
- osxbuf->io_proc_needs_deactivation = FALSE;
- osxbuf->io_proc_active = FALSE;
-}
-
-static gboolean
-gst_osx_ring_buffer_io_proc_start (GstOsxRingBuffer * osxbuf)
-{
- OSStatus status;
- AURenderCallbackStruct input;
- AudioUnitPropertyID callback_type;
-
- GST_DEBUG ("osx ring buffer start ioproc: %p device_id %lu",
- osxbuf->element->io_proc, (gulong) osxbuf->device_id);
- if (!osxbuf->io_proc_active) {
- 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_ERROR ("AudioUnitSetProperty failed: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (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_ERROR ("AudioUnitAddRenderNotify failed %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return FALSE;
- }
-
- osxbuf->io_proc_active = TRUE;
- }
-
- osxbuf->io_proc_needs_deactivation = FALSE;
-
- status = AudioOutputUnitStart (osxbuf->audiounit);
- if (status) {
- GST_ERROR ("AudioOutputUnitStart failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-gst_osx_ring_buffer_io_proc_stop (GstOsxRingBuffer * osxbuf)
-{
- OSErr status;
-
- GST_DEBUG ("osx ring buffer stop ioproc: %p device_id %lu",
- osxbuf->element->io_proc, (gulong) osxbuf->device_id);
-
- status = AudioOutputUnitStop (osxbuf->audiounit);
- if (status) {
- GST_WARNING ("AudioOutputUnitStop failed: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
- // ###: why is it okay to directly remove from here but not from pause() ?
- if (osxbuf->io_proc_active) {
- gst_osx_ring_buffer_remove_render_callback (osxbuf);
- }
- return TRUE;
-}
-
-static void
-gst_osx_ring_buffer_remove_render_spdif_callback (GstOsxRingBuffer * osxbuf)
-{
- OSStatus status;
-
- /* Deactivate the render callback by calling
- * AudioDeviceDestroyIOProcID */
- status = AudioDeviceDestroyIOProcID (osxbuf->device_id, osxbuf->procID);
- if (status != noErr) {
- GST_ERROR ("AudioDeviceDestroyIOProcID failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- }
-
- GST_DEBUG ("osx ring buffer removed ioproc ID: %p device_id %lu",
- osxbuf->procID, (gulong) osxbuf->device_id);
-
- /* We're deactivated.. */
- osxbuf->procID = 0;
- osxbuf->io_proc_needs_deactivation = FALSE;
- osxbuf->io_proc_active = FALSE;
-}
-
-static gboolean
-gst_osx_ring_buffer_io_proc_spdif_start (GstOsxRingBuffer * osxbuf)
-{
- OSErr status;
-
- GST_DEBUG ("osx ring buffer start ioproc ID: %p device_id %lu",
- osxbuf->procID, (gulong) osxbuf->device_id);
-
- if (!osxbuf->io_proc_active) {
- /* Add IOProc callback */
- status = AudioDeviceCreateIOProcID (osxbuf->device_id,
- (AudioDeviceIOProc) gst_osx_ring_buffer_io_proc_spdif,
- (void *) osxbuf, &osxbuf->procID);
- if (status != noErr) {
- GST_ERROR ("AudioDeviceCreateIOProcID failed: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return FALSE;
- }
- osxbuf->io_proc_active = TRUE;
- }
-
- osxbuf->io_proc_needs_deactivation = FALSE;
-
- /* Start device */
- status = AudioDeviceStart (osxbuf->device_id, osxbuf->procID);
- if (status != noErr) {
- GST_ERROR ("AudioDeviceStart failed: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-gst_osx_ring_buffer_io_proc_spdif_stop (GstOsxRingBuffer * osxbuf)
-{
- OSErr status;
-
- /* Stop device */
- status = AudioDeviceStop (osxbuf->device_id, osxbuf->procID);
- if (status != noErr) {
- GST_ERROR ("AudioDeviceStop failed: %" GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS (status));
- }
-
- GST_DEBUG ("osx ring buffer stop ioproc ID: %p device_id %lu",
- osxbuf->procID, (gulong) osxbuf->device_id);
-
- if (osxbuf->io_proc_active) {
- gst_osx_ring_buffer_remove_render_spdif_callback (osxbuf);
- }
-
- gst_osx_ring_buffer_close_spdif (osxbuf);
-
return TRUE;
}
@@ -1158,11 +269,7 @@ gst_osx_ring_buffer_start (GstRingBuffer * buf)
osxbuf = GST_OSX_RING_BUFFER (buf);
- if (osxbuf->is_passthrough) {
- return gst_osx_ring_buffer_io_proc_spdif_start (osxbuf);
- } else {
- return gst_osx_ring_buffer_io_proc_start (osxbuf);
- }
+ return gst_core_audio_start_processing (osxbuf->core_audio);
}
static gboolean
@@ -1170,25 +277,7 @@ gst_osx_ring_buffer_pause (GstRingBuffer * buf)
{
GstOsxRingBuffer *osxbuf = GST_OSX_RING_BUFFER (buf);
- if (osxbuf->is_passthrough) {
- GST_DEBUG ("osx ring buffer pause ioproc ID: %p device_id %lu",
- osxbuf->procID, (gulong) osxbuf->device_id);
-
- if (osxbuf->io_proc_active) {
- gst_osx_ring_buffer_remove_render_spdif_callback (osxbuf);
- }
- } else {
- GST_DEBUG ("osx ring buffer pause ioproc: %p device_id %lu",
- osxbuf->element->io_proc, (gulong) osxbuf->device_id);
- if (osxbuf->io_proc_active) {
- /* 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;
+ return gst_core_audio_pause_processing (osxbuf->core_audio);
}
@@ -1199,11 +288,7 @@ gst_osx_ring_buffer_stop (GstRingBuffer * buf)
osxbuf = GST_OSX_RING_BUFFER (buf);
- if (osxbuf->is_passthrough) {
- gst_osx_ring_buffer_io_proc_spdif_stop (osxbuf);
- } else {
- gst_osx_ring_buffer_io_proc_stop (osxbuf);
- }
+ gst_core_audio_stop_processing (osxbuf->core_audio);
return TRUE;
}
@@ -1211,29 +296,15 @@ gst_osx_ring_buffer_stop (GstRingBuffer * buf)
static guint
gst_osx_ring_buffer_delay (GstRingBuffer * buf)
{
- double latency;
- UInt32 size = sizeof (double);
GstOsxRingBuffer *osxbuf;
- OSStatus status;
+ double latency;
guint samples;
osxbuf = GST_OSX_RING_BUFFER (buf);
- if (osxbuf->is_passthrough) {
- samples = _audio_device_get_latency (osxbuf->device_id);
- samples += _audio_stream_get_latency (osxbuf->stream_id);
- latency = (double) samples / GST_RING_BUFFER (buf)->spec.rate;
- } else {
- 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: %"
- GST_FOURCC_FORMAT, GST_FOURCC_ARGS (status));
- return 0;
- }
-
- samples = latency * GST_RING_BUFFER (buf)->spec.rate;
+ if (!gst_core_audio_get_samples_and_latency (osxbuf->core_audio,
+ GST_RING_BUFFER (buf)->spec.rate, &samples, &latency)) {
+ return 0;
}
GST_DEBUG_OBJECT (buf, "Got latency: %f seconds -> %d samples",
latency, samples);
diff --git a/sys/osxaudio/gstosxringbuffer.h b/sys/osxaudio/gstosxringbuffer.h
index 4394fa64f..3f24d386b 100644
--- a/sys/osxaudio/gstosxringbuffer.h
+++ b/sys/osxaudio/gstosxringbuffer.h
@@ -45,12 +45,14 @@
#ifndef __GST_OSX_RING_BUFFER_H__
#define __GST_OSX_RING_BUFFER_H__
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
#include <gst/gst.h>
#include <gst/audio/gstringbuffer.h>
-#include <CoreAudio/CoreAudio.h>
-#include <AudioToolbox/AudioToolbox.h>
+#include <gstosxcoreaudio.h>
-#include "gstosxaudioelement.h"
G_BEGIN_DECLS
@@ -76,30 +78,10 @@ struct _GstOsxRingBuffer
{
GstRingBuffer object;
- gboolean is_src;
- gboolean is_passthrough;
- gint stream_idx;
+ GstCoreAudio *core_audio;
- AudioDeviceID device_id;
- gboolean io_proc_active;
- gboolean io_proc_needs_deactivation;
guint buffer_len;
guint segoffset;
-
- GstOsxAudioElementInterface *element;
-
- /* For LPCM in/out */
- AudioUnit audiounit;
- AudioBufferList *recBufferList;
-
- /* For SPDIF out */
- pid_t hog_pid;
- gboolean disabled_mixing;
- AudioStreamID stream_id;
- gboolean revert_format;
- AudioStreamBasicDescription stream_format;
- AudioStreamBasicDescription original_format;
- AudioDeviceIOProcID procID;
};
struct _GstOsxRingBufferClass