Bug 1469152: Fix playback on older macOS systems and some 3rd party audio cards. r=kinetik

We were using an audio API not available prior 10.12. Also add a workaround for 3rd party audio cards with unusually high channels count.

This cherry-pick cubeb commits 59f5cb4ba01f21c4ad87e9404d1e470408e18505 and dbd61924736fbe1a1caf1cbd544f7d197f1836f7

Differential Revision: https://phabricator.services.mozilla.com/D2041

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jean-Yves Avenard 2018-07-10 08:45:49 +00:00
Родитель 96465b5cd1
Коммит 5041ae2d32
5 изменённых файлов: 192 добавлений и 3 удалений

Просмотреть файл

@ -0,0 +1,68 @@
From 59f5cb4ba01f21c4ad87e9404d1e470408e18505 Mon Sep 17 00:00:00 2001
From: Jean-Yves Avenard <jyavenard@mozilla.com>
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

Просмотреть файл

@ -0,0 +1,67 @@
From dbd61924736fbe1a1caf1cbd544f7d197f1836f7 Mon Sep 17 00:00:00 2001
From: Jean-Yves Avenard <jyavenard@mozilla.com>
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

Просмотреть файл

@ -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);

Просмотреть файл

@ -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;

Просмотреть файл

@ -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