2 * Copyright (C) 2016 Hyunjun Ko <zzoon@igalia.com>
4 * gstosxaudiodeviceprovider.c: OSX audio device probing and monitoring
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
27 #include <gst/audio/audio.h>
28 #include "gstosxaudiosrc.h"
29 #include "gstosxaudiosink.h"
30 #include "gstosxaudiodeviceprovider.h"
32 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
35 GST_STATIC_CAPS (GST_OSX_AUDIO_SRC_CAPS)
38 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
41 GST_STATIC_CAPS (GST_OSX_AUDIO_SINK_CAPS)
44 static GstOsxAudioDevice *gst_osx_audio_device_new (AudioDeviceID device_id,
45 const gchar * device_name, GstOsxAudioDeviceType type,
46 GstCoreAudio * core_audio);
48 G_DEFINE_TYPE (GstOsxAudioDeviceProvider, gst_osx_audio_device_provider,
49 GST_TYPE_DEVICE_PROVIDER);
51 static GList *gst_osx_audio_device_provider_probe (GstDeviceProvider *
55 gst_osx_audio_device_provider_class_init (GstOsxAudioDeviceProviderClass *
58 GstDeviceProviderClass *dm_class = GST_DEVICE_PROVIDER_CLASS (klass);
60 dm_class->probe = gst_osx_audio_device_provider_probe;
62 gst_device_provider_class_set_static_metadata (dm_class,
63 "OSX Audio Device Provider", "Source/Sink/Audio",
64 "List and monitor OSX audio source and sink devices",
65 "Hyunjun Ko <zzoon@igalia.com>");
69 gst_osx_audio_device_provider_init (GstOsxAudioDeviceProvider * provider)
73 static GstOsxAudioDevice *
74 gst_osx_audio_device_provider_probe_device (GstOsxAudioDeviceProvider *
75 provider, AudioDeviceID device_id, const gchar * device_name,
76 GstOsxAudioDeviceType type)
78 GstOsxAudioDevice *device = NULL;
79 GstCoreAudio *core_audio;
81 core_audio = gst_core_audio_new (NULL);
82 core_audio->is_src = type == GST_OSX_AUDIO_DEVICE_TYPE_SOURCE ? TRUE : FALSE;
83 core_audio->device_id = device_id;
85 if (!gst_core_audio_open (core_audio)) {
86 GST_ERROR ("CoreAudio device could not be opened");
90 device = gst_osx_audio_device_new (device_id, device_name, type, core_audio);
92 gst_core_audio_close (core_audio);
95 g_object_unref (core_audio);
100 static inline gchar *
101 _audio_device_get_name (AudioDeviceID device_id, gboolean output)
103 OSStatus status = noErr;
104 UInt32 propertySize = 0;
105 gchar *device_name = NULL;
106 AudioObjectPropertyScope prop_scope;
108 AudioObjectPropertyAddress deviceNameAddress = {
109 kAudioDevicePropertyDeviceName,
110 kAudioDevicePropertyScopeOutput,
111 kAudioObjectPropertyElementMaster
114 prop_scope = output ? kAudioDevicePropertyScopeOutput :
115 kAudioDevicePropertyScopeInput;
117 deviceNameAddress.mScope = prop_scope;
119 /* Get the length of the device name */
120 status = AudioObjectGetPropertyDataSize (device_id,
121 &deviceNameAddress, 0, NULL, &propertySize);
122 if (status != noErr) {
126 /* Get the name of the device */
127 device_name = (gchar *) g_malloc (propertySize);
128 status = AudioObjectGetPropertyData (device_id,
129 &deviceNameAddress, 0, NULL, &propertySize, device_name);
130 if (status != noErr) {
131 g_free (device_name);
139 static inline gboolean
140 _audio_device_has_output (AudioDeviceID device_id)
142 OSStatus status = noErr;
145 AudioObjectPropertyAddress streamsAddress = {
146 kAudioDevicePropertyStreams,
147 kAudioDevicePropertyScopeOutput,
148 kAudioObjectPropertyElementMaster
151 status = AudioObjectGetPropertyDataSize (device_id,
152 &streamsAddress, 0, NULL, &propertySize);
153 if (status != noErr) {
156 if (propertySize == 0) {
163 static inline AudioDeviceID *
164 _audio_system_get_devices (gint * ndevices)
166 OSStatus status = noErr;
167 UInt32 propertySize = 0;
168 AudioDeviceID *devices = NULL;
170 AudioObjectPropertyAddress audioDevicesAddress = {
171 kAudioHardwarePropertyDevices,
172 kAudioObjectPropertyScopeGlobal,
173 kAudioObjectPropertyElementMaster
176 status = AudioObjectGetPropertyDataSize (kAudioObjectSystemObject,
177 &audioDevicesAddress, 0, NULL, &propertySize);
178 if (status != noErr) {
179 GST_WARNING ("failed getting number of devices: %d", (int) status);
183 *ndevices = propertySize / sizeof (AudioDeviceID);
185 devices = (AudioDeviceID *) g_malloc (propertySize);
187 status = AudioObjectGetPropertyData (kAudioObjectSystemObject,
188 &audioDevicesAddress, 0, NULL, &propertySize, devices);
189 if (status != noErr) {
190 GST_WARNING ("failed getting the list of devices: %d", (int) status);
201 gst_osx_audio_device_provider_probe (GstDeviceProvider * provider)
203 GstOsxAudioDeviceProvider *self = GST_OSX_AUDIO_DEVICE_PROVIDER (provider);
204 GList *devices = NULL;
205 GstOsxAudioDevice *device = NULL;
206 AudioDeviceID *osx_devices = NULL;
207 gint i, ndevices = 0;
209 osx_devices = _audio_system_get_devices (&ndevices);
212 GST_WARNING ("no audio output devices found");
216 GST_INFO ("found %d audio device(s)", ndevices);
218 for (i = 0; i < ndevices; i++) {
220 GstOsxAudioDeviceType type = GST_OSX_AUDIO_DEVICE_TYPE_INVALID;
222 if ((device_name = _audio_device_get_name (osx_devices[i], FALSE))) {
223 if (!_audio_device_has_output (osx_devices[i])) {
224 GST_DEBUG ("Input Device ID: %u Name: %s",
225 (unsigned) osx_devices[i], device_name);
226 type = GST_OSX_AUDIO_DEVICE_TYPE_SOURCE;
229 GST_DEBUG ("Output Device ID: %u Name: %s",
230 (unsigned) osx_devices[i], device_name);
231 type = GST_OSX_AUDIO_DEVICE_TYPE_SINK;
235 gst_osx_audio_device_provider_probe_device (self, osx_devices[i],
238 gst_object_ref_sink (device);
239 devices = g_list_prepend (devices, device);
242 g_free (device_name);
247 g_free (osx_devices);
257 G_DEFINE_TYPE (GstOsxAudioDevice, gst_osx_audio_device, GST_TYPE_DEVICE);
259 static void gst_osx_audio_device_get_property (GObject * object, guint prop_id,
260 GValue * value, GParamSpec * pspec);
261 static void gst_osx_audio_device_set_property (GObject * object, guint prop_id,
262 const GValue * value, GParamSpec * pspec);
263 static GstElement *gst_osx_audio_device_create_element (GstDevice * device,
267 gst_osx_audio_device_class_init (GstOsxAudioDeviceClass * klass)
269 GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass);
270 GObjectClass *object_class = G_OBJECT_CLASS (klass);
272 dev_class->create_element = gst_osx_audio_device_create_element;
274 object_class->get_property = gst_osx_audio_device_get_property;
275 object_class->set_property = gst_osx_audio_device_set_property;
277 g_object_class_install_property (object_class, PROP_DEVICE_ID,
278 g_param_spec_int ("device-id", "Device ID", "Device ID of input device",
279 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
283 gst_osx_audio_device_init (GstOsxAudioDevice * device)
288 gst_osx_audio_device_create_element (GstDevice * device, const gchar * name)
290 GstOsxAudioDevice *osxdev = GST_OSX_AUDIO_DEVICE (device);
293 elem = gst_element_factory_make (osxdev->element, name);
294 g_object_set (elem, "device", osxdev->device_id, NULL);
299 static GstOsxAudioDevice *
300 gst_osx_audio_device_new (AudioDeviceID device_id, const gchar * device_name,
301 GstOsxAudioDeviceType type, GstCoreAudio * core_audio)
303 GstOsxAudioDevice *gstdev;
304 const gchar *element_name = NULL;
305 const gchar *klass = NULL;
306 GstCaps *template_caps, *caps;
308 g_return_val_if_fail (device_id > 0, NULL);
309 g_return_val_if_fail (device_name, NULL);
312 case GST_OSX_AUDIO_DEVICE_TYPE_SOURCE:
313 element_name = "osxaudiosrc";
314 klass = "Audio/Source";
316 template_caps = gst_static_pad_template_get_caps (&src_factory);
317 caps = gst_core_audio_probe_caps (core_audio, template_caps);
318 gst_caps_unref (template_caps);
321 case GST_OSX_AUDIO_DEVICE_TYPE_SINK:
322 element_name = "osxaudiosink";
323 klass = "Audio/Sink";
325 template_caps = gst_static_pad_template_get_caps (&sink_factory);
326 caps = gst_core_audio_probe_caps (core_audio, template_caps);
327 gst_caps_unref (template_caps);
331 g_assert_not_reached ();
335 gstdev = g_object_new (GST_TYPE_OSX_AUDIO_DEVICE, "device-id",
336 device_id, "display-name", device_name, "caps", caps, "device-class",
339 gstdev->element = element_name;
346 gst_osx_audio_device_get_property (GObject * object, guint prop_id,
347 GValue * value, GParamSpec * pspec)
349 GstOsxAudioDevice *device;
351 device = GST_OSX_AUDIO_DEVICE_CAST (object);
355 g_value_set_int (value, device->device_id);
358 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
365 gst_osx_audio_device_set_property (GObject * object, guint prop_id,
366 const GValue * value, GParamSpec * pspec)
368 GstOsxAudioDevice *device;
370 device = GST_OSX_AUDIO_DEVICE_CAST (object);
374 device->device_id = g_value_get_int (value);
377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);