Bug 1321502 - part 1: Enable multi-channel support in Gecko on Windows; r=jya
MozReview-Commit-ID: KURUk3EffOu
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -313,30 +313,31 @@ struct ToCubebFormat<AUDIO_FORMAT_S16> {
template <typename Function, typename... Args>
int AudioStream::InvokeCubeb(Function aFunction, Args&&... aArgs)
{
MonitorAutoUnlock mon(mMonitor);
return aFunction(mCubebStream.get(), Forward<Args>(aArgs)...);
}
nsresult
-AudioStream::Init(uint32_t aNumChannels, uint32_t aRate,
+AudioStream::Init(uint32_t aNumChannels, uint32_t aChannelMap, uint32_t aRate,
const dom::AudioChannel aAudioChannel)
{
auto startTime = TimeStamp::Now();
LOG("%s channels: %d, rate: %d", __FUNCTION__, aNumChannels, aRate);
mChannels = aNumChannels;
mOutChannels = aNumChannels;
mDumpFile = OpenDumpFile(aNumChannels, aRate);
cubeb_stream_params params;
params.rate = aRate;
params.channels = mOutChannels;
+ params.layout = CubebUtils::ConvertChannelMapToCubebLayout(aChannelMap);
#if defined(__ANDROID__)
#if defined(MOZ_B2G)
params.stream_type = CubebUtils::ConvertChannelToCubebType(aAudioChannel);
#else
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
@@ -349,20 +350,16 @@ AudioStream::Init(uint32_t aNumChannels,
cubeb* cubebContext = CubebUtils::GetCubebContext();
if (!cubebContext) {
NS_WARNING("Can't get cubeb context!");
CubebUtils::ReportCubebStreamInitFailure(true);
return NS_ERROR_DOM_MEDIA_CUBEB_INITIALIZATION_ERR;
}
- // The DecodedAudioDataSink forces mono or stereo for now.
- params.layout = params.channels == 1 ? CUBEB_LAYOUT_MONO
- : CUBEB_LAYOUT_STEREO;
-
return OpenCubeb(cubebContext, params, startTime, CubebUtils::GetFirstStream());
}
nsresult
AudioStream::OpenCubeb(cubeb* aContext, cubeb_stream_params& aParams,
TimeStamp aStartTime, bool aIsFirst)
{
MOZ_ASSERT(aContext);
--- a/dom/media/AudioStream.h
+++ b/dom/media/AudioStream.h
@@ -183,19 +183,20 @@ public:
virtual void Drained() = 0;
protected:
virtual ~DataSource() {}
};
explicit AudioStream(DataSource& aSource);
// Initialize the audio stream. aNumChannels is the number of audio
- // channels (1 for mono, 2 for stereo, etc) and aRate is the sample rate
+ // channels (1 for mono, 2 for stereo, etc), aChannelMap is the indicator for
+ // channel layout(mono, stereo, 5.1 or 7.1 ) and aRate is the sample rate
// (22050Hz, 44100Hz, etc).
- nsresult Init(uint32_t aNumChannels, uint32_t aRate,
+ nsresult Init(uint32_t aNumChannels, uint32_t aChannelMap, uint32_t aRate,
const dom::AudioChannel aAudioStreamChannel);
// Closes the stream. All future use of the stream is an error.
void Shutdown();
void Reset();
// Set the current volume of the audio playback. This is a value from
--- a/dom/media/CubebUtils.cpp
+++ b/dom/media/CubebUtils.cpp
@@ -19,16 +19,33 @@
#include "nsAutoRef.h"
#include "prdtoa.h"
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_LATENCY_PLAYBACK "media.cubeb_latency_playback_ms"
#define PREF_CUBEB_LATENCY_MSG "media.cubeb_latency_msg_frames"
#define PREF_CUBEB_LOG_LEVEL "media.cubeb.log_level"
+#define MASK_MONO (1 << AudioConfig::CHANNEL_MONO)
+#define MASK_MONO_LFE (MASK_MONO | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_STEREO ((1 << AudioConfig::CHANNEL_LEFT) | (1 << AudioConfig::CHANNEL_RIGHT))
+#define MASK_STEREO_LFE (MASK_STEREO | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_3F (MASK_STEREO | (1 << AudioConfig::CHANNEL_CENTER))
+#define MASK_3F_LFE (MASK_3F | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_2F1 (MASK_STEREO | (1 << AudioConfig::CHANNEL_RCENTER))
+#define MASK_2F1_LFE (MASK_2F1 | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_3F1 (MASK_3F | (1 < AudioConfig::CHANNEL_RCENTER))
+#define MASK_3F1_LFE (MASK_3F1 | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_2F2 (MASK_STEREO | (1 << AudioConfig::CHANNEL_LS) | (1 << AudioConfig::CHANNEL_RS))
+#define MASK_2F2_LFE (MASK_2F2 | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_3F2 (MASK_3F | (1 << AudioConfig::CHANNEL_LS) | (1 << AudioConfig::CHANNEL_RS))
+#define MASK_3F2_LFE (MASK_3F2 | (1 << AudioConfig::CHANNEL_LFE))
+#define MASK_3F3R_LFE (MASK_3F2_LFE | (1 << AudioConfig::CHANNEL_RCENTER))
+#define MASK_3F4_LFE (MASK_3F2_LFE | (1 << AudioConfig::CHANNEL_RLS) | (1 << AudioConfig::CHANNEL_RRS))
+
namespace mozilla {
namespace {
LazyLogModule gCubebLog("cubeb");
void CubebLogCallback(const char* aFmt, ...)
{
@@ -354,16 +371,41 @@ uint32_t MaxNumberOfChannels()
cubeb_get_max_channel_count(cubebContext,
&maxNumberOfChannels) == CUBEB_OK) {
return maxNumberOfChannels;
}
return 0;
}
+cubeb_channel_layout ConvertChannelMapToCubebLayout(uint32_t aChannelMap)
+{
+ switch(aChannelMap) {
+ case MASK_MONO: return CUBEB_LAYOUT_MONO;
+ case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
+ case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
+ case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
+ case MASK_3F: return CUBEB_LAYOUT_3F;
+ case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
+ case MASK_2F1: return CUBEB_LAYOUT_2F1;
+ case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
+ case MASK_3F1: return CUBEB_LAYOUT_3F1;
+ case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
+ case MASK_2F2: return CUBEB_LAYOUT_2F2;
+ case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
+ case MASK_3F2: return CUBEB_LAYOUT_3F2;
+ case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
+ case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
+ case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
+ default:
+ NS_ERROR("The channel map is unsupported");
+ return CUBEB_LAYOUT_UNDEFINED;
+ }
+}
+
#if defined(__ANDROID__) && defined(MOZ_B2G)
cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
{
switch(aChannel) {
case dom::AudioChannel::Normal:
/* FALLTHROUGH */
case dom::AudioChannel::Content:
return CUBEB_STREAM_TYPE_MUSIC;
--- a/dom/media/CubebUtils.h
+++ b/dom/media/CubebUtils.h
@@ -35,16 +35,17 @@ double GetVolumeScale();
bool GetFirstStream();
cubeb* GetCubebContext();
cubeb* GetCubebContextUnlocked();
void ReportCubebStreamInitFailure(bool aIsFirstStream);
void ReportCubebBackendUsed();
uint32_t GetCubebPlaybackLatencyInMilliseconds();
Maybe<uint32_t> GetCubebMSGLatencyInFrames();
bool CubebLatencyPrefSet();
+cubeb_channel_layout ConvertChannelMapToCubebLayout(uint32_t aChannelMap);
#if defined(__ANDROID__) && defined(MOZ_B2G)
cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel);
#endif
void GetCurrentBackend(nsAString& aBackend);
} // namespace CubebUtils
} // namespace mozilla
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -85,18 +85,22 @@ private:
};
// This is where DECL_MEDIA_PREF for each of the preferences should go.
// AudioSink
DECL_MEDIA_PREF("accessibility.monoaudio.enable", MonoAudio, bool, false);
DECL_MEDIA_PREF("media.resampling.enabled", AudioSinkResampling, bool, false);
DECL_MEDIA_PREF("media.resampling.rate", AudioSinkResampleRate, uint32_t, 48000);
+#if defined(XP_WIN)
+ // Enable multiple channel support on Windows.
+ DECL_MEDIA_PREF("media.forcestereo.enabled", AudioSinkForceStereo, bool, false);
+#else
DECL_MEDIA_PREF("media.forcestereo.enabled", AudioSinkForceStereo, bool, true);
-
+#endif
// VideoSink
DECL_MEDIA_PREF("media.ruin-av-sync.enabled", RuinAvSync, bool, false);
// Encrypted Media Extensions
DECL_MEDIA_PREF("media.clearkey.persistent-license.enabled", ClearKeyPersistentLicenseEnabled, bool, false);
// PlatformDecoderModule
DECL_MEDIA_PREF("media.apple.forcevda", AppleForceVDA, bool, false);
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -190,17 +190,23 @@ DecodedAudioDataSink::SetPlaying(bool aP
}
mPlaying = aPlaying;
}
nsresult
DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
{
mAudioStream = new AudioStream(*this);
- nsresult rv = mAudioStream->Init(mOutputChannels, mOutputRate, mChannel);
+ // The layout map used here is already processed by mConverter with
+ // mOutputChannels into SMPTE format, so there is no need to worry if
+ // MediaPrefs::MonoAudio() or MediaPrefs::AudioSinkForceStereo() is applied.
+ nsresult rv = mAudioStream->Init(mOutputChannels,
+ mConverter->OutputConfig().Layout().Map(),
+ mOutputRate,
+ mChannel);
if (NS_FAILED(rv)) {
mAudioStream->Shutdown();
mAudioStream = nullptr;
return rv;
}
// Set playback params before calling Start() so they can take effect
// as soon as the 1st DataCallback of the AudioStream fires.