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
6 print(" - '" .. e.name .. "' (" .. e.description .. ")")6 print(" - '" .. e.name .. "' (" .. e.description .. ")")
7 end7 end
8end)8end)
9
10mp.observe_property("audio-out-detected-device", "native", function(name, val)
11 print("Detected audio device changed:")
12 print(" - '" .. val)
13end)
audio/out/ao.c+5−5
@@ -450,11 +450,6 @@ bool ao_untimed(struct ao *ao) · 449 unmodified lines
450 return ao->untimed;450 return ao->untimed;
451}451}
452 452
453const char *ao_get_detected_device(struct ao *ao)
454{
455 return ao->detected_device;
456}
457
458// ---453// ---
459 454
460struct ao_hotplug {455struct ao_hotplug {
@@ -502,6 +497,11 @@ bool ao_hotplug_check_update(struct ao_hotplug *hp) · 41 unmodified lines
502 return false;497 return false;
503}498}
504 499
500const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp)
501{
502 return hp->ao->detected_device;
503}
504
505// The return value is valid until the next call to this API.505// The return value is valid until the next call to this API.
506struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)506struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp)
507{507{
audio/out/ao.h+1−1
@@ -80,7 +80,6 @@ void ao_uninit(struct ao *ao); · 79 unmodified lines
80void ao_get_format(struct ao *ao, struct mp_audio *format);80void ao_get_format(struct ao *ao, struct mp_audio *format);
81const char *ao_get_name(struct ao *ao);81const char *ao_get_name(struct ao *ao);
82const char *ao_get_description(struct ao *ao);82const char *ao_get_description(struct ao *ao);
83const char *ao_get_detected_device(struct ao *ao);
84bool ao_untimed(struct ao *ao);83bool ao_untimed(struct ao *ao);
85int ao_play(struct ao *ao, void **data, int samples, int flags);84int ao_play(struct ao *ao, void **data, int samples, int flags);
86int ao_control(struct ao *ao, enum aocontrol cmd, void *arg);85int 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
100 struct input_ctx *input_ctx);99 struct input_ctx *input_ctx);
101void ao_hotplug_destroy(struct ao_hotplug *hp);100void ao_hotplug_destroy(struct ao_hotplug *hp);
102bool ao_hotplug_check_update(struct ao_hotplug *hp);101bool ao_hotplug_check_update(struct ao_hotplug *hp);
102const char *ao_hotplug_get_detected_device(struct ao_hotplug *hp);
103struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp);103struct ao_device_list *ao_hotplug_get_device_list(struct ao_hotplug *hp);
104 104
105void ao_print_devices(struct mpv_global *global, struct mp_log *log);105void 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
143static bool init_chmap(struct ao *ao);143static bool init_chmap(struct ao *ao);
144static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd);144static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd);
145 145
146static int init(struct ao *ao)146static bool reinit_device(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
154 struct priv *p = ao->priv;147 struct priv *p = ao->priv;
155 148
156 OSStatus err = ca_select_device(ao, ao->device, &p->device);149 OSStatus err = ca_select_device(ao, ao->device, &p->device);
@@ -161,6 +154,23 @@ static int init(struct ao *ao) · 4 unmodified lines
161 CHECK_CA_ERROR("failed to get device UID");154 CHECK_CA_ERROR("failed to get device UID");
162 ao->detected_device = talloc_steal(ao, uid);155 ao->detected_device = talloc_steal(ao, uid);
163 156
157 return true;
158
159coreaudio_error:
160 return false;
161}
162
163static 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
164 if (!init_chmap(ao))174 if (!init_chmap(ao))
165 goto coreaudio_error;175 goto coreaudio_error;
166 176
@@ -361,6 +371,67 @@ static void uninit(struct ao *ao) · 194 unmodified lines
361 AudioComponentInstanceDispose(p->audio_unit);371 AudioComponentInstanceDispose(p->audio_unit);
362}372}
363 373
374static 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
382static uint32_t hotplug_properties[] = {
383 kAudioHardwarePropertyDevices,
384 kAudioHardwarePropertyDefaultOutputDevice
385};
386
387static 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
411coreaudio_error:
412 return -1;
413}
414
415static 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
364// Channel Mapping functions435// Channel Mapping functions
365static const int speaker_map[][2] = {436static const int speaker_map[][2] = {
366 { kAudioChannelLabel_Left, MP_SPEAKER_ID_FL },437 { kAudioChannelLabel_Left, MP_SPEAKER_ID_FL },
@@ -513,13 +584,15 @@ coreaudio_error: · 146 unmodified lines
513#define OPT_BASE_STRUCT struct priv584#define OPT_BASE_STRUCT struct priv
514 585
515const struct ao_driver audio_out_coreaudio = {586const struct ao_driver audio_out_coreaudio = {
516 .description = "CoreAudio AudioUnit",587 .description = "CoreAudio AudioUnit",
517 .name = "coreaudio",588 .name = "coreaudio",
518 .uninit = uninit,589 .uninit = uninit,
519 .init = init,590 .init = init,
520 .control = control,591 .control = control,
521 .pause = stop,592 .pause = stop,
522 .resume = start,593 .resume = start,
523 .list_devs = ca_get_device_list,594 .hotplug_init = hotplug_init,
524 .priv_size = sizeof(struct priv),595 .hotplug_uninit = hotplug_uninit,
596 .list_devs = ca_get_device_list,
597 .priv_size = sizeof(struct priv),
525};598};
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
1578static int mp_property_ao_detected_device(void *ctx,struct m_property *prop,1578static int mp_property_ao_detected_device(void *ctx,struct m_property *prop,
1579 int action, void *arg)1579 int action, void *arg)
1580{1580{
1581 MPContext *mpctx = ctx;1581 struct MPContext *mpctx = ctx;
1582 struct command_ctx *cmd = mpctx->command_ctx;
1582 if (!mpctx->ao)1583 if (!mpctx->ao)
1583 return M_PROPERTY_UNAVAILABLE;1584 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);
1585}1587}
1586 1588
1587/// Audio delay (RW)1589/// Audio delay (RW)
@@ -3524,7 +3526,7 @@ static const char *const *const mp_event_property_change[] = { · 1936 unmodified lines
3524 "detected-hwdec"),3526 "detected-hwdec"),
3525 E(MPV_EVENT_AUDIO_RECONFIG, "audio-format", "audio-codec", "audio-bitrate",3527 E(MPV_EVENT_AUDIO_RECONFIG, "audio-format", "audio-codec", "audio-bitrate",
3526 "samplerate", "channels", "audio", "volume", "mute", "balance",3528 "samplerate", "channels", "audio", "volume", "mute", "balance",
3527 "volume-restore-data", "current-ao", "audio-out-detected-device"),3529 "volume-restore-data", "current-ao"),
3528 E(MPV_EVENT_SEEK, "seeking", "core-idle"),3530 E(MPV_EVENT_SEEK, "seeking", "core-idle"),
3529 E(MPV_EVENT_PLAYBACK_RESTART, "seeking", "core-idle"),3531 E(MPV_EVENT_PLAYBACK_RESTART, "seeking", "core-idle"),
3530 E(MPV_EVENT_METADATA_UPDATE, "metadata", "filtered-metadata"),3532 E(MPV_EVENT_METADATA_UPDATE, "metadata", "filtered-metadata"),
@@ -3534,6 +3536,7 @@ static const char *const *const mp_event_property_change[] = { · 3 unmodified lines
3534 E(MP_EVENT_WIN_RESIZE, "window-scale"),3536 E(MP_EVENT_WIN_RESIZE, "window-scale"),
3535 E(MP_EVENT_WIN_STATE, "window-minimized", "display-names"),3537 E(MP_EVENT_WIN_STATE, "window-minimized", "display-names"),
3536 E(MP_EVENT_AUDIO_DEVICES, "audio-device-list"),3538 E(MP_EVENT_AUDIO_DEVICES, "audio-device-list"),
3539 E(MP_EVENT_DETECTED_AUDIO_DEVICE, "audio-out-detected-device"),
3537};3540};
3538#undef E3541#undef E
3539 3542
@@ -4875,8 +4878,10 @@ static void command_event(struct MPContext *mpctx, int event, void *arg) · 1335 unmodified lines
4875 4878
4876 // This is a bit messy: ao_hotplug wakes up the player, and then we have4879 // This is a bit messy: ao_hotplug wakes up the player, and then we have
4877 // to recheck the state. Then the client(s) will read the property.4880 // 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)) {
4879 mp_notify_property(mpctx, "audio-device-list");4882 mp_notify_property(mpctx, "audio-device-list");
4883 mp_notify_property(mpctx, "audio-out-detected-device");
4884 }
4880}4885}
4881 4886
4882void mp_notify(struct MPContext *mpctx, int event, void *arg)4887void mp_notify(struct MPContext *mpctx, int event, void *arg)
player/command.h+1−0
@@ -48,6 +48,7 @@ enum { · 47 unmodified lines
48 MP_EVENT_WIN_RESIZE,48 MP_EVENT_WIN_RESIZE,
49 MP_EVENT_WIN_STATE,49 MP_EVENT_WIN_STATE,
50 MP_EVENT_AUDIO_DEVICES,50 MP_EVENT_AUDIO_DEVICES,
51 MP_EVENT_DETECTED_AUDIO_DEVICE,
51};52};
52 53
53bool mp_hook_test_completion(struct MPContext *mpctx, char *type);54bool 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