summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2015-02-14 12:43:55 +0100
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2015-02-14 12:51:15 +0100
commit70802d519f9130696959346aa413f7faeeed7621 (patch)
tree130639c7880b1495b2b43d31480705733989c899 /audio/out
parent9aaec7cffb2fb1543d4c3cabb55165f606c0b87d (diff)
downloadmpv-70802d519f9130696959346aa413f7faeeed7621.tar.bz2
mpv-70802d519f9130696959346aa413f7faeeed7621.tar.xz
ao_coreaudio: add support for hotplug notifications
This commit adds notifications for hot plugging of devices. It also extends the old behaviour of the `audio-out-detected-device` property which is now backed by the hotplugging code. This allows clients to be notified when the actual audio output device changes. Maybe hotplugging should be supported for ao_coreaudio_exclusive too, but it's device selection code is a bit fragile.
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/ao.c10
-rw-r--r--audio/out/ao.h2
-rw-r--r--audio/out/ao_coreaudio.c107
3 files changed, 96 insertions, 23 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c
index a2fa2fb104..c7065f386a 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -450,11 +450,6 @@ bool ao_untimed(struct ao *ao)
return ao->untimed;
}
-const char *ao_get_detected_device(struct ao *ao)
-{
- return ao->detected_device;
-}
-
// ---
struct ao_hotplug {
@@ -502,6 +497,11 @@ bool ao_hotplug_check_update(struct ao_hotplug *hp)
return false;
}
+const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp)
+{
+ return hp->ao->detected_device;
+}
+
// The return value is valid until the next call to this API.
struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
{
diff --git a/audio/out/ao.h b/audio/out/ao.h
index 7b85ec80ba..3a028bb402 100644
--- a/audio/out/ao.h
+++ b/audio/out/ao.h
@@ -80,7 +80,6 @@ void ao_uninit(struct ao *ao);
void ao_get_format(struct ao *ao, struct mp_audio *format);
const char *ao_get_name(struct ao *ao);
const char *ao_get_description(struct ao *ao);
-const char *ao_get_detected_device(struct ao *ao);
bool ao_untimed(struct ao *ao);
int ao_play(struct ao *ao, void **data, int samples, int flags);
int ao_control(struct ao *ao, enum aocontrol cmd, void *arg);
@@ -100,6 +99,7 @@ struct ao_hotplug *ao_hotplug_create(struct mpv_global *global,
struct input_ctx *input_ctx);
void ao_hotplug_destroy(struct ao_hotplug *hp);
bool ao_hotplug_check_update(struct ao_hotplug *hp);
+const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp);
struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp);
void ao_print_devices(struct mpv_global *global, struct mp_log *log);
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 0eab220421..99f0572723 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -143,14 +143,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg)
static bool init_chmap(struct ao *ao);
static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd);
-static int init(struct ao *ao)
-{
- if (AF_FORMAT_IS_IEC61937(ao->format)) {
- MP_WARN(ao, "detected IEC61937, redirecting to coreaudio_exclusive\n");
- ao->redirect = "coreaudio_exclusive";
- return CONTROL_ERROR;
- }
-
+static bool reinit_device(struct ao *ao) {
struct priv *p = ao->priv;
OSStatus err = ca_select_device(ao, ao->device, &p->device);
@@ -161,6 +154,23 @@ static int init(struct ao *ao)
CHECK_CA_ERROR("failed to get device UID");
ao->detected_device = talloc_steal(ao, uid);
+ return true;
+
+coreaudio_error:
+ return false;
+}
+
+static int init(struct ao *ao)
+{
+ if (AF_FORMAT_IS_IEC61937(ao->format)) {
+ MP_WARN(ao, "detected IEC61937, redirecting to coreaudio_exclusive\n");
+ ao->redirect = "coreaudio_exclusive";
+ return CONTROL_ERROR;
+ }
+
+ if (!reinit_device(ao))
+ goto coreaudio_error;
+
if (!init_chmap(ao))
goto coreaudio_error;
@@ -361,6 +371,67 @@ static void uninit(struct ao *ao)
AudioComponentInstanceDispose(p->audio_unit);
}
+static OSStatus hotplug_cb(AudioObjectID id, UInt32 naddr,
+ const AudioObjectPropertyAddress addr[],
+ void *ctx) {
+ reinit_device(ctx);
+ ao_hotplug_event(ctx);
+ return noErr;
+}
+
+static uint32_t hotplug_properties[] = {
+ kAudioHardwarePropertyDevices,
+ kAudioHardwarePropertyDefaultOutputDevice
+};
+
+static int hotplug_init(struct ao *ao)
+{
+ if (!reinit_device(ao))
+ goto coreaudio_error;
+
+ OSStatus err = noErr;
+ for (int i = 0; i < MP_ARRAY_SIZE(hotplug_properties); i++) {
+ AudioObjectPropertyAddress addr = {
+ hotplug_properties[i],
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+ err = AudioObjectAddPropertyListener(
+ kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
+ if (err != noErr) {
+ char *c1 = fourcc_repr(ao, hotplug_properties[i]);
+ char *c2 = fourcc_repr(ao, err);
+ MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
+ goto coreaudio_error;
+ }
+ }
+
+ return 0;
+
+coreaudio_error:
+ return -1;
+}
+
+static void hotplug_uninit(struct ao *ao)
+{
+ OSStatus err = noErr;
+ for (int i = 0; i < MP_ARRAY_SIZE(hotplug_properties); i++) {
+ AudioObjectPropertyAddress addr = {
+ hotplug_properties[i],
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+ err = AudioObjectRemovePropertyListener(
+ kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
+ if (err != noErr) {
+ char *c1 = fourcc_repr(ao, hotplug_properties[i]);
+ char *c2 = fourcc_repr(ao, err);
+ MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
+ }
+ }
+}
+
+
// Channel Mapping functions
static const int speaker_map[][2] = {
{ kAudioChannelLabel_Left, MP_SPEAKER_ID_FL },
@@ -513,13 +584,15 @@ coreaudio_error:
#define OPT_BASE_STRUCT struct priv
const struct ao_driver audio_out_coreaudio = {
- .description = "CoreAudio AudioUnit",
- .name = "coreaudio",
- .uninit = uninit,
- .init = init,
- .control = control,
- .pause = stop,
- .resume = start,
- .list_devs = ca_get_device_list,
- .priv_size = sizeof(struct priv),
+ .description = "CoreAudio AudioUnit",
+ .name = "coreaudio",
+ .uninit = uninit,
+ .init = init,
+ .control = control,
+ .pause = stop,
+ .resume = start,
+ .hotplug_init = hotplug_init,
+ .hotplug_uninit = hotplug_uninit,
+ .list_devs = ca_get_device_list,
+ .priv_size = sizeof(struct priv),
};