<p>This file documents recent user-visible changes to <a
href="http://www.greenend.org.uk/rjk/disorder/">DisOrder</a>.</p>
+<h2>Changes up to version 4.4</h2>
+
+ <div class=section>
+
+ <h3>Mac OS X</h3>
+
+ <div class=section>
+
+ <p>The <tt>device</tt> configuration option and <tt>--device</tt> option
+ to <tt>disorder-playrtp</tt> now work. Devices may be specified either
+ by UID or name. Fixes <a
+ href="http://code.google.com/p/disorder/issues/detail?id=27">Issue
+ 27</a>.</p>
+
+ </div>
+
+ <h3>Bugs fixed</h3>
+
+ <div class=section>
+
+ <table class=bugs>
+ <tr>
+ <th>ID</th>
+ <th>Description</th>
+ </tr>
+
+ <tr>
+ <td><a href="http://code.google.com/p/disorder/issues/detail?id=27">#27</a></td>
+ <td>Mac DisOrder uses wrong sound device</td>
+ </tr>
+
+ </table>
+
+ </div>
+ </div>
+
<h2>Changes up to version 4.3</h2>
<div class=section>
#if HAVE_COREAUDIO_AUDIOHARDWARE_H
#include <pthread.h>
-#include <CoreAudio/AudioHardware.h>
#include "mem.h"
#include "log.h"
#include "vector.h"
#include "heap.h"
#include "playrtp.h"
+#include "coreaudio.h"
/** @brief Callback from Core Audio */
static OSStatus adioproc
* excellent reason for that... */
/* TODO report errors as strings not numbers */
- propertySize = sizeof adid;
- status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
- &propertySize, &adid);
- if(status)
- fatal(0, "AudioHardwareGetProperty: %d", (int)status);
- if(adid == kAudioDeviceUnknown)
- fatal(0, "no output device");
+ /* Identify the device to use */
+ adid = coreaudio_getdevice(device);
propertySize = sizeof asbd;
status = AudioDeviceGetProperty(adid, 0, false,
kAudioDevicePropertyStreamFormat,
*-apple-darwin* )
AC_MSG_RESULT([Mac OS X])
if test $want_coreaudio = yes; then
- COREAUDIO="-framework CoreAudio"
+ COREAUDIO="-framework CoreFoundation -framework CoreAudio"
fi
browser=open
AC_MSG_CHECKING([Mac OS X target version])
.TP
.B \-\-device \fIDEVICE\fR, \fB\-D \fIDEVICE\fR
Specifies the audio device to use.
-The exact meaning of this is platform-dependent; on Linux it is the
-ALSA device name.
+See
+.B "DEVICE NAMES"
+below for more information.
.TP
.B \-\-config \fIPATH\fR, \fB\-C \fIPATH
Set the configuration file.
Only one connection at a time will be serviced.
.PP
This protocol is not guaranteed to be stable.
+.SH "DEVICE NAMES"
+.SS "Core Audio"
+On a Mac, the device name can either be the human-readable name of the desired
+output or its UID.
+To get a list of the human-readable names, visit System Preferences -> Sound;
+the Type column has the name you want.
+.PP
+For example, you might use "Built-in Output" for the built-in speaker
+or "Built-in Line Output" if you have connected external speakers.
+Remember to quote the name.
.SH "SEE ALSO"
.BR disobedience (1),
.BR disorder_config (5),
.IP
For \fBapi alsa\fR this is the device name to use.
.IP
-For \fBapi coreaudio\fR this is currently ignored.
+For \fBapi coreaudio\fR this can be either the UID or the human-readable
+name of the desired device.
+For a list of names, visit System Preferences -> Sound and look at the Type column.
+For example, you might use "Built-in Output" for the built-in speaker
+or "Built-in Line Output" if you have connected external speakers.
+Remember to quote the name.
.IP
The default is \fBdefault\fR, which is intended to map to whatever the system's
default is.
client-common.c client-common.h \
configuration.c configuration.h \
cookies.c cookies.h \
+ coreaudio.c coreaudio.h \
dateparse.c dateparse.h xgetdate.c \
defs.c defs.h \
eclient.c eclient.h \
--- /dev/null
+/*
+ * 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:
+*/
--- /dev/null
+/*
+ * 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.h
+ * @brief Support for @ref BACKEND_COREAUDIO
+ */
+
+#ifndef COREAUDIO_H
+#define COREAUDIO_H
+
+#include <CoreAudio/AudioHardware.h>
+
+AudioDeviceID coreaudio_getdevice(const char *name);
+
+#endif /* COREAUDIO_H */
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
#include <poll.h>
#include <sys/socket.h>
#include <unistd.h>
-#include <CoreAudio/AudioHardware.h>
#include "configuration.h"
#include "syscalls.h"
#include "log.h"
#include "speaker-protocol.h"
#include "speaker.h"
+#include "coreaudio.h"
/** @brief Core Audio Device ID */
static AudioDeviceID adid;
UInt32 propertySize;
AudioStreamBasicDescription asbd;
- propertySize = sizeof adid;
- status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
- &propertySize, &adid);
- if(status)
- fatal(0, "AudioHardwareGetProperty: %d", (int)status);
- if(adid == kAudioDeviceUnknown)
- fatal(0, "no output device");
+ adid = coreaudio_getdevice(config->device);
propertySize = sizeof asbd;
status = AudioDeviceGetProperty(adid, 0, false,
kAudioDevicePropertyStreamFormat,