summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--TOOLS/lua/audio-hotplug-test.lua5
-rw-r--r--audio/out/ao.c10
-rw-r--r--audio/out/ao.h2
-rw-r--r--audio/out/ao_coreaudio.c107
-rw-r--r--player/command.c13
-rw-r--r--player/command.h1
6 files changed, 111 insertions, 27 deletions
diff --git a/TOOLS/lua/audio-hotplug-test.lua b/TOOLS/lua/audio-hotplug-test.lua
index 8dedc68cbe..f27b793151 100644
--- a/TOOLS/lua/audio-hotplug-test.lua
+++ b/TOOLS/lua/audio-hotplug-test.lua
@@ -6,3 +6,8 @@ mp.observe_property("audio-device-list", "native", function(name, val)
print(" - '" .. e.name .. "' (" .. e.description .. ")")
end
end)
+
+mp.observe_property("audio-out-detected-device", "native", function(name, val)
+ print("Detected audio device changed:")
+ print(" - '" .. val)
+end)
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),
};
diff --git a/player/command.c b/player/command.c
index 8e3d38ebfe..b8a0a7b5ce 100644
--- a/player/command.c
+++ b/player/command.c
@@ -1578,10 +1578,12 @@ static int mp_property_ao(void *ctx, struct m_property *p, int action, void *arg
static int mp_property_ao_detected_device(void *ctx,struct m_property *prop,
int action, void *arg)
{
- MPContext *mpctx = ctx;
+ struct MPContext *mpctx = ctx;
+ struct command_ctx *cmd = mpctx->command_ctx;
if (!mpctx->ao)
return M_PROPERTY_UNAVAILABLE;
- return m_property_strdup_ro(action, arg, ao_get_detected_device(mpctx->ao));
+ const char *d = ao_hotplug_get_detected_device(cmd->hotplug);
+ return m_property_strdup_ro(action, arg, d);
}
/// Audio delay (RW)
@@ -3524,7 +3526,7 @@ static const char *const *const mp_event_property_change[] = {
"detected-hwdec"),
E(MPV_EVENT_AUDIO_RECONFIG, "audio-format", "audio-codec", "audio-bitrate",
"samplerate", "channels", "audio", "volume", "mute", "balance",
- "volume-restore-data", "current-ao", "audio-out-detected-device"),
+ "volume-restore-data", "current-ao"),
E(MPV_EVENT_SEEK, "seeking", "core-idle"),
E(MPV_EVENT_PLAYBACK_RESTART, "seeking", "core-idle"),
E(MPV_EVENT_METADATA_UPDATE, "metadata", "filtered-metadata"),
@@ -3534,6 +3536,7 @@ static const char *const *const mp_event_property_change[] = {
E(MP_EVENT_WIN_RESIZE, "window-scale"),
E(MP_EVENT_WIN_STATE, "window-minimized", "display-names"),
E(MP_EVENT_AUDIO_DEVICES, "audio-device-list"),
+ E(MP_EVENT_DETECTED_AUDIO_DEVICE, "audio-out-detected-device"),
};
#undef E
@@ -4875,8 +4878,10 @@ static void command_event(struct MPContext *mpctx, int event, void *arg)
// This is a bit messy: ao_hotplug wakes up the player, and then we have
// to recheck the state. Then the client(s) will read the property.
- if (ctx->hotplug && ao_hotplug_check_update(ctx->hotplug))
+ if (ctx->hotplug && ao_hotplug_check_update(ctx->hotplug)) {
mp_notify_property(mpctx, "audio-device-list");
+ mp_notify_property(mpctx, "audio-out-detected-device");
+ }
}
void mp_notify(struct MPContext *mpctx, int event, void *arg)
diff --git a/player/command.h b/player/command.h
index 96a58b1f80..945d686786 100644
--- a/player/command.h
+++ b/player/command.h
@@ -48,6 +48,7 @@ enum {
MP_EVENT_WIN_RESIZE,
MP_EVENT_WIN_STATE,
MP_EVENT_AUDIO_DEVICES,
+ MP_EVENT_DETECTED_AUDIO_DEVICE,
};
bool mp_hook_test_completion(struct MPContext *mpctx, char *type);