diff options
author | wm4 <wm4@nowhere> | 2015-07-03 19:07:42 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2015-07-03 19:28:00 +0200 |
commit | e9e323f35da7247d8a36f3d2a33a76f8bc98fde0 (patch) | |
tree | caee972a88ae539b44eb9730199c87adb6a978ba /audio/out | |
parent | 65e3657bc40dbe66c487063832aa2a84b1952101 (diff) | |
download | mpv-e9e323f35da7247d8a36f3d2a33a76f8bc98fde0.tar.bz2 mpv-e9e323f35da7247d8a36f3d2a33a76f8bc98fde0.tar.xz |
ao_coreaudio_exclusive: support PCM
Until now, this was for AC3 only. For PCM, we used AudioUnit in
ao_coreaudio, and the only reason ao_coreaudio_exclusive exists
is that there is no other way to passthrough AC3.
PCM support is actually rather simple. The most complicated
issue is that modern OS X versions actually do not support
copying through the data; instead everything must go through
float. So we have to deal with virtual and physical format
being different, which causes some complications.
This possibly also doesn't support some other things correctly.
For one, if the device allows non-interleaved output only, we
will probably fail. (I couldn't test it, so I don't even know
what is required. Supporting it would probably be rather
simple, and we already do it with AudioUnit.)
Diffstat (limited to 'audio/out')
-rw-r--r-- | audio/out/ao_coreaudio_exclusive.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/audio/out/ao_coreaudio_exclusive.c b/audio/out/ao_coreaudio_exclusive.c index 5cdf4d93e2..e22319a6d6 100644 --- a/audio/out/ao_coreaudio_exclusive.c +++ b/audio/out/ao_coreaudio_exclusive.c @@ -44,6 +44,7 @@ #include "osdep/atomics.h" #include "options/m_option.h" #include "common/msg.h" +#include "audio/out/ao_coreaudio_chmap.h" #include "audio/out/ao_coreaudio_properties.h" #include "audio/out/ao_coreaudio_utils.h" @@ -85,7 +86,7 @@ static OSStatus property_listener_cb( // Check whether we need to reset the compressed output stream. AudioStreamBasicDescription f; - OSErr err = CA_GET(p->stream, kAudioStreamPropertyPhysicalFormat, &f); + OSErr err = CA_GET(p->stream, kAudioStreamPropertyVirtualFormat, &f); CHECK_CA_WARN("could not get stream format"); if (err != noErr || !ca_asbd_equals(&p->stream_asbd, &f)) { if (atomic_compare_exchange_strong(&p->reload_requested, @@ -186,7 +187,9 @@ static int select_stream(struct ao *ao) continue; } - if (ca_stream_supports_compressed(ao, streams[i])) { + if (af_fmt_is_pcm(ao->format) || ca_stream_supports_compressed(ao, + streams[i])) + { MP_VERBOSE(ao, "Using substream %d/%zd.\n", i, n_streams); p->stream = streams[i]; p->stream_idx = i; @@ -214,6 +217,7 @@ static int find_best_format(struct ao *ao, AudioStreamBasicDescription *out_fmt) // Build ASBD for the input format AudioStreamBasicDescription asbd; ca_fill_asbd(ao, &asbd); + ca_print_asbd(ao, "our format:", &asbd); *out_fmt = (AudioStreamBasicDescription){0}; @@ -255,13 +259,8 @@ static int init(struct ao *ao) ao->format = af_fmt_from_planar(ao->format); - if (!af_fmt_is_spdif(ao->format)) { - MP_ERR(ao, "Only compressed formats are supported.\n"); - goto coreaudio_error_nounlock; - } - - if (!ca_device_supports_compressed(ao, p->device)) { - MP_ERR(ao, "selected device doesn't support compressed formats\n"); + if (!af_fmt_is_pcm(ao->format) && !af_fmt_is_spdif(ao->format)) { + MP_ERR(ao, "Unsupported format.\n"); goto coreaudio_error_nounlock; } @@ -285,8 +284,6 @@ static int init(struct ao *ao) if (find_best_format(ao, &hwfmt) < 0) goto coreaudio_error; - p->stream_asbd = hwfmt; - err = CA_GET(p->stream, kAudioStreamPropertyPhysicalFormat, &p->original_asbd); CHECK_CA_ERROR("could not get stream's original physical format"); @@ -294,14 +291,34 @@ static int init(struct ao *ao) if (!ca_change_physical_format_sync(ao, p->stream, hwfmt)) goto coreaudio_error; - err = enable_property_listener(ao, true); - CHECK_CA_ERROR("cannot install format change listener during init"); + if (!ca_init_chmap(ao, p->device)) + goto coreaudio_error; + + err = CA_GET(p->stream, kAudioStreamPropertyVirtualFormat, &p->stream_asbd); + CHECK_CA_ERROR("could not get stream's virtual format"); + + ca_print_asbd(ao, "virtual format", &p->stream_asbd); - if (p->stream_asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) - MP_WARN(ao, "stream has non-native byte order, output may fail\n"); + int new_format = ca_asbd_to_mp_format(&p->stream_asbd); + + // If both old and new formats are spdif, avoid changing it due to the + // imperfect mapping between mp and CA formats. + if (!(af_fmt_is_spdif(ao->format) && af_fmt_is_spdif(new_format))) + ao->format = new_format; + + if (!ao->format || af_fmt_is_planar(ao->format)) { + MP_ERR(ao, "hardware format not supported\n"); + goto coreaudio_error; + } ao->samplerate = p->stream_asbd.mSampleRate; + if (ao->channels.num != p->stream_asbd.mChannelsPerFrame) { + // We really expect that ca_init_chmap() fixes the layout to the HW's. + MP_ERR(ao, "number of channels changed, and unknown channel layout!\n"); + goto coreaudio_error; + } + uint32_t latency_frames = 0; uint32_t latency_properties[] = { kAudioDevicePropertyLatency, @@ -322,6 +339,9 @@ static int init(struct ao *ao) p->hw_latency_us = ca_frames_to_us(ao, latency_frames); MP_VERBOSE(ao, "base latency: %d microseconds\n", (int)p->hw_latency_us); + err = enable_property_listener(ao, true); + CHECK_CA_ERROR("cannot install format change listener during init"); + err = AudioDeviceCreateIOProcID(p->device, (AudioDeviceIOProc)render_cb_compressed, (void *)ao, |