ao_coreaudio: add an option for changing the physical format

ao_coreaudio uses AudioUnit - the OSX software mixer. In theory, it
supports multichannel audio just fine. But in practice, this might be
disabled by default, and the user is supposed to select a multichannel
base format in the "Audio MIDI Setup" utility.

This option attempts to change this setting automatically. Some possible
disadvantages and caveats are listed in the manpage additions. It is off
by default, since changing this might be rather bad behavior for a
normal application.
This commit is contained in:
wm4 2015-05-05 01:07:57 +02:00
parent 305a85cc9a
commit 8121529a6c
2 changed files with 63 additions and 0 deletions

View File

@ -162,6 +162,14 @@ Available audio output drivers are:
Automatically redirects to ``coreaudio_exclusive`` when playing compressed
formats.
``change-physical-format=<yes|no>``
Change the physical format to one similar to the requested audio format
(default: no). This has the advantage that multichannel audio output
will actually work. The disadvantage is that it will change the
system-wide audio settings. This is equivalent to change the ``Format``
setting in the ``Audio Devices`` dialog in the ``Audio MIDI Setup``
utility. Note that this does not effect the selected speaker setup.
``coreaudio_exclusive`` (Mac OS X only)
Native Mac OS X audio output driver using direct device access and
exclusive mode (bypasses the sound server).

View File

@ -33,6 +33,8 @@ struct priv {
AudioUnit audio_unit;
uint64_t hw_latency_us;
int change_physical_format;
};
bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout,
@ -260,12 +262,61 @@ coreaudio_error:
return false;
}
static void init_physical_format(struct ao *ao, AudioStreamBasicDescription asbd)
{
struct priv *p = ao->priv;
OSErr err;
AudioStreamID *streams;
size_t n_streams;
err = CA_GET_ARY_O(p->device, kAudioDevicePropertyStreams,
&streams, &n_streams);
CHECK_CA_ERROR("could not get number of streams");
for (int i = 0; i < n_streams; i++) {
AudioStreamRangedDescription *formats;
size_t n_formats;
err = CA_GET_ARY(streams[i],
kAudioStreamPropertyAvailablePhysicalFormats,
&formats, &n_formats);
if (!CHECK_CA_WARN("could not get number of stream formats"))
continue; // try next one
AudioStreamBasicDescription best_asbd = {0};
for (int j = 0; j < n_formats; j++) {
AudioStreamBasicDescription *stream_asbd = &formats[j].mFormat;
if (!best_asbd.mFormatID || ca_asbd_is_better(&asbd, &best_asbd,
stream_asbd))
best_asbd = *stream_asbd;
}
if (best_asbd.mFormatID) {
ca_print_asbd(ao, "Trying to set physical format:", &best_asbd);
err = CA_SET(streams[i], kAudioStreamPropertyPhysicalFormat,
&best_asbd);
CHECK_CA_ERROR("could not set physical format");
break;
}
}
coreaudio_error:
return;
}
static bool init_audiounit(struct ao *ao, AudioStreamBasicDescription asbd)
{
OSStatus err;
uint32_t size;
struct priv *p = ao->priv;
if (p->change_physical_format)
init_physical_format(ao, asbd);
AudioComponentDescription desc = (AudioComponentDescription) {
.componentType = kAudioUnitType_Output,
.componentSubType = (ao->device) ?
@ -583,4 +634,8 @@ const struct ao_driver audio_out_coreaudio = {
.hotplug_uninit = hotplug_uninit,
.list_devs = ca_get_device_list,
.priv_size = sizeof(struct priv),
.options = (const struct m_option[]){
OPT_FLAG("change-physical-format", change_physical_format, 0),
{0}
},
};