Bug 848954 - Part 6 - Put cubeb-related static functions in their own file. r=kinetik

This commit is contained in:
Paul Adenot 2014-08-25 15:26:09 +02:00
parent 735258f143
commit bf1afe6d99
8 changed files with 263 additions and 215 deletions

View File

@ -13,10 +13,10 @@
#include "mozilla/Monitor.h"
#include "mozilla/Mutex.h"
#include <algorithm>
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "soundtouch/SoundTouch.h"
#include "Latency.h"
#include "CubebUtils.h"
#include "nsPrintfCString.h"
#ifdef XP_MACOSX
#include <sys/sysctl.h>
@ -44,19 +44,6 @@ PRLogModuleInfo* gAudioStreamLog = nullptr;
*/
static int gDumpedAudioCount = 0;
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_LATENCY "media.cubeb_latency_ms"
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
StaticMutex AudioStream::sMutex;
cubeb* AudioStream::sCubebContext;
uint32_t AudioStream::sPreferredSampleRate;
double AudioStream::sVolumeScale;
uint32_t AudioStream::sCubebLatency;
bool AudioStream::sCubebLatencyPrefSet;
/**
* Keep a list of frames sent to the audio engine in each DataCallback along
* with the playback rate at the moment. Since the playback rate and number of
@ -138,108 +125,6 @@ private:
double mBasePosition;
};
/*static*/ void AudioStream::PrefChanged(const char* aPref, void* aClosure)
{
if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
nsAdoptingString value = Preferences::GetString(aPref);
StaticMutexAutoLock lock(sMutex);
if (value.IsEmpty()) {
sVolumeScale = 1.0;
} else {
NS_ConvertUTF16toUTF8 utf8(value);
sVolumeScale = std::max<double>(0, PR_strtod(utf8.get(), nullptr));
}
} else if (strcmp(aPref, PREF_CUBEB_LATENCY) == 0) {
// Arbitrary default stream latency of 100ms. The higher this
// value, the longer stream volume changes will take to become
// audible.
sCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
StaticMutexAutoLock lock(sMutex);
sCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
}
}
/*static*/ bool AudioStream::GetFirstStream()
{
static bool sFirstStream = true;
StaticMutexAutoLock lock(sMutex);
bool result = sFirstStream;
sFirstStream = false;
return result;
}
/*static*/ double AudioStream::GetVolumeScale()
{
StaticMutexAutoLock lock(sMutex);
return sVolumeScale;
}
/*static*/ cubeb* AudioStream::GetCubebContext()
{
StaticMutexAutoLock lock(sMutex);
return GetCubebContextUnlocked();
}
/*static*/ void AudioStream::InitPreferredSampleRate()
{
StaticMutexAutoLock lock(sMutex);
if (sPreferredSampleRate == 0 &&
cubeb_get_preferred_sample_rate(GetCubebContextUnlocked(),
&sPreferredSampleRate) != CUBEB_OK) {
sPreferredSampleRate = 44100;
}
}
/*static*/ cubeb* AudioStream::GetCubebContextUnlocked()
{
sMutex.AssertCurrentThreadOwns();
if (sCubebContext ||
cubeb_init(&sCubebContext, "AudioStream") == CUBEB_OK) {
return sCubebContext;
}
NS_WARNING("cubeb_init failed");
return nullptr;
}
/*static*/ uint32_t AudioStream::GetCubebLatency()
{
StaticMutexAutoLock lock(sMutex);
return sCubebLatency;
}
/*static*/ bool AudioStream::CubebLatencyPrefSet()
{
StaticMutexAutoLock lock(sMutex);
return sCubebLatencyPrefSet;
}
#if defined(__ANDROID__) && defined(MOZ_B2G)
static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
{
switch(aChannel) {
case dom::AudioChannel::Normal:
return CUBEB_STREAM_TYPE_SYSTEM;
case dom::AudioChannel::Content:
return CUBEB_STREAM_TYPE_MUSIC;
case dom::AudioChannel::Notification:
return CUBEB_STREAM_TYPE_NOTIFICATION;
case dom::AudioChannel::Alarm:
return CUBEB_STREAM_TYPE_ALARM;
case dom::AudioChannel::Telephony:
return CUBEB_STREAM_TYPE_VOICE_CALL;
case dom::AudioChannel::Ringer:
return CUBEB_STREAM_TYPE_RING;
case dom::AudioChannel::Publicnotification:
return CUBEB_STREAM_TYPE_SYSTEM_ENFORCED;
default:
NS_ERROR("The value of AudioChannel is invalid");
return CUBEB_STREAM_TYPE_MAX;
}
}
#endif
AudioStream::AudioStream()
: mMonitor("AudioStream")
, mInRate(0)
@ -287,29 +172,6 @@ AudioStream::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
return amount;
}
/*static*/ void AudioStream::InitLibrary()
{
#ifdef PR_LOGGING
gAudioStreamLog = PR_NewLogModule("AudioStream");
#endif
PrefChanged(PREF_VOLUME_SCALE, nullptr);
Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
PrefChanged(PREF_CUBEB_LATENCY, nullptr);
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
}
/*static*/ void AudioStream::ShutdownLibrary()
{
Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
StaticMutexAutoLock lock(sMutex);
if (sCubebContext) {
cubeb_destroy(sCubebContext);
sCubebContext = nullptr;
}
}
nsresult AudioStream::EnsureTimeStretcherInitializedUnlocked()
{
mMonitor.AssertCurrentThreadOwns();
@ -387,26 +249,6 @@ int64_t AudioStream::GetWritten()
return mWritten;
}
/*static*/ int AudioStream::MaxNumberOfChannels()
{
cubeb* cubebContext = GetCubebContext();
uint32_t maxNumberOfChannels;
if (cubebContext &&
cubeb_get_max_channel_count(cubebContext,
&maxNumberOfChannels) == CUBEB_OK) {
return static_cast<int>(maxNumberOfChannels);
}
return 0;
}
/*static*/ int AudioStream::PreferredSampleRate()
{
MOZ_ASSERT(sPreferredSampleRate,
"sPreferredSampleRate has not been initialized!");
return sPreferredSampleRate;
}
static void SetUint16LE(uint8_t* aDest, uint16_t aValue)
{
aDest[0] = aValue & 0xFF;
@ -484,9 +326,9 @@ AudioStream::Init(int32_t aNumChannels, int32_t aRate,
LatencyRequest aLatencyRequest)
{
mStartTime = TimeStamp::Now();
mIsFirst = GetFirstStream();
mIsFirst = CubebUtils::GetFirstStream();
if (!GetCubebContext() || aNumChannels < 0 || aRate < 0) {
if (!CubebUtils::GetCubebContext() || aNumChannels < 0 || aRate < 0) {
return NS_ERROR_FAILURE;
}
@ -634,7 +476,7 @@ nsresult
AudioStream::OpenCubeb(cubeb_stream_params &aParams,
LatencyRequest aLatencyRequest)
{
cubeb* cubebContext = GetCubebContext();
cubeb* cubebContext = CubebUtils::GetCubebContext();
if (!cubebContext) {
NS_WARNING("Can't get cubeb context!");
MonitorAutoLock mon(mMonitor);
@ -646,12 +488,12 @@ AudioStream::OpenCubeb(cubeb_stream_params &aParams,
// for low latency playback, try to get the lowest latency possible.
// Otherwise, for normal streams, use 100ms.
uint32_t latency;
if (aLatencyRequest == LowLatency && !CubebLatencyPrefSet()) {
if (aLatencyRequest == LowLatency && !CubebUtils::CubebLatencyPrefSet()) {
if (cubeb_get_min_latency(cubebContext, aParams, &latency) != CUBEB_OK) {
latency = GetCubebLatency();
latency = CubebUtils::GetCubebLatency();
}
} else {
latency = GetCubebLatency();
latency = CubebUtils::GetCubebLatency();
}
{
@ -844,7 +686,7 @@ AudioStream::SetVolume(double aVolume)
{
NS_ABORT_IF_FALSE(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
if (cubeb_stream_set_volume(mCubebStream.get(), aVolume * GetVolumeScale()) != CUBEB_OK) {
if (cubeb_stream_set_volume(mCubebStream, aVolume * CubebUtils::GetVolumeScale()) != CUBEB_OK) {
NS_WARNING("Could not change volume on cubeb stream.");
}
}

View File

@ -13,10 +13,8 @@
#include "Latency.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/UniquePtr.h"
#include "cubeb/cubeb.h"
#include "CubebUtils.h"
namespace soundtouch {
class SoundTouch;
@ -186,24 +184,6 @@ class AudioStream MOZ_FINAL
virtual ~AudioStream();
public:
// Initialize Audio Library. Some Audio backends require initializing the
// library before using it.
static void InitLibrary();
// Shutdown Audio Library. Some Audio backends require shutting down the
// library after using it.
static void ShutdownLibrary();
// Returns the maximum number of channels supported by the audio hardware.
static int MaxNumberOfChannels();
// Queries the samplerate the hardware/mixer runs at, and stores it.
// Can be called on any thread. When this returns, it is safe to call
// PreferredSampleRate without locking.
static void InitPreferredSampleRate();
// Get the aformentionned sample rate. Does not lock.
static int PreferredSampleRate();
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioStream)
AudioStream();
@ -305,14 +285,6 @@ private:
void CheckForStart();
static void PrefChanged(const char* aPref, void* aClosure);
static double GetVolumeScale();
static bool GetFirstStream();
static cubeb* GetCubebContext();
static cubeb* GetCubebContextUnlocked();
static uint32_t GetCubebLatency();
static bool CubebLatencyPrefSet();
static long DataCallback_S(cubeb_stream*, void* aThis, void* aBuffer, long aFrames)
{
return static_cast<AudioStream*>(aThis)->DataCallback(aBuffer, aFrames);
@ -430,18 +402,6 @@ private:
// True if there is a pending AudioInitTask. Shutdown() will wait until the
// pending AudioInitTask is finished.
bool mPendingAudioInitTask;
// This mutex protects the static members below.
static StaticMutex sMutex;
static cubeb* sCubebContext;
// Prefered samplerate, in Hz (characteristic of the
// hardware/mixer/platform/API used).
static uint32_t sPreferredSampleRate;
static double sVolumeScale;
static uint32_t sCubebLatency;
static bool sCubebLatencyPrefSet;
};
class AudioInitTask : public nsRunnable

View File

@ -0,0 +1,172 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdint.h>
#include "mozilla/Preferences.h"
#include "CubebUtils.h"
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_LATENCY "media.cubeb_latency_ms"
namespace mozilla {
extern PRLogModuleInfo* gAudioStreamLog;
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
StaticMutex CubebUtils::sMutex;
cubeb* CubebUtils::sCubebContext;
uint32_t CubebUtils::sPreferredSampleRate;
double CubebUtils::sVolumeScale;
uint32_t CubebUtils::sCubebLatency;
bool CubebUtils::sCubebLatencyPrefSet;
/*static*/ void CubebUtils::PrefChanged(const char* aPref, void* aClosure)
{
if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
nsAdoptingString value = Preferences::GetString(aPref);
StaticMutexAutoLock lock(sMutex);
if (value.IsEmpty()) {
sVolumeScale = 1.0;
} else {
NS_ConvertUTF16toUTF8 utf8(value);
sVolumeScale = std::max<double>(0, PR_strtod(utf8.get(), nullptr));
}
} else if (strcmp(aPref, PREF_CUBEB_LATENCY) == 0) {
// Arbitrary default stream latency of 100ms. The higher this
// value, the longer stream volume changes will take to become
// audible.
sCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
StaticMutexAutoLock lock(sMutex);
sCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
}
}
/*static*/ bool CubebUtils::GetFirstStream()
{
static bool sFirstStream = true;
StaticMutexAutoLock lock(sMutex);
bool result = sFirstStream;
sFirstStream = false;
return result;
}
/*static*/ double CubebUtils::GetVolumeScale()
{
StaticMutexAutoLock lock(sMutex);
return sVolumeScale;
}
/*static*/ cubeb* CubebUtils::GetCubebContext()
{
StaticMutexAutoLock lock(sMutex);
return GetCubebContextUnlocked();
}
/*static*/ void CubebUtils::InitPreferredSampleRate()
{
StaticMutexAutoLock lock(sMutex);
if (sPreferredSampleRate == 0 &&
cubeb_get_preferred_sample_rate(GetCubebContextUnlocked(),
&sPreferredSampleRate) != CUBEB_OK) {
sPreferredSampleRate = 44100;
}
}
/*static*/ cubeb* CubebUtils::GetCubebContextUnlocked()
{
sMutex.AssertCurrentThreadOwns();
if (sCubebContext ||
cubeb_init(&sCubebContext, "CubebUtils") == CUBEB_OK) {
return sCubebContext;
}
NS_WARNING("cubeb_init failed");
return nullptr;
}
/*static*/ uint32_t CubebUtils::GetCubebLatency()
{
StaticMutexAutoLock lock(sMutex);
return sCubebLatency;
}
/*static*/ bool CubebUtils::CubebLatencyPrefSet()
{
StaticMutexAutoLock lock(sMutex);
return sCubebLatencyPrefSet;
}
/*static*/ void CubebUtils::InitLibrary()
{
#ifdef PR_LOGGING
gAudioStreamLog = PR_NewLogModule("AudioStream");
#endif
PrefChanged(PREF_VOLUME_SCALE, nullptr);
Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
PrefChanged(PREF_CUBEB_LATENCY, nullptr);
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
}
/*static*/ void CubebUtils::ShutdownLibrary()
{
Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
StaticMutexAutoLock lock(sMutex);
if (sCubebContext) {
cubeb_destroy(sCubebContext);
sCubebContext = nullptr;
}
}
/*static*/ int CubebUtils::MaxNumberOfChannels()
{
cubeb* cubebContext = CubebUtils::GetCubebContext();
uint32_t maxNumberOfChannels;
if (cubebContext &&
cubeb_get_max_channel_count(cubebContext,
&maxNumberOfChannels) == CUBEB_OK) {
return static_cast<int>(maxNumberOfChannels);
}
return 0;
}
/*static*/ int CubebUtils::PreferredSampleRate()
{
MOZ_ASSERT(sPreferredSampleRate,
"sPreferredSampleRate has not been initialized!");
return sPreferredSampleRate;
}
#if defined(__ANDROID__) && defined(MOZ_B2G)
static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel)
{
switch(aChannel) {
case dom::AudioChannel::Normal:
return CUBEB_STREAM_TYPE_SYSTEM;
case dom::AudioChannel::Content:
return CUBEB_STREAM_TYPE_MUSIC;
case dom::AudioChannel::Notification:
return CUBEB_STREAM_TYPE_NOTIFICATION;
case dom::AudioChannel::Alarm:
return CUBEB_STREAM_TYPE_ALARM;
case dom::AudioChannel::Telephony:
return CUBEB_STREAM_TYPE_VOICE_CALL;
case dom::AudioChannel::Ringer:
return CUBEB_STREAM_TYPE_RING;
case dom::AudioChannel::Publicnotification:
return CUBEB_STREAM_TYPE_SYSTEM_ENFORCED;
default:
NS_ERROR("The value of AudioChannel is invalid");
return CUBEB_STREAM_TYPE_MAX;
}
}
#endif
}

View File

@ -0,0 +1,72 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(CubebUtils_h_)
#define CubebUtils_h_
#include "cubeb/cubeb.h"
#include "nsAutoRef.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/dom/AudioChannelBinding.h"
template <>
class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
{
public:
static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
};
namespace mozilla {
class CubebUtils {
public:
// Initialize Audio Library. Some Audio backends require initializing the
// library before using it.
static void InitLibrary();
// Shutdown Audio Library. Some Audio backends require shutting down the
// library after using it.
static void ShutdownLibrary();
// Returns the maximum number of channels supported by the audio hardware.
static int MaxNumberOfChannels();
// Queries the samplerate the hardware/mixer runs at, and stores it.
// Can be called on any thread. When this returns, it is safe to call
// PreferredSampleRate without locking.
static void InitPreferredSampleRate();
// Get the aformentionned sample rate. Does not lock.
static int PreferredSampleRate();
static void PrefChanged(const char* aPref, void* aClosure);
static double GetVolumeScale();
static bool GetFirstStream();
static cubeb* GetCubebContext();
static cubeb* GetCubebContextUnlocked();
static uint32_t GetCubebLatency();
static bool CubebLatencyPrefSet();
#if defined(__ANDROID__) && defined(MOZ_B2G)
static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannel aChannel);
#endif
private:
// This mutex protects the static members below.
static StaticMutex sMutex;
static cubeb* sCubebContext;
// Prefered samplerate, in Hz (characteristic of the
// hardware/mixer/platform/API used).
static uint32_t sPreferredSampleRate;
static double sVolumeScale;
static uint32_t sCubebLatency;
static bool sCubebLatencyPrefSet;
};
}
#endif // CubebUtils_h_

View File

@ -2728,9 +2728,9 @@ MediaStreamGraph::GetInstance()
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
}
AudioStream::InitPreferredSampleRate();
CubebUtils::InitPreferredSampleRate();
gGraph = new MediaStreamGraphImpl(true, AudioStream::PreferredSampleRate());
gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate());
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
}

View File

@ -70,6 +70,7 @@ EXPORTS += [
'AudioSegment.h',
'AudioStream.h',
'BufferMediaResource.h',
'CubebUtils.h',
'DecoderTraits.h',
'DOMMediaStream.h',
'EncodedBufferCache.h',
@ -133,6 +134,7 @@ UNIFIED_SOURCES += [
'AudioStreamTrack.cpp',
'AudioTrack.cpp',
'AudioTrackList.cpp',
'CubebUtils.cpp',
'DOMMediaStream.cpp',
'EncodedBufferCache.cpp',
'FileBlockCache.cpp',

View File

@ -71,8 +71,8 @@ static float GetSampleRateForAudioContext(bool aIsOffline, float aSampleRate)
if (aIsOffline) {
return aSampleRate;
} else {
AudioStream::InitPreferredSampleRate();
return static_cast<float>(AudioStream::PreferredSampleRate());
CubebUtils::InitPreferredSampleRate();
return static_cast<float>(CubebUtils::PreferredSampleRate());
}
}
@ -518,7 +518,7 @@ AudioContext::UpdatePannerSource()
uint32_t
AudioContext::MaxChannelCount() const
{
return mIsOffline ? mNumberOfChannels : AudioStream::MaxNumberOfChannels();
return mIsOffline ? mNumberOfChannels : CubebUtils::MaxNumberOfChannels();
}
MediaStreamGraph*

View File

@ -102,7 +102,7 @@
#include "FFmpegRuntimeLinker.h"
#endif
#include "AudioStream.h"
#include "CubebUtils.h"
#include "Latency.h"
#include "WebAudioUtils.h"
@ -263,7 +263,7 @@ nsLayoutStatics::Initialize()
}
AsyncLatencyLogger::InitializeStatics();
AudioStream::InitLibrary();
CubebUtils::InitLibrary();
nsContentSink::InitializeStatics();
nsHtml5Module::InitializeStatics();
@ -379,7 +379,7 @@ nsLayoutStatics::Shutdown()
FFmpegRuntimeLinker::Unlink();
#endif
AudioStream::ShutdownLibrary();
CubebUtils::ShutdownLibrary();
AsyncLatencyLogger::ShutdownLogger();
WebAudioUtils::Shutdown();