3 * Copyright 2005,2006 Zaheer Abbas Merali <zaheerabbas at merali dot org>
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
23 * Alternatively, the contents of this file may be used under the
24 * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
25 * which case the following provisions apply instead of the ones
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Library General Public
30 * License as published by the Free Software Foundation; either
31 * version 2 of the License, or (at your option) any later version.
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Library General Public License for more details.
38 * You should have received a copy of the GNU Library General Public
39 * License along with this library; if not, write to the
40 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
41 * Boston, MA 02111-1307, USA.
45 * SECTION:element-plugin
48 * <title>Example launch line</title>
51 * gst-launch -v -m audiotestsrc ! audioconvert ! osxaudiosink
62 #include <CoreAudio/CoreAudio.h>
63 #include "gstosxaudiosink.h"
64 #include "gstosxaudioelement.h"
66 GST_DEBUG_CATEGORY_STATIC (osx_audiosink_debug);
67 #define GST_CAT_DEFAULT osx_audiosink_debug
69 static GstElementDetails gst_osx_audio_sink_details =
70 GST_ELEMENT_DETAILS ("Audio Sink (OSX)",
72 "Output to a sound card in OS X",
73 "Zaheer Abbas Merali <zaheerabbas at merali dot org>");
75 /* Filter signals and args */
88 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
91 GST_STATIC_CAPS ("audio/x-raw-float, "
92 "endianness = (int) {" G_STRINGIFY (G_BYTE_ORDER) " }, "
93 "signed = (boolean) { TRUE }, "
94 "width = (int) 32, " "rate = (int) 44100, " "channels = (int) 2")
97 static void gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
98 const GValue * value, GParamSpec * pspec);
99 static void gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
100 GValue * value, GParamSpec * pspec);
101 static GstCaps *gst_osx_audio_sink_getcaps (GstBaseSink * sink);
104 static GstRingBuffer *gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink *
106 /*static GstCaps* gst_osx_audio_sink_getcaps (GstBaseSink * bsink);*/
107 static void gst_osx_audio_sink_osxelement_init (gpointer g_iface,
108 gpointer iface_data);
109 OSStatus gst_osx_audio_sink_io_proc (AudioDeviceID inDevice,
110 const AudioTimeStamp * inNow, const AudioBufferList * inInputData,
111 const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData,
112 const AudioTimeStamp * inOutputTime, void *inClientData);
114 gst_osx_audio_sink_osxelement_do_init (GType type)
116 static const GInterfaceInfo osxelement_info = {
117 gst_osx_audio_sink_osxelement_init,
122 GST_DEBUG_CATEGORY_INIT (osx_audiosink_debug, "osxaudiosink", 0,
124 GST_DEBUG ("Adding static interface\n");
125 g_type_add_interface_static (type, GST_OSX_AUDIO_ELEMENT_TYPE,
129 GST_BOILERPLATE_FULL (GstOsxAudioSink, gst_osx_audio_sink, GstBaseAudioSink,
130 GST_TYPE_BASE_AUDIO_SINK, gst_osx_audio_sink_osxelement_do_init)
133 static void gst_osx_audio_sink_base_init (gpointer g_class)
135 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
137 gst_element_class_add_pad_template (element_class,
138 gst_static_pad_template_get (&sink_factory));
140 gst_element_class_set_details (element_class, &gst_osx_audio_sink_details);
143 /* initialize the plugin's class */
145 gst_osx_audio_sink_class_init (GstOsxAudioSinkClass * klass)
147 GObjectClass *gobject_class;
148 GstElementClass *gstelement_class;
149 GstBaseSinkClass *gstbasesink_class;
150 GstBaseAudioSinkClass *gstbaseaudiosink_class;
152 gobject_class = (GObjectClass *) klass;
153 gstelement_class = (GstElementClass *) klass;
154 gstbasesink_class = (GstBaseSinkClass *) klass;
155 gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
157 parent_class = g_type_class_peek_parent (klass);
159 gobject_class->set_property =
160 GST_DEBUG_FUNCPTR (gst_osx_audio_sink_set_property);
161 gobject_class->get_property =
162 GST_DEBUG_FUNCPTR (gst_osx_audio_sink_get_property);
164 g_object_class_install_property (gobject_class, ARG_DEVICE,
165 g_param_spec_int ("device", "Device ID", "Device ID of output device",
166 0, G_MAXINT, 0, G_PARAM_READWRITE));
168 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_osx_audio_sink_getcaps);
169 gstbaseaudiosink_class->create_ringbuffer =
170 GST_DEBUG_FUNCPTR (gst_osx_audio_sink_create_ringbuffer);
174 /* initialize the new element
175 * instantiate pads and add them to element
177 * initialize structure
180 gst_osx_audio_sink_init (GstOsxAudioSink * sink, GstOsxAudioSinkClass * gclass)
182 /* GstElementClass *klass = GST_ELEMENT_GET_CLASS (sink); */
183 sink->ringbuffer = NULL;
184 GST_DEBUG ("Initialising object\n");
185 gst_osx_audio_sink_create_ringbuffer (sink);
190 gst_osx_audio_sink_set_property (GObject * object, guint prop_id,
191 const GValue * value, GParamSpec * pspec)
193 GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object);
197 if (sink->ringbuffer)
198 sink->ringbuffer->device_id = g_value_get_int (value);
201 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207 gst_osx_audio_sink_get_property (GObject * object, guint prop_id,
208 GValue * value, GParamSpec * pspec)
210 GstOsxAudioSink *sink = GST_OSX_AUDIO_SINK (object);
215 if (sink->ringbuffer)
216 val = sink->ringbuffer->device_id;
218 g_value_set_int (value, val);
221 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226 /* GstElement vmethod implementations */
228 /* GstBaseSink vmethod implementations */
230 gst_osx_audio_sink_getcaps (GstBaseSink * sink)
233 GstOsxAudioSink *osxsink;
235 AudioValueRange rates[10];
239 propertySize = sizeof (AudioValueRange) * 9;
240 osxsink = GST_OSX_AUDIO_SINK (sink);
242 caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
246 status = AudioDeviceGetProperty (osxsink->ringbuffer->device_id, 0, FALSE,
247 kAudioDevicePropertyAvailableNominalSampleRates, &propertySize, &rates);
250 ("Getting available sample rates: Status: %d number of ranges: %d\n",
251 status, propertySize / sizeof (AudioValueRange));
253 for (i = 0; i < propertySize / sizeof (AudioValueRange); i++) {
254 g_print ("Range from %f to %f\n", rates[i].mMinimum, rates[i].mMaximum);
260 /* GstBaseAudioSink vmethod implementations */
261 static GstRingBuffer *
262 gst_osx_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
264 GstOsxAudioSink *osxsink;
266 osxsink = GST_OSX_AUDIO_SINK (sink);
267 if (!osxsink->ringbuffer) {
268 GST_DEBUG ("Creating ringbuffer\n");
269 osxsink->ringbuffer = g_object_new (GST_TYPE_OSX_RING_BUFFER, NULL);
270 GST_DEBUG ("osx sink 0x%x element 0x%x ioproc 0x%x\n", osxsink,
271 GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink),
272 (void *) gst_osx_audio_sink_io_proc);
273 osxsink->ringbuffer->element =
274 GST_OSX_AUDIO_ELEMENT_GET_INTERFACE (osxsink);
277 return GST_RING_BUFFER (osxsink->ringbuffer);
281 gst_osx_audio_sink_io_proc (AudioDeviceID inDevice,
282 const AudioTimeStamp * inNow, const AudioBufferList * inInputData,
283 const AudioTimeStamp * inInputTime, AudioBufferList * outOutputData,
284 const AudioTimeStamp * inOutputTime, void *inClientData)
286 GstOsxRingBuffer *buf = GST_OSX_RING_BUFFER (inClientData);
292 if (gst_ring_buffer_prepare_read (GST_RING_BUFFER (buf), &readseg, &readptr,
294 outOutputData->mBuffers[0].mDataByteSize = len;
295 memcpy ((char *) outOutputData->mBuffers[0].mData, readptr, len);
297 /* clear written samples */
298 gst_ring_buffer_clear (GST_RING_BUFFER (buf), readseg);
300 /* we wrote one segment */
301 gst_ring_buffer_advance (GST_RING_BUFFER (buf), 1);
307 gst_osx_audio_sink_osxelement_init (gpointer g_iface, gpointer iface_data)
309 GstOsxAudioElementInterface *iface = (GstOsxAudioElementInterface *) g_iface;
311 iface->io_proc = gst_osx_audio_sink_io_proc;
314 /* entry point to initialize the plug-in
315 * initialize the plug-in itself
316 * register the element factories and pad templates
317 * register the features
319 * exchange the string 'plugin' with your elemnt name
322 plugin_init (GstPlugin * plugin)
324 return gst_element_register (plugin, "osxaudiosink",
325 GST_RANK_NONE, GST_TYPE_OSX_AUDIO_SINK);
328 /* this is the structure that gstreamer looks for to register plugins
330 * exchange the strings 'plugin' and 'Template plugin' with you plugin name and
333 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
337 plugin_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/")