History

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.

Stefano Pigozzi committed 11 years ago

Commit 70802d51 parent 9aaec7c6 files · +111 −27Browse files

Unified · Split

6 files
  1. TOOLS/lua/audio-hotplug-test.lua +5 −0
  2. audio/out/ao.c +5 −5
  3. audio/out/ao.h +1 −1
  4. audio/out/ao_coreaudio.c +90 −17
  5. player/command.c +9 −4
  6. player/command.h +1 −0
TOOLS/lua/audio-hotplug-test.lua+5−0
@@ -6,3 +6,8 @@ mp.observe_property("audio-device-list", "native", function(name, val) · 5 unmodified lines
66 print(" - '" .. e.name .. "' (" .. e.description .. ")")
77 end
88 end)
9+
10+mp.observe_property("audio-out-detected-device", "native", function(name, val)
11+ print("Detected audio device changed:")
12+ print(" - '" .. val)
13+end)
audio/out/ao.c+5−5
@@ -450,11 +450,6 @@ bool ao_untimed(struct ao *ao) · 449 unmodified lines
450450 return ao->untimed;
451451 }
452452
453−const char *ao_get_detected_device(struct ao *ao)
454−{
455− return ao->detected_device;
456−}
457−
458453 // ---
459454
460455 struct ao_hotplug {
@@ -502,6 +497,11 @@ bool ao_hotplug_check_update(struct ao_hotplug *hp) · 41 unmodified lines
502497 return false;
503498 }
504499
500+const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp)
501+{
502+ return hp->ao->detected_device;
503+}
504+
505505 // The return value is valid until the next call to this API.
506506 struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
507507 {
audio/out/ao.h+1−1
@@ -80,7 +80,6 @@ void ao_uninit(struct ao *ao); · 79 unmodified lines
8080 void ao_get_format(struct ao *ao, struct mp_audio *format);
8181 const char *ao_get_name(struct ao *ao);
8282 const char *ao_get_description(struct ao *ao);
83−const char *ao_get_detected_device(struct ao *ao);
8483 bool ao_untimed(struct ao *ao);
8584 int ao_play(struct ao *ao, void **data, int samples, int flags);
8685 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, · 13 unmodified lines
10099 struct input_ctx *input_ctx);
101100 void ao_hotplug_destroy(struct ao_hotplug *hp);
102101 bool ao_hotplug_check_update(struct ao_hotplug *hp);
102+const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp);
103103 struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp);
104104
105105 void ao_print_devices(struct mpv_global *global, struct mp_log *log);
audio/out/ao_coreaudio.c+90−17
@@ -143,14 +143,7 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) · 142 unmodified lines
143143 static bool init_chmap(struct ao *ao);
144144 static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd);
145145
146−static int init(struct ao *ao)
147−{
148− if (AF_FORMAT_IS_IEC61937(ao->format)) {
149− MP_WARN(ao, "detected IEC61937, redirecting to coreaudio_exclusive\n");
150− ao->redirect = "coreaudio_exclusive";
151− return CONTROL_ERROR;
152− }
153−
146+static bool reinit_device(struct ao *ao) {
154147 struct priv *p = ao->priv;
155148
156149 OSStatus err = ca_select_device(ao, ao->device, &p->device);
@@ -161,6 +154,23 @@ static int init(struct ao *ao) · 4 unmodified lines
161154 CHECK_CA_ERROR("failed to get device UID");
162155 ao->detected_device = talloc_steal(ao, uid);
163156
157+ return true;
158+
159+coreaudio_error:
160+ return false;
161+}
162+
163+static int init(struct ao *ao)
164+{
165+ if (AF_FORMAT_IS_IEC61937(ao->format)) {
166+ MP_WARN(ao, "detected IEC61937, redirecting to coreaudio_exclusive\n");
167+ ao->redirect = "coreaudio_exclusive";
168+ return CONTROL_ERROR;
169+ }
170+
171+ if (!reinit_device(ao))
172+ goto coreaudio_error;
173+
164174 if (!init_chmap(ao))
165175 goto coreaudio_error;
166176
@@ -361,6 +371,67 @@ static void uninit(struct ao *ao) · 194 unmodified lines
361371 AudioComponentInstanceDispose(p->audio_unit);
362372 }
363373
374+static OSStatus hotplug_cb(AudioObjectID id, UInt32 naddr,
375+ const AudioObjectPropertyAddress addr[],
376+ void *ctx) {
377+ reinit_device(ctx);
378+ ao_hotplug_event(ctx);
379+ return noErr;
380+}
381+
382+static uint32_t hotplug_properties[] = {
383+ kAudioHardwarePropertyDevices,
384+ kAudioHardwarePropertyDefaultOutputDevice
385+};
386+
387+static int hotplug_init(struct ao *ao)
388+{
389+ if (!reinit_device(ao))
390+ goto coreaudio_error;
391+
392+ OSStatus err = noErr;
393+ for (int i = 0; i < MP_ARRAY_SIZE(hotplug_properties); i++) {
394+ AudioObjectPropertyAddress addr = {
395+ hotplug_properties[i],
396+ kAudioObjectPropertyScopeGlobal,
397+ kAudioObjectPropertyElementMaster
398+ };
399+ err = AudioObjectAddPropertyListener(
400+ kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
401+ if (err != noErr) {
402+ char *c1 = fourcc_repr(ao, hotplug_properties[i]);
403+ char *c2 = fourcc_repr(ao, err);
404+ MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
405+ goto coreaudio_error;
406+ }
407+ }
408+
409+ return 0;
410+
411+coreaudio_error:
412+ return -1;
413+}
414+
415+static void hotplug_uninit(struct ao *ao)
416+{
417+ OSStatus err = noErr;
418+ for (int i = 0; i < MP_ARRAY_SIZE(hotplug_properties); i++) {
419+ AudioObjectPropertyAddress addr = {
420+ hotplug_properties[i],
421+ kAudioObjectPropertyScopeGlobal,
422+ kAudioObjectPropertyElementMaster
423+ };
424+ err = AudioObjectRemovePropertyListener(
425+ kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
426+ if (err != noErr) {
427+ char *c1 = fourcc_repr(ao, hotplug_properties[i]);
428+ char *c2 = fourcc_repr(ao, err);
429+ MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
430+ }
431+ }
432+}
433+
434+
364435 // Channel Mapping functions
365436 static const int speaker_map[][2] = {
366437 { kAudioChannelLabel_Left, MP_SPEAKER_ID_FL },
@@ -513,13 +584,15 @@ coreaudio_error: · 146 unmodified lines
513584 #define OPT_BASE_STRUCT struct priv
514585
515586 const struct ao_driver audio_out_coreaudio = {
516− .description = "CoreAudio AudioUnit",
517− .name = "coreaudio",
518− .uninit = uninit,
519− .init = init,
520− .control = control,
521− .pause = stop,
522− .resume = start,
523− .list_devs = ca_get_device_list,
524− .priv_size = sizeof(struct priv),
587+ .description = "CoreAudio AudioUnit",
588+ .name = "coreaudio",
589+ .uninit = uninit,
590+ .init = init,
591+ .control = control,
592+ .pause = stop,
593+ .resume = start,
594+ .hotplug_init = hotplug_init,
595+ .hotplug_uninit = hotplug_uninit,
596+ .list_devs = ca_get_device_list,
597+ .priv_size = sizeof(struct priv),
525598 };
player/command.c+9−4
@@ -1578,10 +1578,12 @@ static int mp_property_ao(void *ctx, struct m_property *p, int action, void *arg · 1577 unmodified lines
15781578 static int mp_property_ao_detected_device(void *ctx,struct m_property *prop,
15791579 int action, void *arg)
15801580 {
1581− MPContext *mpctx = ctx;
1581+ struct MPContext *mpctx = ctx;
1582+ struct command_ctx *cmd = mpctx->command_ctx;
15821583 if (!mpctx->ao)
15831584 return M_PROPERTY_UNAVAILABLE;
1584− return m_property_strdup_ro(action, arg, ao_get_detected_device(mpctx->ao));
1585+ const char *d = ao_hotplug_get_detected_device(cmd->hotplug);
1586+ return m_property_strdup_ro(action, arg, d);
15851587 }
15861588
15871589 /// Audio delay (RW)
@@ -3524,7 +3526,7 @@ static const char *const *const mp_event_property_change[] = { · 1936 unmodified lines
35243526 "detected-hwdec"),
35253527 E(MPV_EVENT_AUDIO_RECONFIG, "audio-format", "audio-codec", "audio-bitrate",
35263528 "samplerate", "channels", "audio", "volume", "mute", "balance",
3527− "volume-restore-data", "current-ao", "audio-out-detected-device"),
3529+ "volume-restore-data", "current-ao"),
35283530 E(MPV_EVENT_SEEK, "seeking", "core-idle"),
35293531 E(MPV_EVENT_PLAYBACK_RESTART, "seeking", "core-idle"),
35303532 E(MPV_EVENT_METADATA_UPDATE, "metadata", "filtered-metadata"),
@@ -3534,6 +3536,7 @@ static const char *const *const mp_event_property_change[] = { · 3 unmodified lines
35343536 E(MP_EVENT_WIN_RESIZE, "window-scale"),
35353537 E(MP_EVENT_WIN_STATE, "window-minimized", "display-names"),
35363538 E(MP_EVENT_AUDIO_DEVICES, "audio-device-list"),
3539+ E(MP_EVENT_DETECTED_AUDIO_DEVICE, "audio-out-detected-device"),
35373540 };
35383541 #undef E
35393542
@@ -4875,8 +4878,10 @@ static void command_event(struct MPContext *mpctx, int event, void *arg) · 1335 unmodified lines
48754878
48764879 // This is a bit messy: ao_hotplug wakes up the player, and then we have
48774880 // to recheck the state. Then the client(s) will read the property.
4878− if (ctx->hotplug && ao_hotplug_check_update(ctx->hotplug))
4881+ if (ctx->hotplug && ao_hotplug_check_update(ctx->hotplug)) {
48794882 mp_notify_property(mpctx, "audio-device-list");
4883+ mp_notify_property(mpctx, "audio-out-detected-device");
4884+ }
48804885 }
48814886
48824887 void mp_notify(struct MPContext *mpctx, int event, void *arg)
player/command.h+1−0
@@ -48,6 +48,7 @@ enum { · 47 unmodified lines
4848 MP_EVENT_WIN_RESIZE,
4949 MP_EVENT_WIN_STATE,
5050 MP_EVENT_AUDIO_DEVICES,
51+ MP_EVENT_DETECTED_AUDIO_DEVICE,
5152 };
5253
5354 bool mp_hook_test_completion(struct MPContext *mpctx, char *type);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t