Bug 942657 - Devirtualize AudioStream. r=doublec,gps

This commit is contained in:
Matthew Gregan 2013-11-28 18:09:08 +13:00
parent ded7b4c4c5
commit 93237d768e
13 changed files with 414 additions and 492 deletions

View File

@ -33,14 +33,12 @@ if CONFIG['MOZ_VP8'] and not CONFIG['MOZ_NATIVE_LIBVPX']:
if CONFIG['MOZ_OGG']:
external_dirs += ['media/libogg', 'media/libtheora']
if CONFIG['MOZ_CUBEB']:
external_dirs += ['media/libcubeb']
if not CONFIG['MOZ_NATIVE_PNG']:
external_dirs += ['media/libpng']
external_dirs += [
'media/kiss_fft',
'media/libcubeb',
'media/libspeex_resampler',
'media/libsoundtouch',
]

View File

@ -3938,7 +3938,6 @@ MOZ_JSDEBUGGER=1
MOZ_AUTH_EXTENSION=1
MOZ_OGG=1
MOZ_RAW=
MOZ_CUBEB=
MOZ_VORBIS=
MOZ_TREMOR=
MOZ_WAVE=1
@ -5199,7 +5198,6 @@ MOZ_ARG_DISABLE_BOOL(ogg,
if test -n "$MOZ_OGG"; then
AC_DEFINE(MOZ_OGG)
MOZ_CUBEB=1
dnl Checks for __attribute__(aligned()) directive
AC_CACHE_CHECK([__attribute__ ((aligned ())) support],
@ -5259,7 +5257,6 @@ MOZ_ARG_DISABLE_BOOL(directshow,
if test -n "$MOZ_DIRECTSHOW"; then
AC_DEFINE(MOZ_DIRECTSHOW)
MOZ_CUBEB=1
fi;
dnl ========================================================
@ -5279,7 +5276,6 @@ MOZ_ARG_DISABLE_BOOL(wmf,
if test -n "$MOZ_WMF"; then
AC_DEFINE(MOZ_WMF)
MOZ_CUBEB=1
fi;
dnl ========================================================
@ -5410,7 +5406,6 @@ AC_SUBST(MOZ_LIBVPX_CFLAGS)
AC_SUBST(MOZ_LIBVPX_LIBS)
if test "$MOZ_WEBM" -o "$MOZ_OGG"; then
MOZ_CUBEB=1
if test "$MOZ_SAMPLE_TYPE_FLOAT32"; then
MOZ_VORBIS=1
else
@ -5512,17 +5507,12 @@ MOZ_ARG_DISABLE_BOOL(wave,
if test -n "$MOZ_WAVE"; then
AC_DEFINE(MOZ_WAVE)
MOZ_CUBEB=1
fi
dnl ========================================================
dnl = Handle dependent CUBEB and MEDIA defines
dnl = Handle dependent MEDIA defines
dnl ========================================================
if test -n "$MOZ_CUBEB"; then
AC_DEFINE(MOZ_CUBEB)
fi
if test -n "$MOZ_OPUS" -a -z "$MOZ_OGG"; then
AC_MSG_ERROR([MOZ_OPUS requires MOZ_OGG which is disabled.])
fi
@ -5552,12 +5542,12 @@ if test -n "$MOZ_OPUS"; then
AC_DEFINE(MOZ_OPUS)
fi
dnl ====================================================
dnl = Check alsa availability on Linux if using libcubeb
dnl ====================================================
dnl ==================================
dnl = Check alsa availability on Linux
dnl ==================================
dnl If using libcubeb with Linux, ensure that the alsa library is available
if test -n "$MOZ_CUBEB" -a "$OS_TARGET" = "Linux"; then
dnl If using Linux, ensure that the alsa library is available
if test "$OS_TARGET" = "Linux"; then
MOZ_ALSA=1
fi
@ -5567,7 +5557,6 @@ MOZ_ARG_ENABLE_BOOL(alsa,
MOZ_ALSA=)
if test -n "$MOZ_ALSA"; then
AC_DEFINE(MOZ_CUBEB)
PKG_CHECK_MODULES(MOZ_ALSA, alsa, ,
[echo "$MOZ_ALSA_PKG_ERRORS"
AC_MSG_ERROR([Need alsa for Ogg, Wave or WebM decoding on Linux. Disable with --disable-ogg --disable-wave --disable-webm. (On Ubuntu, you might try installing the package libasound2-dev.)])])
@ -5581,8 +5570,8 @@ dnl ========================================================
dnl = Disable PulseAudio
dnl ========================================================
dnl If using libcubeb with Linux, ensure that the PA library is available
if test -n "$MOZ_CUBEB" -a "$OS_TARGET" = "Linux" -a -z "$MOZ_B2G"; then
dnl If using Linux, ensure that the PA library is available
if test "$OS_TARGET" = "Linux" -a -z "$MOZ_B2G"; then
MOZ_PULSEAUDIO=1
fi
@ -5592,7 +5581,6 @@ MOZ_ARG_DISABLE_BOOL(pulseaudio,
MOZ_PULSEAUDIO=1)
if test -n "$MOZ_PULSEAUDIO"; then
AC_DEFINE(MOZ_CUBEB)
if test -z "$gonkdir"; then
PKG_CHECK_MODULES(MOZ_PULSEAUDIO, libpulse, ,
[echo "$MOZ_PULSEAUDIO_PKG_ERRORS"
@ -8655,7 +8643,6 @@ AC_SUBST(MOZ_NSS_PATCH)
AC_SUBST(MOZ_APP_COMPONENT_LIBS)
AC_SUBST(MOZ_APP_EXTRA_LIBS)
AC_SUBST(MOZ_CUBEB)
AC_SUBST(MOZ_WAVE)
AC_SUBST(MOZ_VORBIS)
AC_SUBST(MOZ_TREMOR)

View File

@ -111,7 +111,7 @@ HTMLAudioElement::MozSetup(uint32_t aChannels, uint32_t aRate, ErrorResult& aRv)
}
#endif
mAudioStream = AudioStream::AllocateStream();
mAudioStream = new AudioStream();
aRv = mAudioStream->Init(aChannels, aRate, mAudioChannelType, AudioStream::HighLatency);
if (aRv.Failed()) {
mAudioStream->Shutdown();

View File

@ -16,104 +16,91 @@
#include "soundtouch/SoundTouch.h"
#include "Latency.h"
#if defined(MOZ_CUBEB)
#include "nsAutoRef.h"
#include "cubeb/cubeb.h"
template <>
class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
{
public:
static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
};
#endif
namespace mozilla {
#ifdef PR_LOGGING
PRLogModuleInfo* gAudioStreamLog = nullptr;
#endif
#define PREF_VOLUME_SCALE "media.volume_scale"
#define PREF_CUBEB_LATENCY "media.cubeb_latency_ms"
static Mutex* gAudioPrefsLock = nullptr;
static double gVolumeScale;
static uint32_t gCubebLatency;
static bool gCubebLatencyPrefSet;
static const uint32_t CUBEB_NORMAL_LATENCY_MS = 100;
StaticMutex AudioStream::mMutex;
uint32_t AudioStream::mPreferredSampleRate = 0;
/**
* When MOZ_DUMP_AUDIO is set in the environment (to anything),
* we'll drop a series of files in the current working directory named
* dumped-audio-<nnn>.wav, one per nsBufferedAudioStream created, containing
* dumped-audio-<nnn>.wav, one per AudioStream created, containing
* the audio for the stream including any skips due to underruns.
*/
#if defined(MOZ_CUBEB)
static int gDumpedAudioCount = 0;
#endif
static int PrefChanged(const char* aPref, void* aClosure)
#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;
/*static*/ int AudioStream::PrefChanged(const char* aPref, void* aClosure)
{
if (strcmp(aPref, PREF_VOLUME_SCALE) == 0) {
nsAdoptingString value = Preferences::GetString(aPref);
MutexAutoLock lock(*gAudioPrefsLock);
StaticMutexAutoLock lock(sMutex);
if (value.IsEmpty()) {
gVolumeScale = 1.0;
sVolumeScale = 1.0;
} else {
NS_ConvertUTF16toUTF8 utf8(value);
gVolumeScale = std::max<double>(0, PR_strtod(utf8.get(), nullptr));
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.
gCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
sCubebLatencyPrefSet = Preferences::HasUserValue(aPref);
uint32_t value = Preferences::GetUint(aPref, CUBEB_NORMAL_LATENCY_MS);
MutexAutoLock lock(*gAudioPrefsLock);
gCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
StaticMutexAutoLock lock(sMutex);
sCubebLatency = std::min<uint32_t>(std::max<uint32_t>(value, 1), 1000);
}
return 0;
}
#if defined(MOZ_CUBEB)
static double GetVolumeScale()
/*static*/ double AudioStream::GetVolumeScale()
{
MutexAutoLock lock(*gAudioPrefsLock);
return gVolumeScale;
StaticMutexAutoLock lock(sMutex);
return sVolumeScale;
}
static cubeb* gCubebContext;
static cubeb* GetCubebContext()
/*static*/ cubeb* AudioStream::GetCubebContext()
{
MutexAutoLock lock(*gAudioPrefsLock);
if (gCubebContext ||
cubeb_init(&gCubebContext, "AudioStream") == CUBEB_OK) {
return gCubebContext;
StaticMutexAutoLock lock(sMutex);
return GetCubebContextUnlocked();
}
/*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 GetCubebLatency()
/*static*/ uint32_t AudioStream::GetCubebLatency()
{
MutexAutoLock lock(*gAudioPrefsLock);
return gCubebLatency;
StaticMutexAutoLock lock(sMutex);
return sCubebLatency;
}
static bool CubebLatencyPrefSet()
/*static*/ bool AudioStream::CubebLatencyPrefSet()
{
MutexAutoLock lock(*gAudioPrefsLock);
return gCubebLatencyPrefSet;
StaticMutexAutoLock lock(sMutex);
return sCubebLatencyPrefSet;
}
#endif
#if defined(MOZ_CUBEB) && defined(__ANDROID__) && defined(MOZ_B2G)
#if defined(__ANDROID__) && defined(MOZ_B2G)
static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannelType aType)
{
switch(aType) {
@ -139,52 +126,58 @@ static cubeb_stream_type ConvertChannelToCubebType(dom::AudioChannelType aType)
#endif
AudioStream::AudioStream()
: mInRate(0),
mOutRate(0),
mChannels(0),
mWritten(0),
mAudioClock(MOZ_THIS_IN_INITIALIZER_LIST()),
mLatencyRequest(HighLatency),
mReadPoint(0)
{}
void AudioStream::InitLibrary()
: mMonitor("AudioStream")
, mInRate(0)
, mOutRate(0)
, mChannels(0)
, mWritten(0)
, mAudioClock(MOZ_THIS_IN_INITIALIZER_LIST())
, mLatencyRequest(HighLatency)
, mReadPoint(0)
, mLostFrames(0)
, mDumpFile(nullptr)
, mVolume(1.0)
, mBytesPerFrame(0)
, mState(INITIALIZED)
{
#ifdef PR_LOGGING
gAudioStreamLog = PR_NewLogModule("AudioStream");
#endif
gAudioPrefsLock = new Mutex("AudioStream::gAudioPrefsLock");
PrefChanged(PREF_VOLUME_SCALE, nullptr);
Preferences::RegisterCallback(PrefChanged, PREF_VOLUME_SCALE);
#if defined(MOZ_CUBEB)
PrefChanged(PREF_CUBEB_LATENCY, nullptr);
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
#endif
}
void AudioStream::ShutdownLibrary()
{
Preferences::UnregisterCallback(PrefChanged, PREF_VOLUME_SCALE);
#if defined(MOZ_CUBEB)
Preferences::UnregisterCallback(PrefChanged, PREF_CUBEB_LATENCY);
#endif
delete gAudioPrefsLock;
gAudioPrefsLock = nullptr;
#if defined(MOZ_CUBEB)
if (gCubebContext) {
cubeb_destroy(gCubebContext);
gCubebContext = nullptr;
}
#endif
// keep a ref in case we shut down later than nsLayoutStatics
mLatencyLog = AsyncLatencyLogger::Get(true);
}
AudioStream::~AudioStream()
{
Shutdown();
if (mDumpFile) {
fclose(mDumpFile);
}
}
/*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::EnsureTimeStretcherInitialized()
{
MonitorAutoLock mon(mMonitor);
if (!mTimeStretcher) {
// SoundTouch does not support a number of channels > 2
if (mChannels > 2) {
@ -254,224 +247,43 @@ int64_t AudioStream::GetWritten()
return mWritten;
}
#if defined(MOZ_CUBEB)
class nsCircularByteBuffer
/*static*/ int AudioStream::MaxNumberOfChannels()
{
public:
nsCircularByteBuffer()
: mBuffer(nullptr), mCapacity(0), mStart(0), mCount(0)
{}
// Set the capacity of the buffer in bytes. Must be called before any
// call to append or pop elements.
void SetCapacity(uint32_t aCapacity) {
NS_ABORT_IF_FALSE(!mBuffer, "Buffer allocated.");
mCapacity = aCapacity;
mBuffer = new uint8_t[mCapacity];
}
uint32_t Length() {
return mCount;
}
uint32_t Capacity() {
return mCapacity;
}
uint32_t Available() {
return Capacity() - Length();
}
// Append aLength bytes from aSrc to the buffer. Caller must check that
// sufficient space is available.
void AppendElements(const uint8_t* aSrc, uint32_t aLength) {
NS_ABORT_IF_FALSE(mBuffer && mCapacity, "Buffer not initialized.");
NS_ABORT_IF_FALSE(aLength <= Available(), "Buffer full.");
uint32_t end = (mStart + mCount) % mCapacity;
uint32_t toCopy = std::min(mCapacity - end, aLength);
memcpy(&mBuffer[end], aSrc, toCopy);
memcpy(&mBuffer[0], aSrc + toCopy, aLength - toCopy);
mCount += aLength;
}
// Remove aSize bytes from the buffer. Caller must check returned size in
// aSize{1,2} before using the pointer returned in aData{1,2}. Caller
// must not specify an aSize larger than Length().
void PopElements(uint32_t aSize, void** aData1, uint32_t* aSize1,
void** aData2, uint32_t* aSize2) {
NS_ABORT_IF_FALSE(mBuffer && mCapacity, "Buffer not initialized.");
NS_ABORT_IF_FALSE(aSize <= Length(), "Request too large.");
*aData1 = &mBuffer[mStart];
*aSize1 = std::min(mCapacity - mStart, aSize);
*aData2 = &mBuffer[0];
*aSize2 = aSize - *aSize1;
mCount -= *aSize1 + *aSize2;
mStart += *aSize1 + *aSize2;
mStart %= mCapacity;
}
private:
nsAutoArrayPtr<uint8_t> mBuffer;
uint32_t mCapacity;
uint32_t mStart;
uint32_t mCount;
};
class BufferedAudioStream : public AudioStream
{
public:
BufferedAudioStream();
~BufferedAudioStream();
nsresult Init(int32_t aNumChannels, int32_t aRate,
const dom::AudioChannelType aAudioChannelType,
AudioStream::LatencyRequest aLatencyRequest);
void Shutdown();
nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime = nullptr);
uint32_t Available();
void SetVolume(double aVolume);
void Drain();
void Start();
void Pause();
void Resume();
int64_t GetPosition();
int64_t GetPositionInFrames();
int64_t GetPositionInFramesInternal();
int64_t GetLatencyInFrames();
bool IsPaused();
void GetBufferInsertTime(int64_t &aTimeMs);
// This method acquires the monitor and forward the call to the base
// class, to prevent a race on |mTimeStretcher|, in
// |AudioStream::EnsureTimeStretcherInitialized|.
nsresult EnsureTimeStretcherInitialized();
private:
static long DataCallback_S(cubeb_stream*, void* aThis, void* aBuffer, long aFrames)
{
return static_cast<BufferedAudioStream*>(aThis)->DataCallback(aBuffer, aFrames);
}
static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
{
static_cast<BufferedAudioStream*>(aThis)->StateCallback(aState);
}
long DataCallback(void* aBuffer, long aFrames);
void StateCallback(cubeb_state aState);
// aTime is the time in ms the samples were inserted into MediaStreamGraph
long GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTime);
long GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTime);
long GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t &aTime);
// Shared implementation of underflow adjusted position calculation.
// Caller must own the monitor.
int64_t GetPositionInFramesUnlocked();
void StartUnlocked();
// The monitor is held to protect all access to member variables. Write()
// waits while mBuffer is full; DataCallback() notifies as it consumes
// data from mBuffer. Drain() waits while mState is DRAINING;
// StateCallback() notifies when mState is DRAINED.
Monitor mMonitor;
// Sum of silent frames written when DataCallback requests more frames
// than are available in mBuffer.
uint64_t mLostFrames;
// Output file for dumping audio
FILE* mDumpFile;
// Temporary audio buffer. Filled by Write() and consumed by
// DataCallback(). Once mBuffer is full, Write() blocks until sufficient
// space becomes available in mBuffer. mBuffer is sized in bytes, not
// frames.
nsCircularByteBuffer mBuffer;
// Software volume level. Applied during the servicing of DataCallback().
double mVolume;
// Owning reference to a cubeb_stream. cubeb_stream_destroy is called by
// nsAutoRef's destructor.
nsAutoRef<cubeb_stream> mCubebStream;
uint32_t mBytesPerFrame;
uint32_t BytesToFrames(uint32_t aBytes) {
NS_ASSERTION(aBytes % mBytesPerFrame == 0,
"Byte count not aligned on frames size.");
return aBytes / mBytesPerFrame;
}
uint32_t FramesToBytes(uint32_t aFrames) {
return aFrames * mBytesPerFrame;
}
enum StreamState {
INITIALIZED, // Initialized, playback has not begun.
STARTED, // Started by a call to Write() (iff INITIALIZED) or Resume().
STOPPED, // Stopped by a call to Pause().
DRAINING, // Drain requested. DataCallback will indicate end of stream
// once the remaining contents of mBuffer are requested by
// cubeb, after which StateCallback will indicate drain
// completion.
DRAINED, // StateCallback has indicated that the drain is complete.
ERRORED // Stream disabled due to an internal error.
};
StreamState mState;
};
#endif
AudioStream* AudioStream::AllocateStream()
{
#if defined(MOZ_CUBEB)
return new BufferedAudioStream();
#endif
return nullptr;
}
int AudioStream::MaxNumberOfChannels()
{
#if defined(MOZ_CUBEB)
cubeb* cubebContext = GetCubebContext();
uint32_t maxNumberOfChannels;
if (cubeb_get_max_channel_count(GetCubebContext(),
if (cubebContext &&
cubeb_get_max_channel_count(cubebContext,
&maxNumberOfChannels) == CUBEB_OK) {
return static_cast<int>(maxNumberOfChannels);
}
#endif
return 0;
}
int AudioStream::PreferredSampleRate()
/*static*/ int AudioStream::PreferredSampleRate()
{
StaticMutexAutoLock lock(AudioStream::mMutex);
const int fallbackSampleRate = 44100;
StaticMutexAutoLock lock(sMutex);
if (sPreferredSampleRate != 0) {
return sPreferredSampleRate;
}
cubeb* cubebContext = GetCubebContextUnlocked();
if (!cubebContext) {
sPreferredSampleRate = fallbackSampleRate;
}
// Get the preferred samplerate for this platform, or fallback to something
// sensible if we fail. We cache the value, because this might be accessed
// often, and the complexity of the function call below depends on the
// backend used.
const int fallbackSampleRate = 44100;
if (mPreferredSampleRate == 0) {
#if defined(MOZ_CUBEB)
if (cubeb_get_preferred_sample_rate(GetCubebContext(),
&mPreferredSampleRate) == CUBEB_OK) {
return mPreferredSampleRate;
}
#endif
mPreferredSampleRate = fallbackSampleRate;
if (cubeb_get_preferred_sample_rate(cubebContext,
&sPreferredSampleRate) != CUBEB_OK) {
sPreferredSampleRate = fallbackSampleRate;
}
return mPreferredSampleRate;
return sPreferredSampleRate;
}
#if defined(MOZ_CUBEB)
static void SetUint16LE(uint8_t* aDest, uint16_t aValue)
{
aDest[0] = aValue & 0xFF;
@ -541,33 +353,10 @@ WriteDumpFile(FILE* aDumpFile, AudioStream* aStream, uint32_t aFrames,
fflush(aDumpFile);
}
BufferedAudioStream::BufferedAudioStream()
: mMonitor("BufferedAudioStream"), mLostFrames(0), mDumpFile(nullptr),
mVolume(1.0), mBytesPerFrame(0), mState(INITIALIZED)
{
// keep a ref in case we shut down later than nsLayoutStatics
mLatencyLog = AsyncLatencyLogger::Get(true);
}
BufferedAudioStream::~BufferedAudioStream()
{
Shutdown();
if (mDumpFile) {
fclose(mDumpFile);
}
}
nsresult
BufferedAudioStream::EnsureTimeStretcherInitialized()
{
MonitorAutoLock mon(mMonitor);
return AudioStream::EnsureTimeStretcherInitialized();
}
nsresult
BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
const dom::AudioChannelType aAudioChannelType,
AudioStream::LatencyRequest aLatencyRequest)
AudioStream::Init(int32_t aNumChannels, int32_t aRate,
const dom::AudioChannelType aAudioChannelType,
LatencyRequest aLatencyRequest)
{
cubeb* cubebContext = GetCubebContext();
@ -610,7 +399,7 @@ BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
// for low latency playback, try to get the lowest latency possible.
// Otherwise, for normal streams, use 100ms.
uint32_t latency;
if (aLatencyRequest == AudioStream::LowLatency && !CubebLatencyPrefSet()) {
if (aLatencyRequest == LowLatency && !CubebLatencyPrefSet()) {
if (cubeb_get_min_latency(cubebContext, params, &latency) != CUBEB_OK) {
latency = GetCubebLatency();
}
@ -620,7 +409,7 @@ BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
{
cubeb_stream* stream;
if (cubeb_stream_init(cubebContext, &stream, "BufferedAudioStream", params,
if (cubeb_stream_init(cubebContext, &stream, "AudioStream", params,
latency, DataCallback_S, StateCallback_S, this) == CUBEB_OK) {
mCubebStream.own(stream);
}
@ -639,8 +428,8 @@ BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
// Start the stream right away when low latency has been requested. This means
// that the DataCallback will feed silence to cubeb, until the first frames
// are writtent to this BufferedAudioStream.
if (mLatencyRequest == AudioStream::LowLatency) {
// are writtent to this AudioStream.
if (mLatencyRequest == LowLatency) {
Start();
}
@ -648,7 +437,7 @@ BufferedAudioStream::Init(int32_t aNumChannels, int32_t aRate,
}
void
BufferedAudioStream::Shutdown()
AudioStream::Shutdown()
{
if (mState == STARTED) {
Pause();
@ -660,7 +449,7 @@ BufferedAudioStream::Shutdown()
// aTime is the time in ms the samples were inserted into MediaStreamGraph
nsresult
BufferedAudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime)
AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime)
{
MonitorAutoLock mon(mMonitor);
if (!mCubebStream || mState == ERRORED) {
@ -715,7 +504,7 @@ BufferedAudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeSta
}
uint32_t
BufferedAudioStream::Available()
AudioStream::Available()
{
MonitorAutoLock mon(mMonitor);
NS_ABORT_IF_FALSE(mBuffer.Length() % mBytesPerFrame == 0, "Buffer invariant violated.");
@ -723,7 +512,7 @@ BufferedAudioStream::Available()
}
void
BufferedAudioStream::SetVolume(double aVolume)
AudioStream::SetVolume(double aVolume)
{
MonitorAutoLock mon(mMonitor);
NS_ABORT_IF_FALSE(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
@ -731,7 +520,7 @@ BufferedAudioStream::SetVolume(double aVolume)
}
void
BufferedAudioStream::Drain()
AudioStream::Drain()
{
MonitorAutoLock mon(mMonitor);
if (mState != STARTED) {
@ -745,14 +534,14 @@ BufferedAudioStream::Drain()
}
void
BufferedAudioStream::Start()
AudioStream::Start()
{
MonitorAutoLock mon(mMonitor);
StartUnlocked();
}
void
BufferedAudioStream::StartUnlocked()
AudioStream::StartUnlocked()
{
mMonitor.AssertCurrentThreadOwns();
if (!mCubebStream || mState != INITIALIZED) {
@ -771,7 +560,7 @@ BufferedAudioStream::StartUnlocked()
}
void
BufferedAudioStream::Pause()
AudioStream::Pause()
{
MonitorAutoLock mon(mMonitor);
if (!mCubebStream || mState != STARTED) {
@ -789,7 +578,7 @@ BufferedAudioStream::Pause()
}
void
BufferedAudioStream::Resume()
AudioStream::Resume()
{
MonitorAutoLock mon(mMonitor);
if (!mCubebStream || mState != STOPPED) {
@ -807,7 +596,7 @@ BufferedAudioStream::Resume()
}
int64_t
BufferedAudioStream::GetPosition()
AudioStream::GetPosition()
{
return mAudioClock.GetPosition();
}
@ -817,7 +606,7 @@ BufferedAudioStream::GetPosition()
#pragma optimize("", off)
#endif
int64_t
BufferedAudioStream::GetPositionInFrames()
AudioStream::GetPositionInFrames()
{
return mAudioClock.GetPositionInFrames();
}
@ -826,14 +615,14 @@ BufferedAudioStream::GetPositionInFrames()
#endif
int64_t
BufferedAudioStream::GetPositionInFramesInternal()
AudioStream::GetPositionInFramesInternal()
{
MonitorAutoLock mon(mMonitor);
return GetPositionInFramesUnlocked();
}
int64_t
BufferedAudioStream::GetPositionInFramesUnlocked()
AudioStream::GetPositionInFramesUnlocked()
{
mMonitor.AssertCurrentThreadOwns();
@ -859,10 +648,10 @@ BufferedAudioStream::GetPositionInFramesUnlocked()
}
int64_t
BufferedAudioStream::GetLatencyInFrames()
AudioStream::GetLatencyInFrames()
{
uint32_t latency;
if(cubeb_stream_get_latency(mCubebStream, &latency)) {
if (cubeb_stream_get_latency(mCubebStream, &latency)) {
NS_WARNING("Could not get cubeb latency.");
return 0;
}
@ -870,14 +659,14 @@ BufferedAudioStream::GetLatencyInFrames()
}
bool
BufferedAudioStream::IsPaused()
AudioStream::IsPaused()
{
MonitorAutoLock mon(mMonitor);
return mState == STOPPED;
}
void
BufferedAudioStream::GetBufferInsertTime(int64_t &aTimeMs)
AudioStream::GetBufferInsertTime(int64_t &aTimeMs)
{
if (mInserts.Length() > 0) {
// Find the right block, but don't leave the array empty
@ -894,7 +683,7 @@ BufferedAudioStream::GetBufferInsertTime(int64_t &aTimeMs)
}
long
BufferedAudioStream::GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTimeMs)
AudioStream::GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTimeMs)
{
uint8_t* wpos = reinterpret_cast<uint8_t*>(aBuffer);
@ -925,7 +714,7 @@ BufferedAudioStream::GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTimeM
// Get unprocessed samples, and pad the beginning of the buffer with silence if
// there is not enough data.
long
BufferedAudioStream::GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t& aTimeMs)
AudioStream::GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t& aTimeMs)
{
uint32_t toPopBytes = FramesToBytes(aFrames);
uint32_t available = std::min(toPopBytes, mBuffer.Length());
@ -949,12 +738,12 @@ BufferedAudioStream::GetUnprocessedWithSilencePadding(void* aBuffer, long aFrame
}
long
BufferedAudioStream::GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTimeMs)
AudioStream::GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTimeMs)
{
long processedFrames = 0;
// We need to call the non-locking version, because we already have the lock.
if (AudioStream::EnsureTimeStretcherInitialized() != NS_OK) {
if (EnsureTimeStretcherInitialized() != NS_OK) {
return 0;
}
@ -990,7 +779,7 @@ BufferedAudioStream::GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTim
}
long
BufferedAudioStream::DataCallback(void* aBuffer, long aFrames)
AudioStream::DataCallback(void* aBuffer, long aFrames)
{
MonitorAutoLock mon(mMonitor);
uint32_t available = std::min(static_cast<uint32_t>(FramesToBytes(aFrames)), mBuffer.Length());
@ -1006,7 +795,7 @@ BufferedAudioStream::DataCallback(void* aBuffer, long aFrames)
// underrun at the beginning of the buffer, so the first buffer is not cut
// in half by the silence inserted to compensate for the underrun.
if (mInRate == mOutRate) {
if (mLatencyRequest == AudioStream::LowLatency && !mWritten) {
if (mLatencyRequest == LowLatency && !mWritten) {
servicedFrames = GetUnprocessedWithSilencePadding(output, aFrames, insertTime);
} else {
servicedFrames = GetUnprocessed(output, aFrames, insertTime);
@ -1060,7 +849,7 @@ BufferedAudioStream::DataCallback(void* aBuffer, long aFrames)
}
void
BufferedAudioStream::StateCallback(cubeb_state aState)
AudioStream::StateCallback(cubeb_state aState)
{
MonitorAutoLock mon(mMonitor);
if (aState == CUBEB_STATE_DRAINED) {
@ -1071,8 +860,6 @@ BufferedAudioStream::StateCallback(cubeb_state aState)
mon.NotifyAll();
}
#endif
AudioClock::AudioClock(AudioStream* aStream)
:mAudioStream(aStream),
mOldOutRate(0),

View File

@ -9,10 +9,20 @@
#include "AudioSampleFormat.h"
#include "AudioChannelCommon.h"
#include "nsAutoPtr.h"
#include "nsAutoRef.h"
#include "nsCOMPtr.h"
#include "Latency.h"
#include "mozilla/StaticMutex.h"
#include "cubeb/cubeb.h"
template <>
class nsAutoRefTraits<cubeb_stream> : public nsPointerRefTraits<cubeb_stream>
{
public:
static void Release(cubeb_stream* aStream) { cubeb_stream_destroy(aStream); }
};
namespace soundtouch {
class SoundTouch;
}
@ -23,84 +33,141 @@ class AudioStream;
class AudioClock
{
public:
AudioClock(mozilla::AudioStream* aStream);
// Initialize the clock with the current AudioStream. Need to be called
// before querying the clock. Called on the audio thread.
void Init();
// Update the number of samples that has been written in the audio backend.
// Called on the state machine thread.
void UpdateWritePosition(uint32_t aCount);
// Get the read position of the stream, in microseconds.
// Called on the state machine thead.
uint64_t GetPosition();
// Get the read position of the stream, in frames.
// Called on the state machine thead.
uint64_t GetPositionInFrames();
// Set the playback rate.
// Called on the audio thread.
void SetPlaybackRate(double aPlaybackRate);
// Get the current playback rate.
// Called on the audio thread.
double GetPlaybackRate();
// Set if we are preserving the pitch.
// Called on the audio thread.
void SetPreservesPitch(bool aPreservesPitch);
// Get the current pitch preservation state.
// Called on the audio thread.
bool GetPreservesPitch();
// Get the number of frames written to the backend.
int64_t GetWritten();
private:
// This AudioStream holds a strong reference to this AudioClock. This
// pointer is garanteed to always be valid.
AudioStream* mAudioStream;
// The old output rate, to compensate audio latency for the period inbetween
// the moment resampled buffers are pushed to the hardware and the moment the
// clock should take the new rate into account for A/V sync.
int mOldOutRate;
// Position at which the last playback rate change occured
int64_t mBasePosition;
// Offset, in frames, at which the last playback rate change occured
int64_t mBaseOffset;
// Old base offset (number of samples), used when changing rate to compute the
// position in the stream.
int64_t mOldBaseOffset;
// Old base position (number of microseconds), when changing rate. This is the
// time in the media, not wall clock position.
int64_t mOldBasePosition;
// Write position at which the playbackRate change occured.
int64_t mPlaybackRateChangeOffset;
// The previous position reached in the media, used when compensating
// latency, to have the position at which the playbackRate change occured.
int64_t mPreviousPosition;
// Number of samples effectivelly written in backend, i.e. write position.
int64_t mWritten;
// Output rate in Hz (characteristic of the playback rate)
int mOutRate;
// Input rate in Hz (characteristic of the media being played)
int mInRate;
// True if the we are timestretching, false if we are resampling.
bool mPreservesPitch;
// True if we are playing at the old playbackRate after it has been changed.
bool mCompensatingLatency;
public:
AudioClock(AudioStream* aStream);
// Initialize the clock with the current AudioStream. Need to be called
// before querying the clock. Called on the audio thread.
void Init();
// Update the number of samples that has been written in the audio backend.
// Called on the state machine thread.
void UpdateWritePosition(uint32_t aCount);
// Get the read position of the stream, in microseconds.
// Called on the state machine thead.
uint64_t GetPosition();
// Get the read position of the stream, in frames.
// Called on the state machine thead.
uint64_t GetPositionInFrames();
// Set the playback rate.
// Called on the audio thread.
void SetPlaybackRate(double aPlaybackRate);
// Get the current playback rate.
// Called on the audio thread.
double GetPlaybackRate();
// Set if we are preserving the pitch.
// Called on the audio thread.
void SetPreservesPitch(bool aPreservesPitch);
// Get the current pitch preservation state.
// Called on the audio thread.
bool GetPreservesPitch();
// Get the number of frames written to the backend.
int64_t GetWritten();
private:
// This AudioStream holds a strong reference to this AudioClock. This
// pointer is garanteed to always be valid.
AudioStream* mAudioStream;
// The old output rate, to compensate audio latency for the period inbetween
// the moment resampled buffers are pushed to the hardware and the moment the
// clock should take the new rate into account for A/V sync.
int mOldOutRate;
// Position at which the last playback rate change occured
int64_t mBasePosition;
// Offset, in frames, at which the last playback rate change occured
int64_t mBaseOffset;
// Old base offset (number of samples), used when changing rate to compute the
// position in the stream.
int64_t mOldBaseOffset;
// Old base position (number of microseconds), when changing rate. This is the
// time in the media, not wall clock position.
int64_t mOldBasePosition;
// Write position at which the playbackRate change occured.
int64_t mPlaybackRateChangeOffset;
// The previous position reached in the media, used when compensating
// latency, to have the position at which the playbackRate change occured.
int64_t mPreviousPosition;
// Number of samples effectivelly written in backend, i.e. write position.
int64_t mWritten;
// Output rate in Hz (characteristic of the playback rate)
int mOutRate;
// Input rate in Hz (characteristic of the media being played)
int mInRate;
// True if the we are timestretching, false if we are resampling.
bool mPreservesPitch;
// True if we are playing at the old playbackRate after it has been changed.
bool mCompensatingLatency;
};
class CircularByteBuffer
{
public:
CircularByteBuffer()
: mBuffer(nullptr), mCapacity(0), mStart(0), mCount(0)
{}
// Set the capacity of the buffer in bytes. Must be called before any
// call to append or pop elements.
void SetCapacity(uint32_t aCapacity) {
NS_ABORT_IF_FALSE(!mBuffer, "Buffer allocated.");
mCapacity = aCapacity;
mBuffer = new uint8_t[mCapacity];
}
uint32_t Length() {
return mCount;
}
uint32_t Capacity() {
return mCapacity;
}
uint32_t Available() {
return Capacity() - Length();
}
// Append aLength bytes from aSrc to the buffer. Caller must check that
// sufficient space is available.
void AppendElements(const uint8_t* aSrc, uint32_t aLength) {
NS_ABORT_IF_FALSE(mBuffer && mCapacity, "Buffer not initialized.");
NS_ABORT_IF_FALSE(aLength <= Available(), "Buffer full.");
uint32_t end = (mStart + mCount) % mCapacity;
uint32_t toCopy = std::min(mCapacity - end, aLength);
memcpy(&mBuffer[end], aSrc, toCopy);
memcpy(&mBuffer[0], aSrc + toCopy, aLength - toCopy);
mCount += aLength;
}
// Remove aSize bytes from the buffer. Caller must check returned size in
// aSize{1,2} before using the pointer returned in aData{1,2}. Caller
// must not specify an aSize larger than Length().
void PopElements(uint32_t aSize, void** aData1, uint32_t* aSize1,
void** aData2, uint32_t* aSize2) {
NS_ABORT_IF_FALSE(mBuffer && mCapacity, "Buffer not initialized.");
NS_ABORT_IF_FALSE(aSize <= Length(), "Request too large.");
*aData1 = &mBuffer[mStart];
*aSize1 = std::min(mCapacity - mStart, aSize);
*aData2 = &mBuffer[0];
*aSize2 = aSize - *aSize1;
mCount -= *aSize1 + *aSize2;
mStart += *aSize1 + *aSize2;
mStart %= mCapacity;
}
private:
nsAutoArrayPtr<uint8_t> mBuffer;
uint32_t mCapacity;
uint32_t mStart;
uint32_t mCount;
};
// Access to a single instance of this class must be synchronized by
// callers, or made from a single thread. One exception is that access to
// GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels}
// is thread-safe without external synchronization.
class AudioStream
class AudioStream MOZ_FINAL
{
public:
enum LatencyRequest {
HighLatency,
LowLatency
};
AudioStream();
virtual ~AudioStream();
// Initialize Audio Library. Some Audio backends require initializing the
// library before using it.
static void InitLibrary();
@ -109,11 +176,6 @@ public:
// library after using it.
static void ShutdownLibrary();
// AllocateStream will return either a local stream or a remoted stream
// depending on where you call it from. If you call this from a child process,
// you may receive an implementation which forwards to a compositing process.
static AudioStream* AllocateStream();
// Returns the maximum number of channels supported by the audio hardware.
static int MaxNumberOfChannels();
@ -121,79 +183,122 @@ public:
// samplerate the hardware/mixer supports.
static int PreferredSampleRate();
AudioStream();
~AudioStream();
enum LatencyRequest {
HighLatency,
LowLatency
};
// Initialize the audio stream. aNumChannels is the number of audio
// channels (1 for mono, 2 for stereo, etc) and aRate is the sample rate
// (22050Hz, 44100Hz, etc).
virtual nsresult Init(int32_t aNumChannels, int32_t aRate,
const dom::AudioChannelType aAudioStreamType,
LatencyRequest aLatencyRequest) = 0;
nsresult Init(int32_t aNumChannels, int32_t aRate,
const dom::AudioChannelType aAudioStreamType,
LatencyRequest aLatencyRequest);
// Closes the stream. All future use of the stream is an error.
virtual void Shutdown() = 0;
void Shutdown();
// Write audio data to the audio hardware. aBuf is an array of AudioDataValues
// AudioDataValue of length aFrames*mChannels. If aFrames is larger
// than the result of Available(), the write will block until sufficient
// buffer space is available. aTime is the time in ms associated with the first sample
// for latency calculations
virtual nsresult Write(const mozilla::AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime = nullptr) = 0;
nsresult Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp* aTime = nullptr);
// Return the number of audio frames that can be written without blocking.
virtual uint32_t Available() = 0;
uint32_t Available();
// Set the current volume of the audio playback. This is a value from
// 0 (meaning muted) to 1 (meaning full volume). Thread-safe.
virtual void SetVolume(double aVolume) = 0;
void SetVolume(double aVolume);
// Block until buffered audio data has been consumed.
virtual void Drain() = 0;
void Drain();
// Start the stream.
virtual void Start() = 0;
void Start();
// Return the number of frames written so far in the stream. This allow the
// caller to check if it is safe to start the stream, if needed.
virtual int64_t GetWritten();
int64_t GetWritten();
// Pause audio playback.
virtual void Pause() = 0;
void Pause();
// Resume audio playback.
virtual void Resume() = 0;
void Resume();
// Return the position in microseconds of the audio frame being played by
// the audio hardware, compensated for playback rate change. Thread-safe.
virtual int64_t GetPosition() = 0;
int64_t GetPosition();
// Return the position, measured in audio frames played since the stream
// was opened, of the audio hardware. Thread-safe.
virtual int64_t GetPositionInFrames() = 0;
int64_t GetPositionInFrames();
// Return the position, measured in audio framed played since the stream was
// opened, of the audio hardware, not adjusted for the changes of playback
// rate.
virtual int64_t GetPositionInFramesInternal() = 0;
int64_t GetPositionInFramesInternal();
// Returns true when the audio stream is paused.
virtual bool IsPaused() = 0;
bool IsPaused();
int GetRate() { return mOutRate; }
int GetChannels() { return mChannels; }
// This should be called before attempting to use the time stretcher.
virtual nsresult EnsureTimeStretcherInitialized();
nsresult EnsureTimeStretcherInitialized();
// Set playback rate as a multiple of the intrinsic playback rate. This is to
// be called only with aPlaybackRate > 0.0.
virtual nsresult SetPlaybackRate(double aPlaybackRate);
nsresult SetPlaybackRate(double aPlaybackRate);
// Switch between resampling (if false) and time stretching (if true, default).
virtual nsresult SetPreservesPitch(bool aPreservesPitch);
nsresult SetPreservesPitch(bool aPreservesPitch);
private:
static int PrefChanged(const char* aPref, void* aClosure);
static double GetVolumeScale();
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);
}
static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState)
{
static_cast<AudioStream*>(aThis)->StateCallback(aState);
}
long DataCallback(void* aBuffer, long aFrames);
void StateCallback(cubeb_state aState);
// aTime is the time in ms the samples were inserted into MediaStreamGraph
long GetUnprocessed(void* aBuffer, long aFrames, int64_t &aTime);
long GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTime);
long GetUnprocessedWithSilencePadding(void* aBuffer, long aFrames, int64_t &aTime);
// Shared implementation of underflow adjusted position calculation.
// Caller must own the monitor.
int64_t GetPositionInFramesUnlocked();
int64_t GetLatencyInFrames();
void GetBufferInsertTime(int64_t &aTimeMs);
void StartUnlocked();
// The monitor is held to protect all access to member variables. Write()
// waits while mBuffer is full; DataCallback() notifies as it consumes
// data from mBuffer. Drain() waits while mState is DRAINING;
// StateCallback() notifies when mState is DRAINED.
Monitor mMonitor;
protected:
// This mutex protects the mPreferedSamplerate member below.
static StaticMutex mMutex;
// Prefered samplerate, in Hz (characteristic of the
// hardware/mixer/platform/API used).
static uint32_t mPreferredSampleRate;
// Input rate in Hz (characteristic of the media being played)
int mInRate;
// Output rate in Hz (characteristic of the playback rate)
@ -218,7 +323,65 @@ protected:
int64_t mTimeMs;
int64_t mFrames;
};
nsAutoTArray<Inserts,8> mInserts;
nsAutoTArray<Inserts, 8> mInserts;
// Sum of silent frames written when DataCallback requests more frames
// than are available in mBuffer.
uint64_t mLostFrames;
// Output file for dumping audio
FILE* mDumpFile;
// Temporary audio buffer. Filled by Write() and consumed by
// DataCallback(). Once mBuffer is full, Write() blocks until sufficient
// space becomes available in mBuffer. mBuffer is sized in bytes, not
// frames.
CircularByteBuffer mBuffer;
// Software volume level. Applied during the servicing of DataCallback().
double mVolume;
// Owning reference to a cubeb_stream. cubeb_stream_destroy is called by
// nsAutoRef's destructor.
nsAutoRef<cubeb_stream> mCubebStream;
uint32_t mBytesPerFrame;
uint32_t BytesToFrames(uint32_t aBytes) {
NS_ASSERTION(aBytes % mBytesPerFrame == 0,
"Byte count not aligned on frames size.");
return aBytes / mBytesPerFrame;
}
uint32_t FramesToBytes(uint32_t aFrames) {
return aFrames * mBytesPerFrame;
}
enum StreamState {
INITIALIZED, // Initialized, playback has not begun.
STARTED, // Started by a call to Write() (iff INITIALIZED) or Resume().
STOPPED, // Stopped by a call to Pause().
DRAINING, // Drain requested. DataCallback will indicate end of stream
// once the remaining contents of mBuffer are requested by
// cubeb, after which StateCallback will indicate drain
// completion.
DRAINED, // StateCallback has indicated that the drain is complete.
ERRORED // Stream disabled due to an internal error.
};
StreamState mState;
// 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;
};
} // namespace mozilla

View File

@ -1056,7 +1056,7 @@ void MediaDecoderStateMachine::AudioLoop()
// AudioStream initialization can block for extended periods in unusual
// circumstances, so we take care to drop the decoder monitor while
// initializing.
nsAutoPtr<AudioStream> audioStream(AudioStream::AllocateStream());
nsAutoPtr<AudioStream> audioStream(new AudioStream());
audioStream->Init(channels, rate, audioChannelType, AudioStream::HighLatency);
audioStream->SetVolume(volume);
if (audioStream->SetPreservesPitch(preservesPitch) != NS_OK) {

View File

@ -778,7 +778,7 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTim
aStream->mAudioOutputStreams.AppendElement();
audioOutputStream->mAudioPlaybackStartTime = aAudioOutputStartTime;
audioOutputStream->mBlockedAudioTime = 0;
audioOutputStream->mStream = AudioStream::AllocateStream();
audioOutputStream->mStream = new AudioStream();
// XXX for now, allocate stereo output. But we need to fix this to
// match the system's ideal channel configuration.
audioOutputStream->mStream->Init(2, tracks->GetRate(), AUDIO_CHANNEL_NORMAL, AudioStream::LowLatency);

View File

@ -17,10 +17,5 @@ ifeq (WINNT,$(OS_TARGET))
symbols.def: symbols.def.in $(GLOBAL_DEPS)
$(call py_action,preprocessor,$(ACDEFINES) $< -o $@)
OS_LIBS += $(call EXPAND_LIBNAME, msimg32)
ifdef MOZ_CUBEB
OS_LIBS += $(call EXPAND_LIBNAME, winmm)
endif
OS_LIBS += $(call EXPAND_LIBNAME, msimg32 winmm)
endif

View File

@ -117,7 +117,6 @@ speex_resampler_get_output_latency
speex_resampler_skip_zeros
speex_resampler_reset_mem
speex_resampler_strerror
#ifdef MOZ_CUBEB
cubeb_destroy
cubeb_init
cubeb_get_max_channel_count
@ -129,7 +128,6 @@ cubeb_stream_init
cubeb_stream_start
cubeb_stream_stop
cubeb_stream_get_latency
#endif
#ifdef MOZ_OGG
th_comment_clear
th_comment_init

View File

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
The git commit ID used was 8c78a282aa0320e997436d6832024efe1527ca1c.
The git commit ID used was e92a27c96c0efd33acf983e4c873376ff4cae3d8.

View File

@ -159,7 +159,7 @@ cubeb_get_max_channel_count(cubeb * context, uint32_t * max_channels)
int
cubeb_get_min_latency(cubeb * context, cubeb_stream_params params, uint32_t * latency_ms)
{
if (!latency_ms) {
if (!context || !latency_ms) {
return CUBEB_ERROR_INVALID_PARAMETER;
}
return context->ops->get_min_latency(context, params, latency_ms);
@ -168,7 +168,7 @@ cubeb_get_min_latency(cubeb * context, cubeb_stream_params params, uint32_t * la
int
cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate)
{
if (!rate) {
if (!context || !rate) {
return CUBEB_ERROR_INVALID_PARAMETER;
}
return context->ops->get_preferred_sample_rate(context, rate);

View File

@ -17,13 +17,11 @@ LIBS = \
$(DEPTH)/netwerk/srtp/src/$(LIB_PREFIX)nksrtp_s.$(LIB_SUFFIX) \
$(NULL)
ifdef MOZ_CUBEB
ifdef MOZ_ALSA
LIBS += \
$(MOZ_ALSA_LIBS) \
$(NULL)
endif
endif
ifeq ($(OS_TARGET),Android)
LIBS += \

View File

@ -180,11 +180,9 @@ endif
endif
ifdef MOZ_CUBEB
ifdef MOZ_ALSA
EXTRA_DSO_LDOPTS += $(MOZ_ALSA_LIBS)
endif
endif
ifdef HAVE_CLOCK_MONOTONIC
EXTRA_DSO_LDOPTS += $(REALTIME_LIBS)
@ -247,10 +245,8 @@ OS_LIBS += \
endif
ifeq (OpenBSD,$(OS_ARCH))
ifdef MOZ_CUBEB
EXTRA_DSO_LDOPTS += -lsndio
endif
endif
ifdef MOZ_ENABLE_DBUS
EXTRA_DSO_LDOPTS += $(MOZ_DBUS_GLIB_LIBS)