summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2015-02-03 00:28:54 +0100
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2015-02-03 00:40:02 +0100
commitde4f9977528e454c44f980a4364ecd18d3219c62 (patch)
tree323c54565b1ead914d59a4826f09b8cecccef91c
parenta3be14683a33211e3e07094246bb3342fc789763 (diff)
downloadmpv-de4f9977528e454c44f980a4364ecd18d3219c62.tar.bz2
mpv-de4f9977528e454c44f980a4364ecd18d3219c62.tar.xz
ao_coreaudio: use device UID instead of ID for selection
Previously we let the user use the audio device ID, but this is not persistent and can change when plugging in new devices. That of course made it quite worthless for storing it as a user setting for GUIs, or for user scripts. In theory getting the kAudioDevicePropertyDeviceUID can fail but it doesn't on any of my devices, so I'm leaving the error reporting quite high and see if someone complains.
-rw-r--r--audio/out/ao_coreaudio.c5
-rw-r--r--audio/out/ao_coreaudio_properties.c7
-rw-r--r--audio/out/ao_coreaudio_utils.c50
-rw-r--r--audio/out/ao_coreaudio_utils.h3
4 files changed, 46 insertions, 19 deletions
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 590549bd1a..0eab220421 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -156,7 +156,10 @@ static int init(struct ao *ao)
OSStatus err = ca_select_device(ao, ao->device, &p->device);
CHECK_CA_ERROR("failed to select device");
- ao->detected_device = talloc_asprintf(ao, "%d", p->device);
+ char *uid;
+ err = CA_GET_STR(p->device, kAudioDevicePropertyDeviceUID, &uid);
+ CHECK_CA_ERROR("failed to get device UID");
+ ao->detected_device = talloc_steal(ao, uid);
if (!init_chmap(ao))
goto coreaudio_error;
diff --git a/audio/out/ao_coreaudio_properties.c b/audio/out/ao_coreaudio_properties.c
index 181d338cbd..cf2b4d14a1 100644
--- a/audio/out/ao_coreaudio_properties.c
+++ b/audio/out/ao_coreaudio_properties.c
@@ -83,12 +83,7 @@ OSStatus ca_get_str(AudioObjectID id, ca_scope scope, ca_sel selector,
ca_get(id, scope, selector, sizeof(CFStringRef), (void **)&string);
CHECK_CA_ERROR_SILENT_L(coreaudio_error);
- CFIndex size =
- CFStringGetMaximumSizeForEncoding(
- CFStringGetLength(string), CA_CFSTR_ENCODING) + 1;
-
- *data = talloc_zero_size(NULL, size);
- CFStringGetCString(string, *data, size, CA_CFSTR_ENCODING);
+ *data = cfstr_get_cstr(string);
CFRelease(string);
coreaudio_error:
return err;
diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c
index fe8354939a..50c866d86c 100644
--- a/audio/out/ao_coreaudio_utils.c
+++ b/audio/out/ao_coreaudio_utils.c
@@ -28,6 +28,21 @@
#include "osdep/endian.h"
#include "audio/format.h"
+CFStringRef cfstr_from_cstr(char *str)
+{
+ return CFStringCreateWithCString(NULL, str, CA_CFSTR_ENCODING);
+}
+
+char *cfstr_get_cstr(CFStringRef cfstr)
+{
+ CFIndex size =
+ CFStringGetMaximumSizeForEncoding(
+ CFStringGetLength(cfstr), CA_CFSTR_ENCODING) + 1;
+ char *buffer = talloc_zero_size(NULL, size);
+ CFStringGetCString(cfstr, buffer, size, CA_CFSTR_ENCODING);
+ return buffer;
+}
+
static bool ca_is_output_device(struct ao *ao, AudioDeviceID dev)
{
size_t n_buffers;
@@ -49,9 +64,9 @@ void ca_get_device_list(struct ao *ao, struct ao_device_list *list)
for (int i = 0; i < n_devs; i++) {
if (!ca_is_output_device(ao, devs[i]))
continue;
- char name[32];
+ char *name;
char *desc;
- sprintf(name, "%d", devs[i]);
+ err = CA_GET_STR(devs[i], kAudioDevicePropertyDeviceUID, &name);
err = CA_GET_STR(devs[i], kAudioObjectPropertyName, &desc);
if (err != noErr)
desc = "Unknown";
@@ -65,21 +80,32 @@ coreaudio_error:
OSStatus ca_select_device(struct ao *ao, char* name, AudioDeviceID *device)
{
OSStatus err = noErr;
- errno = 0;
- int selection = name && name[0] ? strtol(name, (char **)NULL, 10) : -1;
- if (errno == EINVAL || errno == ERANGE) {
- selection = -1;
- MP_WARN(ao, "device identifier '%s' is invalid\n", name);
- }
- *device = 0;
- if (selection < 0) {
+ *device = kAudioObjectUnknown;
+
+ if (name) {
+ CFStringRef uid = cfstr_from_cstr(name);
+ AudioValueTranslation v = (AudioValueTranslation) {
+ .mInputData = &uid,
+ .mInputDataSize = sizeof(CFStringRef),
+ .mOutputData = device,
+ .mOutputDataSize = sizeof(*device),
+ };
+ uint32_t size = sizeof(AudioValueTranslation);
+ AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) {
+ .mSelector = kAudioHardwarePropertyDeviceForUID,
+ .mScope = kAudioObjectPropertyScopeGlobal,
+ .mElement = kAudioObjectPropertyElementMaster,
+ };
+ err = AudioObjectGetPropertyData(
+ kAudioObjectSystemObject, &p_addr, 0, 0, &size, &v);
+ CFRelease(uid);
+ CHECK_CA_ERROR("unable to query for device UID");
+ } else {
// device not set by user, get the default one
err = CA_GET(kAudioObjectSystemObject,
kAudioHardwarePropertyDefaultOutputDevice,
device);
CHECK_CA_ERROR("could not get default audio device");
- } else {
- *device = selection;
}
if (mp_msg_test(ao->log, MSGL_V)) {
diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h
index 0ef84c3afa..17c60b93be 100644
--- a/audio/out/ao_coreaudio_utils.h
+++ b/audio/out/ao_coreaudio_utils.h
@@ -28,6 +28,9 @@
#define CA_CFSTR_ENCODING kCFStringEncodingASCII
+CFStringRef cfstr_from_cstr(char *str);
+char *cfstr_get_cstr(CFStringRef cfstr);
+
char *fourcc_repr(void *talloc_ctx, uint32_t code);
bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message);