diff --git a/media/libcubeb/0001-Correctly-retrieve-the-output-layout-on-macOS-10.12.patch b/media/libcubeb/0001-Correctly-retrieve-the-output-layout-on-macOS-10.12.patch new file mode 100644 index 000000000000..8cd32fbe8467 --- /dev/null +++ b/media/libcubeb/0001-Correctly-retrieve-the-output-layout-on-macOS-10.12.patch @@ -0,0 +1,68 @@ +From 59f5cb4ba01f21c4ad87e9404d1e470408e18505 Mon Sep 17 00:00:00 2001 +From: Jean-Yves Avenard +Date: Mon, 9 Jul 2018 17:37:16 +0200 +Subject: [PATCH 1/2] Correctly retrieve the output layout on macOS < 10.12. + +The method kAudioUnitProperty_AudioChannelLayout used to retrieve the channel layout wasn't introduced until 10.12. So we use kAudioDevicePropertyPreferredChannelLayout instead should it fails. + +Fixes #448 +--- + src/cubeb_audiounit.cpp | 35 ++++++++++++++++++++++++++++++++++- + 1 file changed, 34 insertions(+), 1 deletion(-) + +diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp +index 6163ed7..43120b3 100644 +--- a/src/cubeb_audiounit.cpp ++++ b/src/cubeb_audiounit.cpp +@@ -1239,6 +1239,38 @@ audiounit_convert_channel_layout(AudioChannelLayout * layout) + return cl; + } + ++static cubeb_channel_layout ++audiounit_get_preferred_channel_layout(AudioUnit output_unit) ++{ ++ OSStatus rv = noErr; ++ UInt32 size = 0; ++ rv = AudioUnitGetPropertyInfo(output_unit, ++ kAudioDevicePropertyPreferredChannelLayout, ++ kAudioUnitScope_Output, ++ AU_OUT_BUS, ++ &size, ++ nullptr); ++ if (rv != noErr) { ++ LOG("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout rv=%d", rv); ++ return CUBEB_LAYOUT_UNDEFINED; ++ } ++ assert(size > 0); ++ ++ auto layout = make_sized_audio_channel_layout(size); ++ rv = AudioUnitGetProperty(output_unit, ++ kAudioDevicePropertyPreferredChannelLayout, ++ kAudioUnitScope_Output, ++ AU_OUT_BUS, ++ layout.get(), ++ &size); ++ if (rv != noErr) { ++ LOG("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout rv=%d", rv); ++ return CUBEB_LAYOUT_UNDEFINED; ++ } ++ ++ return audiounit_convert_channel_layout(layout.get()); ++} ++ + static cubeb_channel_layout + audiounit_get_current_channel_layout(AudioUnit output_unit) + { +@@ -1252,7 +1284,8 @@ audiounit_get_current_channel_layout(AudioUnit output_unit) + nullptr); + if (rv != noErr) { + LOG("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout rv=%d", rv); +- return CUBEB_LAYOUT_UNDEFINED; ++ // This property isn't known before macOS 10.12, attempt another method. ++ return audiounit_get_preferred_channel_layout(output_unit); + } + assert(size > 0); + +-- +2.17.0 + diff --git a/media/libcubeb/0002-Always-upmix-mono-to-the-first-two-channels-if-enoug.patch b/media/libcubeb/0002-Always-upmix-mono-to-the-first-two-channels-if-enoug.patch new file mode 100644 index 000000000000..62bfc3f036b3 --- /dev/null +++ b/media/libcubeb/0002-Always-upmix-mono-to-the-first-two-channels-if-enoug.patch @@ -0,0 +1,67 @@ +From dbd61924736fbe1a1caf1cbd544f7d197f1836f7 Mon Sep 17 00:00:00 2001 +From: Jean-Yves Avenard +Date: Mon, 9 Jul 2018 20:10:13 +0200 +Subject: [PATCH 2/2] Always upmix mono to the first two channels if enough + output channels are available + +This allows to output what people typically expect when playing mono audio: sound coming from both left and right channels. + +To force this conversion for happening on mac, we tag that layout are unknown as soon as a channel type is unknown +--- + src/cubeb_audiounit.cpp | 8 ++++++-- + src/cubeb_mixer.cpp | 12 ++++++++++++ + 2 files changed, 18 insertions(+), 2 deletions(-) + +diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp +index 43120b3..5a83098 100644 +--- a/src/cubeb_audiounit.cpp ++++ b/src/cubeb_audiounit.cpp +@@ -291,7 +291,7 @@ cubeb_channel_to_channel_label(cubeb_channel channel) + case CHANNEL_TOP_BACK_RIGHT: + return kAudioChannelLabel_TopBackRight; + default: +- return CHANNEL_UNKNOWN; ++ return kAudioChannelLabel_Unknown; + } + } + +@@ -1232,8 +1232,12 @@ audiounit_convert_channel_layout(AudioChannelLayout * layout) + + cubeb_channel_layout cl = 0; + for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) { +- cl |= channel_label_to_cubeb_channel( ++ cubeb_channel cc = channel_label_to_cubeb_channel( + layout->mChannelDescriptions[i].mChannelLabel); ++ if (cc == CHANNEL_UNKNOWN) { ++ return CUBEB_LAYOUT_UNDEFINED; ++ } ++ cl |= cc; + } + + return cl; +diff --git a/src/cubeb_mixer.cpp b/src/cubeb_mixer.cpp +index 8995c55..9aa141d 100644 +--- a/src/cubeb_mixer.cpp ++++ b/src/cubeb_mixer.cpp +@@ -533,6 +533,18 @@ struct cubeb_mixer + output_buffer += _context._out_ch_count - _context._in_ch_count; + } + } else { ++ if (_context._in_ch_count == 1 && _context._out_ch_count >= 2) { ++ // Special case for upmixing mono input to stereo and more. We will ++ // duplicate the mono channel to the first two channels. On most system, ++ // the first two channels are for left and right. It is commonly ++ // expected that mono will on both left+right channels ++ for (uint32_t i = 0; i < frames; i++) { ++ output_buffer[0] = output_buffer[1] = *input_buffer; ++ output_buffer += _context._out_ch_count ; ++ input_buffer++; ++ } ++ return; ++ } + for (uint32_t i = 0; i < frames; i++) { + PodCopy(output_buffer, input_buffer, _context._out_ch_count); + output_buffer += _context._out_ch_count; +-- +2.17.0 + diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp index 6163ed72ad74..5a83098cc8e5 100644 --- a/media/libcubeb/src/cubeb_audiounit.cpp +++ b/media/libcubeb/src/cubeb_audiounit.cpp @@ -291,7 +291,7 @@ cubeb_channel_to_channel_label(cubeb_channel channel) case CHANNEL_TOP_BACK_RIGHT: return kAudioChannelLabel_TopBackRight; default: - return CHANNEL_UNKNOWN; + return kAudioChannelLabel_Unknown; } } @@ -1232,13 +1232,49 @@ audiounit_convert_channel_layout(AudioChannelLayout * layout) cubeb_channel_layout cl = 0; for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) { - cl |= channel_label_to_cubeb_channel( + cubeb_channel cc = channel_label_to_cubeb_channel( layout->mChannelDescriptions[i].mChannelLabel); + if (cc == CHANNEL_UNKNOWN) { + return CUBEB_LAYOUT_UNDEFINED; + } + cl |= cc; } return cl; } +static cubeb_channel_layout +audiounit_get_preferred_channel_layout(AudioUnit output_unit) +{ + OSStatus rv = noErr; + UInt32 size = 0; + rv = AudioUnitGetPropertyInfo(output_unit, + kAudioDevicePropertyPreferredChannelLayout, + kAudioUnitScope_Output, + AU_OUT_BUS, + &size, + nullptr); + if (rv != noErr) { + LOG("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout rv=%d", rv); + return CUBEB_LAYOUT_UNDEFINED; + } + assert(size > 0); + + auto layout = make_sized_audio_channel_layout(size); + rv = AudioUnitGetProperty(output_unit, + kAudioDevicePropertyPreferredChannelLayout, + kAudioUnitScope_Output, + AU_OUT_BUS, + layout.get(), + &size); + if (rv != noErr) { + LOG("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout rv=%d", rv); + return CUBEB_LAYOUT_UNDEFINED; + } + + return audiounit_convert_channel_layout(layout.get()); +} + static cubeb_channel_layout audiounit_get_current_channel_layout(AudioUnit output_unit) { @@ -1252,7 +1288,8 @@ audiounit_get_current_channel_layout(AudioUnit output_unit) nullptr); if (rv != noErr) { LOG("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout rv=%d", rv); - return CUBEB_LAYOUT_UNDEFINED; + // This property isn't known before macOS 10.12, attempt another method. + return audiounit_get_preferred_channel_layout(output_unit); } assert(size > 0); diff --git a/media/libcubeb/src/cubeb_mixer.cpp b/media/libcubeb/src/cubeb_mixer.cpp index 8995c55ed792..9aa141d05ed6 100644 --- a/media/libcubeb/src/cubeb_mixer.cpp +++ b/media/libcubeb/src/cubeb_mixer.cpp @@ -533,6 +533,18 @@ struct cubeb_mixer output_buffer += _context._out_ch_count - _context._in_ch_count; } } else { + if (_context._in_ch_count == 1 && _context._out_ch_count >= 2) { + // Special case for upmixing mono input to stereo and more. We will + // duplicate the mono channel to the first two channels. On most system, + // the first two channels are for left and right. It is commonly + // expected that mono will on both left+right channels + for (uint32_t i = 0; i < frames; i++) { + output_buffer[0] = output_buffer[1] = *input_buffer; + output_buffer += _context._out_ch_count ; + input_buffer++; + } + return; + } for (uint32_t i = 0; i < frames; i++) { PodCopy(output_buffer, input_buffer, _context._out_ch_count); output_buffer += _context._out_ch_count; diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh index 864ab3391340..4fd5f4c44e8e 100755 --- a/media/libcubeb/update.sh +++ b/media/libcubeb/update.sh @@ -83,3 +83,8 @@ patch -p3 < prefer-pulse-rust.patch echo "Applying disable-device-switching.patch on top of $rev" patch -p3 < disable-device-switching.patch +echo "Applying Correctly-retrieve-the-output-layout-on-macOS-10.12.patch on top of $rev" +patch -p1 < 0001-Correctly-retrieve-the-output-layout-on-macOS-10.12.patch + +echo "Applying Always-upmix-mono-to-the-first-two-channels-if-enoug.patch on top of $rev" +patch -p1 < 0002-Always-upmix-mono-to-the-first-two-channels-if-enoug.patch