Bug 599089 - Remote Audio to parent process. r=kinetik a=blocking-fennec

--HG--
extra : rebase_source : 8552e45188f1e62a56d5e93b551ec9fb0d4faaca
This commit is contained in:
Doug Turner 2010-11-16 20:14:19 -08:00
parent 99e3c36599
commit 56cee04483
20 changed files with 990 additions and 68 deletions

View File

@ -598,7 +598,7 @@ protected:
nsCOMPtr<nsIContent> mSourceLoadCandidate;
// An audio stream for writing audio directly from JS.
nsAutoPtr<nsAudioStream> mAudioStream;
nsRefPtr<nsAudioStream> mAudioStream;
// PR_TRUE if MozAudioAvailable events can be safely dispatched, based on
// a media and element same-origin check.

View File

@ -168,7 +168,7 @@ nsHTMLAudioElement::MozSetup(PRUint32 aChannels, PRUint32 aRate)
mAudioStream->Shutdown();
}
mAudioStream = new nsAudioStream();
mAudioStream = nsAudioStream::AllocateStream();
nsresult rv = mAudioStream->Init(aChannels, aRate,
nsAudioStream::FORMAT_FLOAT32);
if (NS_FAILED(rv)) {

View File

@ -98,6 +98,8 @@ endif
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk
INCLUDES += \

View File

@ -35,6 +35,15 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef MOZ_IPC
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/PAudioChild.h"
#include "mozilla/dom/AudioChild.h"
#include "nsXULAppAPI.h"
using namespace mozilla::dom;
#endif
#include <stdio.h>
#include <math.h>
#include "prlog.h"
@ -46,6 +55,7 @@ extern "C" {
#include "sydneyaudio/sydney_audio.h"
}
#include "mozilla/TimeStamp.h"
#include "nsThreadUtils.h"
#if defined(XP_MACOSX)
#define SA_PER_STREAM_VOLUME 1
@ -57,21 +67,284 @@ using mozilla::TimeStamp;
PRLogModuleInfo* gAudioStreamLog = nsnull;
#endif
#ifdef MOZ_IPC
static nsIThread *gAudioPlaybackThread = nsnull;
#endif
#define FAKE_BUFFER_SIZE 176400
#define MILLISECONDS_PER_SECOND 1000
class nsAudioStreamLocal : public nsAudioStream
{
public:
NS_DECL_ISUPPORTS
~nsAudioStreamLocal();
nsAudioStreamLocal();
nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
void Shutdown();
nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
PRUint32 Available();
void SetVolume(float aVolume);
void Drain();
void Pause();
void Resume();
PRInt64 GetPosition();
PRInt64 GetSampleOffset();
PRBool IsPaused();
private:
double mVolume;
void* mAudioHandle;
int mRate;
int mChannels;
SampleFormat mFormat;
// When a Write() request is made, and the number of samples
// requested to be written exceeds the buffer size of the audio
// backend, the remaining samples are stored in this variable. They
// will be written on the next Write() request.
nsTArray<short> mBufferOverflow;
// PR_TRUE if this audio stream is paused.
PRPackedBool mPaused;
// PR_TRUE if this stream has encountered an error.
PRPackedBool mInError;
};
#ifdef MOZ_IPC
class nsAudioStreamRemote : public nsAudioStream
{
public:
NS_DECL_ISUPPORTS
nsAudioStreamRemote();
~nsAudioStreamRemote();
nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
void Shutdown();
nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
PRUint32 Available();
void SetVolume(float aVolume);
void Drain();
void Pause();
void Resume();
PRInt64 GetPosition();
PRInt64 GetSampleOffset();
PRBool IsPaused();
AudioChild* mAudioChild;
SampleFormat mFormat;
int mRate;
int mChannels;
// PR_TRUE if this audio stream is paused.
PRPackedBool mPaused;
PRInt32 mBytesPerSample;
friend class AudioInitEvent;
friend class AudioShutdownEvent;
friend class AudioWriteEvent;
friend class AudioSetVolumeEvent;
friend class AudioPauseEvent;
friend class AudioDrainEvent;
friend class AudioGetSampleEvent;
};
class AudioInitEvent : public nsRunnable
{
public:
AudioInitEvent(nsAudioStreamRemote* owner)
{
mOwner = owner;
}
NS_IMETHOD Run()
{
ContentChild * cpc = ContentChild::GetSingleton();
NS_ASSERTION(cpc, "Content Protocol is NULL!");
mOwner->mAudioChild = static_cast<AudioChild*> (cpc->SendPAudioConstructor(mOwner->mChannels,
mOwner->mRate,
mOwner->mFormat));
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
};
class AudioShutdownEvent : public nsRunnable
{
public:
AudioShutdownEvent(nsAudioStreamRemote* owner)
{
mOwner = owner;
}
NS_IMETHOD Run()
{
if (mOwner->mAudioChild) {
PAudioChild::Send__delete__(mOwner->mAudioChild);
mOwner->mAudioChild = nsnull;
}
mOwner = nsnull;
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
};
class AudioWriteEvent : public nsRunnable
{
public:
AudioWriteEvent(nsAudioStreamRemote* owner,
const void* aBuf,
PRUint32 aNumberOfSamples,
PRUint32 aBytesPerSample)
{
mOwner = owner;
mBytesPerSample = aBytesPerSample;
mBuffer.Assign((const char*)aBuf, aNumberOfSamples*aBytesPerSample);
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
return NS_OK;
mOwner->mAudioChild->SendWrite(mBuffer,
mBuffer.Length() / mBytesPerSample);
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
nsCString mBuffer;
PRUint32 mBytesPerSample;
};
class AudioSetVolumeEvent : public nsRunnable
{
public:
AudioSetVolumeEvent(nsAudioStreamRemote* owner, float volume)
{
mOwner = owner;
mVolume = volume;
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
return NS_OK;
mOwner->mAudioChild->SendSetVolume(mVolume);
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
float mVolume;
};
class AudioDrainEvent : public nsRunnable
{
public:
AudioDrainEvent(nsAudioStreamRemote* owner)
{
mOwner = owner;
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
return NS_OK;
mOwner->mAudioChild->SendDrain();
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
};
class AudioPauseEvent : public nsRunnable
{
public:
AudioPauseEvent(nsAudioStreamRemote* owner, PRBool pause)
{
mOwner = owner;
mPause = pause;
}
NS_IMETHOD Run()
{
if (!mOwner->mAudioChild)
return NS_OK;
if (mPause)
mOwner->mAudioChild->SendPause();
else
mOwner->mAudioChild->SendResume();
return NS_OK;
}
nsRefPtr<nsAudioStreamRemote> mOwner;
PRBool mPause;
};
#endif // MOZ_IPC
void nsAudioStream::InitLibrary()
{
#ifdef PR_LOGGING
gAudioStreamLog = PR_NewLogModule("nsAudioStream");
#endif
#ifdef MOZ_IPC
// We only need this thread in the main process.
if (XRE_GetProcessType() == GeckoProcessType_Default) {
NS_NewThread(&gAudioPlaybackThread);
}
#endif
}
void nsAudioStream::ShutdownLibrary()
{
#ifdef MOZ_IPC
NS_IF_RELEASE(gAudioPlaybackThread);
#endif
}
nsAudioStream::nsAudioStream() :
nsIThread *
nsAudioStream::GetGlobalThread()
{
#ifdef MOZ_IPC
NS_IF_ADDREF(gAudioPlaybackThread);
return gAudioPlaybackThread;
#else
return nsnull;
#endif
}
nsAudioStream* nsAudioStream::AllocateStream()
{
nsAudioStream* result = nsnull;
#ifdef MOZ_IPC
if (XRE_GetProcessType() == GeckoProcessType_Content) {
return new nsAudioStreamRemote();
}
#endif
return new nsAudioStreamLocal();
}
nsAudioStreamLocal::nsAudioStreamLocal() :
mVolume(1.0),
mAudioHandle(0),
mRate(0),
@ -82,16 +355,16 @@ nsAudioStream::nsAudioStream() :
{
}
nsAudioStream::~nsAudioStream()
{
Shutdown();
}
nsAudioStreamLocal::~nsAudioStreamLocal(){}
nsresult nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat)
NS_IMPL_THREADSAFE_ISUPPORTS0(nsAudioStreamLocal)
nsresult nsAudioStreamLocal::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat)
{
mRate = aRate;
mChannels = aNumChannels;
mFormat = aFormat;
if (sa_stream_create_pcm(reinterpret_cast<sa_stream_t**>(&mAudioHandle),
NULL,
SA_MODE_WRONLY,
@ -100,7 +373,7 @@ nsresult nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat a
aNumChannels) != SA_SUCCESS) {
mAudioHandle = nsnull;
mInError = PR_TRUE;
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_create_pcm error"));
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_create_pcm error"));
return NS_ERROR_FAILURE;
}
@ -108,16 +381,17 @@ nsresult nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat a
sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
mAudioHandle = nsnull;
mInError = PR_TRUE;
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_open error"));
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_open error"));
return NS_ERROR_FAILURE;
}
mInError = PR_FALSE;
return NS_OK;
}
void nsAudioStream::Shutdown()
void nsAudioStreamLocal::Shutdown()
{
if (!mAudioHandle)
if (!mAudioHandle)
return;
sa_stream_destroy(static_cast<sa_stream_t*>(mAudioHandle));
@ -125,7 +399,7 @@ void nsAudioStream::Shutdown()
mInError = PR_TRUE;
}
nsresult nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking)
nsresult nsAudioStreamLocal::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking)
{
NS_ABORT_IF_FALSE(aCount % mChannels == 0,
"Buffer size must be divisible by channel count");
@ -199,7 +473,7 @@ nsresult nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlockin
s_data.get(),
count * sizeof(short)) != SA_SUCCESS)
{
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_write error"));
mInError = PR_TRUE;
return NS_ERROR_FAILURE;
}
@ -207,7 +481,7 @@ nsresult nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlockin
return NS_OK;
}
PRUint32 nsAudioStream::Available()
PRUint32 nsAudioStreamLocal::Available()
{
// If the audio backend failed to open, lie and say we'll accept some
// data.
@ -221,12 +495,12 @@ PRUint32 nsAudioStream::Available()
return s / sizeof(short);
}
void nsAudioStream::SetVolume(float aVolume)
void nsAudioStreamLocal::SetVolume(float aVolume)
{
NS_ASSERTION(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
#if defined(SA_PER_STREAM_VOLUME)
if (sa_stream_set_volume_abs(static_cast<sa_stream_t*>(mAudioHandle), aVolume) != SA_SUCCESS) {
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_set_volume_abs error"));
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_set_volume_abs error"));
mInError = PR_TRUE;
}
#else
@ -234,7 +508,7 @@ void nsAudioStream::SetVolume(float aVolume)
#endif
}
void nsAudioStream::Drain()
void nsAudioStreamLocal::Drain()
{
if (mInError)
return;
@ -244,19 +518,19 @@ void nsAudioStream::Drain()
if (sa_stream_write(static_cast<sa_stream_t*>(mAudioHandle),
mBufferOverflow.Elements(),
mBufferOverflow.Length() * sizeof(short)) != SA_SUCCESS)
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_write error"));
mInError = PR_TRUE;
return;
}
int r = sa_stream_drain(static_cast<sa_stream_t*>(mAudioHandle));
if (r != SA_SUCCESS && r != SA_ERROR_INVALID) {
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_drain error"));
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStreamLocal: sa_stream_drain error"));
mInError = PR_TRUE;
}
}
void nsAudioStream::Pause()
void nsAudioStreamLocal::Pause()
{
if (mInError)
return;
@ -264,7 +538,7 @@ void nsAudioStream::Pause()
sa_stream_pause(static_cast<sa_stream_t*>(mAudioHandle));
}
void nsAudioStream::Resume()
void nsAudioStreamLocal::Resume()
{
if (mInError)
return;
@ -272,17 +546,16 @@ void nsAudioStream::Resume()
sa_stream_resume(static_cast<sa_stream_t*>(mAudioHandle));
}
PRInt64 nsAudioStream::GetPosition()
PRInt64 nsAudioStreamLocal::GetPosition()
{
PRInt64 sampleOffset = GetSampleOffset();
if (sampleOffset >= 0) {
return ((MILLISECONDS_PER_SECOND * sampleOffset) / mRate / mChannels);
}
return -1;
}
PRInt64 nsAudioStream::GetSampleOffset()
PRInt64 nsAudioStreamLocal::GetSampleOffset()
{
if (mInError) {
return -1;
@ -300,3 +573,141 @@ PRInt64 nsAudioStream::GetSampleOffset()
return -1;
}
PRBool nsAudioStreamLocal::IsPaused()
{
return mPaused;
}
#ifdef MOZ_IPC
nsAudioStreamRemote::nsAudioStreamRemote()
: mAudioChild(NULL),
mFormat(FORMAT_S16_LE),
mRate(0),
mChannels(0),
mPaused(PR_FALSE),
mBytesPerSample(1)
{}
nsAudioStreamRemote::~nsAudioStreamRemote()
{}
NS_IMPL_THREADSAFE_ISUPPORTS0(nsAudioStreamRemote)
nsresult
nsAudioStreamRemote::Init(PRInt32 aNumChannels,
PRInt32 aRate,
SampleFormat aFormat)
{
mRate = aRate;
mChannels = aNumChannels;
mFormat = aFormat;
switch (mFormat) {
case FORMAT_U8: {
mBytesPerSample = sizeof(PRUint8);
break;
}
case FORMAT_S16_LE: {
mBytesPerSample = sizeof(short);
break;
}
case FORMAT_FLOAT32: {
mBytesPerSample = sizeof(float);
}
}
nsCOMPtr<nsIRunnable> event = new AudioInitEvent(this);
NS_DispatchToMainThread(event);
return NS_OK;
}
void
nsAudioStreamRemote::Shutdown()
{
nsCOMPtr<nsIRunnable> event = new AudioShutdownEvent(this);
NS_DispatchToMainThread(event);
}
nsresult
nsAudioStreamRemote::Write(const void* aBuf,
PRUint32 aCount,
PRBool aBlocking)
{
nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(this,
aBuf,
aCount,
mBytesPerSample);
NS_DispatchToMainThread(event);
return NS_OK;
}
PRUint32
nsAudioStreamRemote::Available()
{
return FAKE_BUFFER_SIZE;
}
void
nsAudioStreamRemote::SetVolume(float aVolume)
{
nsCOMPtr<nsIRunnable> event = new AudioSetVolumeEvent(this, aVolume);
NS_DispatchToMainThread(event);
}
void
nsAudioStreamRemote::Drain()
{
nsCOMPtr<nsIRunnable> event = new AudioDrainEvent(this);
NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
}
void
nsAudioStreamRemote::Pause()
{
mPaused = PR_TRUE;
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(this, PR_TRUE);
NS_DispatchToMainThread(event);
}
void
nsAudioStreamRemote::Resume()
{
mPaused = PR_FALSE;
nsCOMPtr<nsIRunnable> event = new AudioPauseEvent(this, PR_FALSE);
NS_DispatchToMainThread(event);
}
PRInt64 nsAudioStreamRemote::GetPosition()
{
PRInt64 sampleOffset = GetSampleOffset();
if (sampleOffset >= 0) {
return ((MILLISECONDS_PER_SECOND * sampleOffset) / mRate / mChannels);
}
return 0;
}
PRInt64
nsAudioStreamRemote::GetSampleOffset()
{
if(!mAudioChild)
return 0;
PRInt64 offset = mAudioChild->GetLastKnownSampleOffset();
if (offset == -1)
return 0;
PRInt64 time = mAudioChild->GetLastKnownSampleOffsetTime();
PRInt64 result = offset + (mRate * mChannels * (PR_IntervalNow() - time) / MILLISECONDS_PER_SECOND);
return result;
}
PRBool
nsAudioStreamRemote::IsPaused()
{
return mPaused;
}
#endif // MOZ_IPC

View File

@ -39,14 +39,13 @@
#define nsAudioStream_h_
#include "nscore.h"
#include "prlog.h"
#include "nsTArray.h"
#include "nsISupportsImpl.h"
#include "nsIThread.h"
extern PRLogModuleInfo* gAudioStreamLog;
class nsAudioStream
class nsAudioStream : public nsISupports
{
public:
public:
enum SampleFormat
{
FORMAT_U8,
@ -62,16 +61,23 @@ class nsAudioStream
// library after using it.
static void ShutdownLibrary();
nsAudioStream();
~nsAudioStream();
// Thread, usually for MOZ_IPC handling, that is shared between audio streams.
// This may return null in the child process
static nsIThread *GetGlobalThread();
// AllocateStream will return either a local stream or a remoted stream
// depending on where you call it from. If MOZ_IPC is enabled, and you
// call this from a child process, you may recieve an implementation which
// forwards to a compositing process.
static nsAudioStream* AllocateStream();
// Initialize the audio stream. aNumChannels is the number of audio channels
// (1 for mono, 2 for stereo, etc) and aRate is the frequency of the sound
// samples (22050, 44100, etc).
nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat);
virtual nsresult Init(PRInt32 aNumChannels, PRInt32 aRate, SampleFormat aFormat) = 0;
// Closes the stream. All future use of the stream is an error.
void Shutdown();
virtual void Shutdown() = 0;
// Write sound data to the audio hardware. aBuf is an array of samples in
// the format specified by mFormat of length aCount. aCount should be
@ -79,54 +85,35 @@ class nsAudioStream
// When aBlocking is PR_TRUE, we'll block until the write has completed,
// otherwise we'll buffer any data we can't write immediately, and write
// it in a later call.
nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
virtual nsresult Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking) = 0;
// Return the number of sound samples that can be written to the audio device
// without blocking.
PRUint32 Available();
virtual PRUint32 Available() = 0;
// Set the current volume of the audio playback. This is a value from
// 0 (meaning muted) to 1 (meaning full volume).
void SetVolume(float aVolume);
virtual void SetVolume(float aVolume) = 0;
// Block until buffered audio data has been consumed.
void Drain();
virtual void Drain() = 0;
// Pause audio playback
void Pause();
virtual void Pause() = 0;
// Resume audio playback
void Resume();
virtual void Resume() = 0;
// Return the position in milliseconds of the sample being played by the
// audio hardware.
PRInt64 GetPosition();
virtual PRInt64 GetPosition() = 0;
// Return the position, measured in samples played since the start, by
// the audio hardware.
PRInt64 GetSampleOffset();
virtual PRInt64 GetSampleOffset() = 0;
// Returns PR_TRUE when the audio stream is paused.
PRBool IsPaused() { return mPaused; }
private:
double mVolume;
void* mAudioHandle;
int mRate;
int mChannels;
SampleFormat mFormat;
// When a Write() request is made, and the number of samples
// requested to be written exceeds the buffer size of the audio
// backend, the remaining samples are stored in this variable. They
// will be written on the next Write() request.
nsTArray<short> mBufferOverflow;
// PR_TRUE if this audio stream is paused.
PRPackedBool mPaused;
// PR_TRUE if this stream has encountered an error.
PRPackedBool mInError;
virtual PRBool IsPaused() = 0;
};
#endif

View File

@ -161,6 +161,12 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
{
MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
if (mAudioStream) {
MonitorAutoEnter mon(mDecoder->GetMonitor());
mAudioStream->Shutdown();
mAudioStream = nsnull;
}
}
PRBool nsBuiltinDecoderStateMachine::HasFutureAudio() const {
@ -611,7 +617,7 @@ void nsBuiltinDecoderStateMachine::StartPlayback()
} else {
// No audiostream, create one.
const nsVideoInfo& info = mReader->GetInfo();
mAudioStream = new nsAudioStream();
mAudioStream = nsAudioStream::AllocateStream();
mAudioStream->Init(info.mAudioChannels,
info.mAudioRate,
MOZ_SOUND_DATA_FORMAT);

View File

@ -426,7 +426,7 @@ protected:
// The audio stream resource. Used on the state machine, audio, and main
// threads. You must hold the mAudioMonitor, and must NOT hold the decoder
// monitor when using the audio stream!
nsAutoPtr<nsAudioStream> mAudioStream;
nsRefPtr<nsAudioStream> mAudioStream;
// The reader, don't call its methods with the decoder monitor held.
// This is created in the play state machine's constructor, and destroyed

View File

@ -295,7 +295,7 @@ private:
// Our audio stream. Created on demand when entering playback state. It
// is destroyed when seeking begins and will not be reinitialized until
// playback resumes, so it is possible for this to be null.
nsAutoPtr<nsAudioStream> mAudioStream;
nsRefPtr<nsAudioStream> mAudioStream;
// Maximum time to spend waiting for data during buffering.
TimeDuration mBufferingWait;
@ -906,7 +906,7 @@ nsWaveStateMachine::ChangeState(State aState)
void
nsWaveStateMachine::OpenAudioStream()
{
mAudioStream = new nsAudioStream();
mAudioStream = nsAudioStream::AllocateStream();
if (!mAudioStream) {
LOG(PR_LOG_ERROR, ("Could not create audio stream"));
} else {

79
dom/ipc/AudioChild.cpp Normal file
View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Audio IPC
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/dom/AudioChild.h"
namespace mozilla {
namespace dom {
AudioChild::AudioChild()
: mLastSampleOffset(-1),
mLastSampleOffsetTime(0)
{
MOZ_COUNT_CTOR(AudioChild);
}
AudioChild::~AudioChild()
{
MOZ_COUNT_DTOR(AudioChild);
}
bool
AudioChild::RecvSampleOffsetUpdate(const PRInt64& offset,
const PRInt64& time)
{
mLastSampleOffset = offset;
mLastSampleOffsetTime = time;
return true;
}
PRInt64
AudioChild::GetLastKnownSampleOffset()
{
return mLastSampleOffset;
}
PRInt64
AudioChild::GetLastKnownSampleOffsetTime()
{
return mLastSampleOffsetTime;
}
} // namespace dom
} // namespace mozilla

64
dom/ipc/AudioChild.h Normal file
View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Audio IPC
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_AudioChild_h
#define mozilla_dom_AudioChild_h
#include "mozilla/dom/PAudioChild.h"
namespace mozilla {
namespace dom {
class AudioChild : public PAudioChild
{
public:
AudioChild();
virtual ~AudioChild();
virtual bool RecvSampleOffsetUpdate(const PRInt64&, const PRInt64&);
PRInt64 GetLastKnownSampleOffset();
PRInt64 GetLastKnownSampleOffsetTime();
private:
PRInt64 mLastSampleOffset, mLastSampleOffsetTime;
};
} // namespace dom
} // namespace mozilla
#endif

160
dom/ipc/AudioParent.cpp Normal file
View File

@ -0,0 +1,160 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Audio IPC
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "mozilla/dom/AudioParent.h"
#include "nsThreadUtils.h"
// C++ file contents
namespace mozilla {
namespace dom {
class AudioWriteEvent : public nsRunnable
{
public:
AudioWriteEvent(nsAudioStream* owner, nsCString data, PRUint32 count)
{
mOwner = owner;
mData = data;
mCount = count;
}
NS_IMETHOD Run()
{
mOwner->Write(mData.get(), mCount, true);
return NS_OK;
}
private:
nsRefPtr<nsAudioStream> mOwner;
nsCString mData;
PRUint32 mCount;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(AudioParent, nsITimerCallback)
nsresult
AudioParent::Notify(nsITimer* timer)
{
if (!mStream) {
timer->Cancel();
return NS_ERROR_FAILURE;
}
PRInt64 offset = mStream->GetSampleOffset();
SendSampleOffsetUpdate(offset, PR_IntervalNow());
return NS_OK;
}
bool
AudioParent::RecvWrite(
const nsCString& data,
const PRUint32& count)
{
nsCOMPtr<nsIRunnable> event = new AudioWriteEvent(mStream, data, count);
nsCOMPtr<nsIThread> thread = nsAudioStream::GetGlobalThread();
thread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL);
return true;
}
bool
AudioParent::RecvSetVolume(const float& aVolume)
{
if (mStream)
mStream->SetVolume(aVolume);
return true;
}
bool
AudioParent::RecvDrain()
{
if (mStream)
mStream->Drain();
return true;
}
bool
AudioParent::RecvPause()
{
if (mStream)
mStream->Pause();
return true;
}
bool
AudioParent::RecvResume()
{
if (mStream)
mStream->Resume();
return true;
}
bool
AudioParent::Recv__delete__()
{
if (mStream) {
mStream->Shutdown();
mStream = nsnull;
}
if (mTimer) {
mTimer->Cancel();
mTimer = nsnull;
}
return true;
}
AudioParent::AudioParent(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat)
{
mStream = nsAudioStream::AllocateStream();
if (mStream)
mStream->Init(aNumChannels,
aRate,
(nsAudioStream::SampleFormat) aFormat);
if (!mStream)
return;
mTimer = do_CreateInstance("@mozilla.org/timer;1");
mTimer->InitWithCallback(this, 1000, nsITimer::TYPE_REPEATING_SLACK);
}
AudioParent::~AudioParent()
{
}
} // namespace dom
} // namespace mozilla

86
dom/ipc/AudioParent.h Normal file
View File

@ -0,0 +1,86 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Audio IPC
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_AudioParent_h
#define mozilla_dom_AudioParent_h
#include "mozilla/dom/PAudioParent.h"
#include "nsAudioStream.h"
#include "nsITimer.h"
namespace mozilla {
namespace dom {
class AudioParent : public PAudioParent, public nsITimerCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
virtual bool
RecvWrite(
const nsCString& data,
const PRUint32& count);
virtual bool
RecvSetVolume(const float& aVolume);
virtual bool
RecvDrain();
virtual bool
RecvPause();
virtual bool
RecvResume();
virtual bool
Recv__delete__();
AudioParent(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
virtual ~AudioParent();
nsRefPtr<nsAudioStream> mStream;
nsCOMPtr<nsITimer> mTimer;
};
} // namespace dom
} // namespace mozilla
#endif

View File

@ -47,6 +47,7 @@
#include "ContentChild.h"
#include "TabChild.h"
#include "AudioChild.h"
#include "mozilla/ipc/TestShellChild.h"
#include "mozilla/net/NeckoChild.h"
@ -54,6 +55,8 @@
#include "mozilla/jsipc/PContextWrapperChild.h"
#include "mozilla/dom/ExternalHelperAppChild.h"
#include "nsAudioStream.h"
#include "nsIObserverService.h"
#include "nsTObserverArray.h"
#include "nsIObserver.h"
@ -287,6 +290,22 @@ ContentChild::RecvPTestShellConstructor(PTestShellChild* actor)
return true;
}
PAudioChild*
ContentChild::AllocPAudio(const PRInt32& numChannels,
const PRInt32& rate,
const PRInt32& format)
{
PAudioChild *child = new AudioChild();
return child;
}
bool
ContentChild::DeallocPAudio(PAudioChild* doomed)
{
delete doomed;
return true;
}
PNeckoChild*
ContentChild::AllocPNecko()
{

View File

@ -83,6 +83,11 @@ public:
virtual bool DeallocPTestShell(PTestShellChild*);
virtual bool RecvPTestShellConstructor(PTestShellChild*);
virtual PAudioChild* AllocPAudio(const PRInt32&,
const PRInt32&,
const PRInt32&);
virtual bool DeallocPAudio(PAudioChild*);
virtual PNeckoChild* AllocPNecko();
virtual bool DeallocPNecko(PNeckoChild*);

View File

@ -66,6 +66,7 @@
#include "nsIConsoleService.h"
#include "nsIScriptError.h"
#include "nsConsoleMessage.h"
#include "AudioParent.h"
#ifdef MOZ_PERMISSIONS
#include "nsPermissionManager.h"
@ -361,6 +362,24 @@ ContentParent::DeallocPTestShell(PTestShellParent* shell)
delete shell;
return true;
}
PAudioParent*
ContentParent::AllocPAudio(const PRInt32& numChannels,
const PRInt32& rate,
const PRInt32& format)
{
AudioParent *parent = new AudioParent(numChannels, rate, format);
parent->AddRef();
return parent;
}
bool
ContentParent::DeallocPAudio(PAudioParent* doomed)
{
AudioParent *parent = static_cast<AudioParent*>(doomed);
NS_RELEASE(parent);
return true;
}
PNeckoParent*
ContentParent::AllocPNecko()

View File

@ -117,6 +117,11 @@ private:
virtual PTestShellParent* AllocPTestShell();
virtual bool DeallocPTestShell(PTestShellParent* shell);
virtual PAudioParent* AllocPAudio(const PRInt32&,
const PRInt32&,
const PRInt32&);
virtual bool DeallocPAudio(PAudioParent*);
virtual PNeckoParent* AllocPNecko();
virtual bool DeallocPNecko(PNeckoParent* necko);

View File

@ -52,6 +52,8 @@ EXPORTS = TabMessageUtils.h PCOMContentPermissionRequestChild.h
EXPORTS_NAMESPACES = mozilla/dom
EXPORTS_mozilla/dom = \
AudioChild.h \
AudioParent.h \
ContentChild.h \
ContentParent.h \
ContentProcess.h \
@ -60,6 +62,8 @@ EXPORTS_mozilla/dom = \
$(NULL)
CPPSRCS = \
AudioChild.cpp \
AudioParent.cpp \
ContentProcess.cpp \
ContentParent.cpp \
ContentChild.cpp \

70
dom/ipc/PAudio.ipdl Normal file
View File

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Audio IPC
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Doug Turner <dougt@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
include protocol PContent;
namespace mozilla {
namespace dom {
sync protocol PAudio
{
manager PContent;
parent:
__delete__();
Write(nsCString data, PRUint32 count);
SetVolume(float aVolume);
sync Drain();
Pause();
Resume();
child:
SampleOffsetUpdate(PRInt64 offset, PRInt64 time);
};
} // namespace dom
} // namespace mozilla

View File

@ -36,6 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
include protocol PAudio;
include protocol PBrowser;
include protocol PTestShell;
include protocol PNecko;
@ -61,6 +62,7 @@ namespace dom {
rpc protocol PContent
{
manages PAudio;
manages PBrowser;
manages PTestShell;
manages PNecko;
@ -92,6 +94,8 @@ child:
parent:
PNecko();
PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
// Services remoting
async StartVisitedQuery(URI uri);

View File

@ -35,6 +35,7 @@
# ***** END LICENSE BLOCK *****
IPDLSRCS = \
PAudio.ipdl \
PBrowser.ipdl \
PContent.ipdl \
PContentDialog.ipdl \