summaryrefslogtreecommitdiffstats
path: root/sys/osxaudio/gstosxaudiosink.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/osxaudio/gstosxaudiosink.c')
-rw-r--r--sys/osxaudio/gstosxaudiosink.c216
1 files changed, 159 insertions, 57 deletions
diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c
index 222056c8..5f67bb7b 100644
--- a/sys/osxaudio/gstosxaudiosink.c
+++ b/sys/osxaudio/gstosxaudiosink.c
@@ -41,8 +41,8 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
- * The development of this code was made possible due to the involvement of Pioneers of i
- * the Inevitable, the creators of the Songbird Music player
+ * The development of this code was made possible due to the involvement of
+ * Pioneers of the Inevitable, the creators of the Songbird Music player.
*
*/
@@ -65,6 +65,7 @@
#include <gst/gst.h>
#include <CoreAudio/CoreAudio.h>
+#include <CoreAudio/AudioHardware.h>
#include "gstosxaudiosink.h"
#include "gstosxaudiosrc.h"
@@ -99,7 +100,8 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
"endianness = (int) {" G_STRINGIFY (G_BYTE_ORDER) " }, "
"signed = (boolean) { TRUE }, "
"width = (int) 32, "
- "depth = (int) 32, " "rate = (int) 44100, " "channels = (int) 2")
+ "depth = (int) 32, "
+ "rate = (int) [1, MAX], " "channels = (int) [1, 2]")
);
static void gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
@@ -108,16 +110,16 @@ static void gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstCaps *gst_osx_audio_sink_getcaps (GstBaseSink * sink);
-
static GstRingBuffer *gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink *
sink);
-/*static GstCaps* gst_osx_audio_sink_getcaps (GstBaseSink * bsink);*/
static void gst_osx_audio_sink_osxelement_init (gpointer g_iface,
gpointer iface_data);
OSStatus gst_osx_audio_sink_io_proc (AudioDeviceID inDevice,
const AudioTimeStamp * inNow, const AudioBufferList * inInputData,
const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData,
const AudioTimeStamp * inOutputTime, void *inClientData);
+static void gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink);
+
static void
gst_osx_audio_sink_osxelement_do_init (GType type)
{
@@ -189,10 +191,10 @@ static void
gst_osx_audio_sink_init (GstOsxAudioSink * sink, GstOsxAudioSinkClass * gclass)
{
/* GstElementClass *klass = GST_ELEMENT_GET_CLASS (sink); */
- sink->ringbuffer = NULL;
GST_DEBUG ("Initialising object");
- gst_osx_audio_sink_create_ringbuffer (GST_BASE_AUDIO_SINK (sink));
+ sink->device_id = kAudioDeviceUnknown;
+ sink->stream_id = kAudioStreamUnknown;
}
static void
@@ -203,8 +205,7 @@ gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
switch (prop_id) {
case ARG_DEVICE:
- if (sink->ringbuffer)
- sink->ringbuffer->device_id = g_value_get_int (value);
+ sink->device_id = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -217,14 +218,9 @@ gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object);
- int val = 0;
-
switch (prop_id) {
case ARG_DEVICE:
- if (sink->ringbuffer)
- val = sink->ringbuffer->device_id;
-
- g_value_set_int (value, val);
+ g_value_set_int (value, sink->device_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -238,32 +234,93 @@ gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
static GstCaps *
gst_osx_audio_sink_getcaps (GstBaseSink * sink)
{
- GstCaps *caps;
+ GstCaps *caps = NULL;
GstOsxAudioSink *osxsink;
OSStatus status;
- AudioValueRange rates[10];
+ AudioValueRange *rates = NULL;
UInt32 propertySize;
int i;
+ gboolean foundFixedRate = FALSE;
+ GstStructure *structure;
+ GValue rate_v = { 0 };
+ GValue rates_v = { 0 };
- propertySize = sizeof (AudioValueRange) * 9;
osxsink = GST_OSX_AUDIO_SINK (sink);
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
- (sink)));
+ gst_osx_audio_sink_select_device (osxsink);
+
+ GST_DEBUG_OBJECT (osxsink, "Using device_id %d", (int) osxsink->device_id);
+
+ status = AudioDeviceGetPropertyInfo (osxsink->device_id, 0, /* Master channel */
+ FALSE, /* isInput */
+ kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, NULL);
+
+ if (status) {
+ GST_WARNING_OBJECT (osxsink, "Failed to get sample rates size: %ld",
+ status);
+ goto done;
+ }
+ GST_DEBUG_OBJECT (osxsink, "Allocating %d bytes for sizes",
+ (int) propertySize);
+ rates = g_malloc (propertySize);
- status = AudioDeviceGetProperty (osxsink->ringbuffer->device_id, 0, FALSE,
- kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, &rates);
+ status = AudioDeviceGetProperty (osxsink->device_id, 0, /* Master channel */
+ FALSE, /* isInput */
+ kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, rates);
+
+ if (status) {
+ GST_WARNING_OBJECT (osxsink, "Failed to get sample rates: %ld", status);
+ goto done;
+ }
+
+ GST_DEBUG_OBJECT (osxsink, "Used %d bytes for sizes", (int) propertySize);
+
+ if (propertySize < sizeof (AudioValueRange)) {
+ GST_WARNING_OBJECT (osxsink, "Zero sample rates available");
+ goto done;
+ }
+
+ /* Create base caps object, then modify to suit. */
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
+ (sink)));
+ structure = gst_caps_get_structure (caps, 0);
GST_DEBUG
("Getting available sample rates: Status: %ld number of ranges: %lu",
status, propertySize / sizeof (AudioValueRange));
+ g_value_init (&rates_v, GST_TYPE_LIST);
+ g_value_init (&rate_v, G_TYPE_INT);
+
for (i = 0; i < propertySize / sizeof (AudioValueRange); i++) {
GST_LOG_OBJECT (osxsink, "Range from %f to %f", rates[i].mMinimum,
rates[i].mMaximum);
+ if (rates[i].mMinimum == rates[i].mMaximum) {
+ /* For now, we only support these in this form. If there are none
+ * in this form, we use the first (only) as a range. */
+ foundFixedRate = TRUE;
+
+ g_value_set_int (&rate_v, rates[i].mMinimum);
+ gst_value_list_append_value (&rates_v, &rate_v);
+ }
}
+ g_value_unset (&rate_v);
+
+ if (foundFixedRate) {
+ gst_structure_set_value (structure, "rate", &rates_v);
+ } else {
+ gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE,
+ rates[0].mMinimum, rates[0].mMaximum, NULL);
+ }
+
+ g_value_unset (&rates_v);
+
+done:
+ if (rates)
+ g_free (rates);
+
return caps;
}
@@ -272,19 +329,22 @@ static GstRingBuffer *
gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
{
GstOsxAudioSink *osxsink;
+ GstOsxRingBuffer *ringbuffer;
osxsink = GST_OSX_AUDIO_SINK (sink);
- if (!osxsink->ringbuffer) {
- GST_DEBUG ("Creating ringbuffer");
- osxsink->ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL);
- GST_DEBUG ("osx sink 0x%p element 0x%p ioproc 0x%p", osxsink,
- GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink),
- (void *) gst_osx_audio_sink_io_proc);
- osxsink->ringbuffer->element =
- GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink);
- }
- return GST_RING_BUFFER (osxsink->ringbuffer);
+ gst_osx_audio_sink_select_device (osxsink);
+
+ GST_DEBUG ("Creating ringbuffer");
+ ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL);
+ GST_DEBUG ("osx sink 0x%p element 0x%p ioproc 0x%p", osxsink,
+ GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink),
+ (void *) gst_osx_audio_sink_io_proc);
+ ringbuffer->element = GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink);
+ ringbuffer->device_id = osxsink->device_id;
+ ringbuffer->stream_id = osxsink->stream_id;
+
+ return GST_RING_BUFFER (ringbuffer);
}
OSStatus
@@ -321,31 +381,73 @@ gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data)
iface->io_proc = gst_osx_audio_sink_io_proc;
}
-/* entry point to initialize the plug-in
- * initialize the plug-in itself
- * register the element factories and pad templates
- * register the features
- *
- * exchange the string 'plugin' with your elemnt name
- */
-static gboolean
-plugin_init (GstPlugin * plugin)
+
+static void
+gst_osx_audio_sink_select_device (GstOsxAudioSink * osxsink)
{
- gboolean ret;
+ OSStatus status;
+ UInt32 propertySize;
- ret = gst_element_register (plugin, "osxaudiosink",
- GST_RANK_PRIMARY, GST_TYPE_OSX_AUDIO_SINK);
- return ret && gst_element_register (plugin, "osxaudiosrc",
- GST_RANK_PRIMARY, GST_TYPE_OSX_AUDIO_SRC);
-}
+ if (osxsink->device_id == kAudioDeviceUnknown) {
+ GST_DEBUG_OBJECT (osxsink, "Selecting device for OSXAudioSink");
+ propertySize = sizeof (osxsink->device_id);
+ status =
+ AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
+ &propertySize, &osxsink->device_id);
+
+ if (status)
+ GST_WARNING_OBJECT (osxsink,
+ "AudioHardwareGetProperty returned %d", (int) status);
+ else
+ GST_DEBUG_OBJECT (osxsink, "AudioHardwareGetProperty returned 0");
+
+ if (osxsink->device_id == kAudioDeviceUnknown)
+ GST_WARNING_OBJECT (osxsink,
+ "AudioHardwareGetProperty: device_id is kAudioDeviceUnknown");
+
+ GST_DEBUG_OBJECT (osxsink, "AudioHardwareGetProperty: device_id is %lu",
+ (long) osxsink->device_id);
+ }
-/* this is the structure that gstreamer looks for to register plugins
- *
- * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
- * description
- */
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "osxaudio",
- "OSX Audio plugin",
- plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")
+ if (osxsink->stream_id == kAudioStreamUnknown) {
+ AudioStreamID *streams;
+
+ GST_DEBUG_OBJECT (osxsink, "Getting streamid");
+ status = AudioDeviceGetPropertyInfo (osxsink->device_id, 0, /* Master channel */
+ FALSE, /* isInput */
+ kAudioDevicePropertyStreams, &propertySize, NULL);
+
+ if (status) {
+ GST_WARNING_OBJECT (osxsink,
+ "AudioDeviceGetProperty returned %d", (int) status);
+ return;
+ }
+
+ GST_DEBUG_OBJECT (osxsink,
+ "Getting available streamids from %d (%d bytes)",
+ (int) (propertySize / sizeof (AudioStreamID)), propertySize);
+ streams = g_malloc (propertySize);
+ status = AudioDeviceGetProperty (osxsink->device_id, 0, /* Master channel */
+ FALSE, /* isInput */
+ kAudioDevicePropertyStreams, &propertySize, streams);
+
+ if (status) {
+ GST_WARNING_OBJECT (osxsink,
+ "AudioDeviceGetProperty returned %d", (int) status);
+ g_free (streams);
+ return;
+ }
+
+ GST_DEBUG_OBJECT (osxsink, "Getting streamid from %d (%d bytes)",
+ (int) (propertySize / sizeof (AudioStreamID)), propertySize);
+
+ if (propertySize >= sizeof (AudioStreamID)) {
+ osxsink->stream_id = streams[0];
+ GST_DEBUG_OBJECT (osxsink, "Selected stream %d of %d: %d", 0,
+ (int) (propertySize / sizeof (AudioStreamID)),
+ (int) osxsink->stream_id);
+ }
+
+ g_free (streams);
+ }
+}