chiark / gitweb /
Support arbitrary Core Audio devices.
[disorder] / lib / coreaudio.c
diff --git a/lib/coreaudio.c b/lib/coreaudio.c
new file mode 100644 (file)
index 0000000..c8732d5
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * This file is part of DisOrder
+ * Copyright (C) 2009 Richard Kettlewell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @file lib/coreaudio.c
+ * @brief Support for @ref BACKEND_COREAUDIO
+ */
+
+#include "common.h"
+
+#if HAVE_COREAUDIO_AUDIOHARDWARE_H
+
+#include "coreaudio.h"
+#include "log.h"
+#include <CoreFoundation/CFString.h>
+
+/** @brief Return the default device ID */
+static AudioDeviceID coreaudio_use_default(void) {
+  OSStatus status;
+  UInt32 propertySize;
+  AudioDeviceID adid;
+
+  /* TODO should we use kAudioHardwarePropertyDefaultSystemOutputDevice
+   * instead?  It is listed in the enumeration but is not documented, so we
+   * leave it alone until better information is available. */
+  propertySize = sizeof adid;
+  status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
+                                    &propertySize, &adid);
+  if(status)
+    fatal(0, "AudioHardwareGetProperty kAudioHardwarePropertyDefaultOutputDevice: %d", (int)status);
+  if(adid == kAudioDeviceUnknown)
+    fatal(0, "no output device");
+  return adid;
+}
+
+/** @brief Find a device by some string
+ * @param selector Selector for property to look for
+ * @param description Property description
+ * @param devs List of device IDs
+ * @param ndevs Number of device IDs in @p devs
+ * @param resultp Where to put device ID
+ * @return 1 if found, 0 if not found
+ */
+static int coreaudio_find_device(AudioObjectPropertySelector selector,
+                                 //const char *description,
+                                 const AudioDeviceID *devs,
+                                 unsigned ndevs,
+                                 CFStringRef dev,
+                                 AudioDeviceID *resultp) {
+  OSStatus status;
+  UInt32 propertySize;
+
+  for(unsigned n = 0; n < ndevs; ++n) {
+    CFStringRef name;
+    propertySize = sizeof name;
+    status = AudioDeviceGetProperty(devs[n], 0, FALSE,
+                                    selector,
+                                    &propertySize, &name);
+    if(status)
+      fatal(0, "AudioDeviceGetProperty: %d", (int)status);
+#if 0
+    UInt8 output[1024];
+    CFIndex used;
+    CFRange r = { 0, CFStringGetLength(name) };
+    CFStringGetBytes(name, r, kCFStringEncodingUTF8,
+                     '?', FALSE, output, sizeof output,
+                     &used);
+    output[used] = 0;
+    info("device %u %s: %s", n, description, (char *)output);
+#endif
+    if(CFStringCompare(dev, name,
+                       kCFCompareCaseInsensitive|kCFCompareNonliteral)
+       == kCFCompareEqualTo) {
+      *resultp = devs[n];
+      CFRelease(name);
+      return 1;
+    }
+    CFRelease(name);
+  }
+  return 0;                             /* didn't find it */
+}
+
+/** @brief Identify audio device
+ * @param name Device name
+ * @return Device ID
+ */
+AudioDeviceID coreaudio_getdevice(const char *name) {
+  OSStatus status;
+  UInt32 propertySize;
+  int found;
+  AudioDeviceID adid;
+
+  if(!name
+     || !*name
+     || !strcmp(name, "default"))
+    return coreaudio_use_default();
+  /* Convert the configured device name to a CFString */
+  CFStringRef dev;
+  dev = CFStringCreateWithCString(NULL/*default allocator*/,
+                                  name,
+                                  kCFStringEncodingUTF8);
+  if(!dev)
+    fatal(0, "CFStringCreateWithBytes failed");
+  /* Get a list of available devices */
+  AudioDeviceID devs[1024];
+  unsigned ndevs;
+
+  propertySize = sizeof devs;
+  status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
+                                    &propertySize, devs);
+  if(status)
+    fatal(0, "AudioHardwareGetProperty kAudioHardwarePropertyDevices: %d",
+          (int)status);
+  ndevs = propertySize / sizeof *devs;
+  if(!ndevs)
+    fatal(0, "no sound devices found");
+  /* Try looking up by UID first */
+  found = coreaudio_find_device(kAudioDevicePropertyDeviceUID, //"UID",
+                                devs, ndevs, dev, &adid);
+  /* Failing that try looking up by name */
+  if(!found)
+    found = coreaudio_find_device(kAudioObjectPropertyName, //"name",
+                                  devs, ndevs, dev, &adid);
+  CFRelease(dev);
+  if(!found)
+    fatal(0, "cannot find device '%s'", name);
+  return adid;
+}
+
+#endif
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/