summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/ao.rst8
-rw-r--r--audio/out/ao_coreaudio.c55
2 files changed, 63 insertions, 0 deletions
diff --git a/DOCS/man/ao.rst b/DOCS/man/ao.rst
index 5103997e76..e02a5886ff 100644
--- a/DOCS/man/ao.rst
+++ b/DOCS/man/ao.rst
@@ -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).
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index 65f7a070fd..85057bee67 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -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}
+ },
};