Bug 874508 - Web Audio is connected to AudioChannelService, r=ehsan

This commit is contained in:
Andrea Marchesini 2013-10-03 18:42:04 -04:00
parent 8c22a53a8f
commit fdbb7e1fbe
3 changed files with 136 additions and 10 deletions

View File

@ -17,13 +17,12 @@ namespace mozilla {
/**
* An AudioNodeStream produces a single audio track with ID
* AUDIO_NODE_STREAM_TRACK_ID. This track has rate AudioContext::sIdealAudioRate
* AUDIO_TRACK. This track has rate AudioContext::sIdealAudioRate
* for regular audio contexts, and the rate requested by the web content
* for offline audio contexts.
* Each chunk in the track is a single block of WEBAUDIO_BLOCK_SIZE samples.
* Note: This must be a different value than MEDIA_STREAM_DEST_TRACK_ID
*/
static const int AUDIO_NODE_STREAM_TRACK_ID = 1;
AudioNodeStream::~AudioNodeStream()
{
@ -409,7 +408,7 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo)
FinishOutput();
}
EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate);
EnsureTrack(AUDIO_TRACK, mSampleRate);
uint16_t outputCount = std::max(uint16_t(1), mEngine->OutputCount());
mLastChunks.SetLength(outputCount);
@ -441,7 +440,7 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo)
}
}
if (mDisabledTrackIDs.Contains(AUDIO_NODE_STREAM_TRACK_ID)) {
if (mDisabledTrackIDs.Contains(AUDIO_TRACK)) {
for (uint32_t i = 0; i < mLastChunks.Length(); ++i) {
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
}
@ -453,7 +452,7 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo)
void
AudioNodeStream::AdvanceOutputSegment()
{
StreamBuffer::Track* track = EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate);
StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK, mSampleRate);
AudioSegment* segment = track->Get<AudioSegment>();
if (mKind == MediaStreamGraph::EXTERNAL_STREAM) {
@ -467,7 +466,7 @@ AudioNodeStream::AdvanceOutputSegment()
AudioChunk copyChunk = mLastChunks[0];
AudioSegment tmpSegment;
tmpSegment.AppendAndConsumeChunk(&copyChunk);
l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
mSampleRate, segment->GetDuration(), 0,
tmpSegment);
}
@ -476,7 +475,7 @@ AudioNodeStream::AdvanceOutputSegment()
TrackTicks
AudioNodeStream::GetCurrentPosition()
{
return EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate)->Get<AudioSegment>()->GetDuration();
return EnsureTrack(AUDIO_TRACK, mSampleRate)->Get<AudioSegment>()->GetDuration();
}
void
@ -486,14 +485,14 @@ AudioNodeStream::FinishOutput()
return;
}
StreamBuffer::Track* track = EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate);
StreamBuffer::Track* track = EnsureTrack(AUDIO_TRACK, mSampleRate);
track->SetEnded();
FinishOnGraphThread();
for (uint32_t j = 0; j < mListeners.Length(); ++j) {
MediaStreamListener* l = mListeners[j];
AudioSegment emptySegment;
l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID,
l->NotifyQueuedTrackChanges(Graph(), AUDIO_TRACK,
mSampleRate,
track->GetSegment()->GetDuration(),
MediaStreamListener::TRACK_EVENT_ENDED, emptySegment);

View File

@ -6,10 +6,15 @@
#include "AudioDestinationNode.h"
#include "mozilla/dom/AudioDestinationNodeBinding.h"
#include "mozilla/Preferences.h"
#include "AudioChannelAgent.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "MediaStreamGraph.h"
#include "OfflineAudioCompletionEvent.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIDocShell.h"
#include "nsIDocument.h"
namespace mozilla {
namespace dom {
@ -213,7 +218,55 @@ private:
float mVolume;
};
NS_IMPL_ISUPPORTS_INHERITED0(AudioDestinationNode, AudioNode)
class AudioChannelAgentCallback MOZ_FINAL : public nsIAudioChannelAgentCallback
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(AudioChannelAgentCallback)
explicit AudioChannelAgentCallback(AudioDestinationNode* aNode)
: mNode(aNode)
{
}
~AudioChannelAgentCallback()
{
}
NS_IMETHODIMP
CanPlayChanged(int32_t aCanPlay)
{
mNode->SetCanPlay(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
return NS_OK;
}
private:
nsRefPtr<AudioDestinationNode> mNode;
};
NS_IMPL_CYCLE_COLLECTION_1(AudioChannelAgentCallback, mNode)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioChannelAgentCallback)
NS_INTERFACE_MAP_ENTRY(nsIAudioChannelAgentCallback)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(AudioChannelAgentCallback)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AudioChannelAgentCallback)
static bool UseAudioChannelService()
{
return Preferences::GetBool("media.useAudioChannelService");
}
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(AudioDestinationNode, AudioNode,
mAudioChannelAgent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(AudioDestinationNode)
NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(AudioDestinationNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(AudioDestinationNode, AudioNode)
AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
bool aIsOffline,
@ -235,6 +288,30 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
static_cast<AudioNodeEngine*>(new DestinationNodeEngine(this));
mStream = graph->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM);
if (!aIsOffline && UseAudioChannelService()) {
mAudioChannelAgent = new AudioChannelAgent();
mAudioChannelAgent->Init(nsIAudioChannelAgent::AUDIO_AGENT_CHANNEL_NORMAL,
new AudioChannelAgentCallback(this));
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
if (target) {
target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
}
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
if (docshell) {
bool isActive = false;
docshell->GetIsActive(&isActive);
mAudioChannelAgent->SetVisibilityState(isActive);
}
int32_t state = 0;
mAudioChannelAgent->StartPlaying(&state);
SetCanPlay(state == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
}
}
void
@ -248,6 +325,18 @@ AudioDestinationNode::DestroyMediaStream()
MediaStreamGraph::DestroyNonRealtimeInstance(graph);
}
AudioNode::DestroyMediaStream();
if (mAudioChannelAgent && !Context()->IsOffline()) {
mAudioChannelAgent->StopPlaying();
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
NS_ENSURE_TRUE_VOID(target);
target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
/* useCapture = */ true);
mAudioChannelAgent = nullptr;
}
}
uint32_t
@ -304,5 +393,31 @@ AudioDestinationNode::StartRendering()
mStream->Graph()->StartNonRealtimeProcessing(mFramesToProduce);
}
void
AudioDestinationNode::SetCanPlay(bool aCanPlay)
{
mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, aCanPlay);
}
NS_IMETHODIMP
AudioDestinationNode::HandleEvent(nsIDOMEvent* aEvent)
{
nsAutoString type;
aEvent->GetType(type);
if (!type.EqualsLiteral("visibilitychange")) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
bool isActive = false;
docshell->GetIsActive(&isActive);
mAudioChannelAgent->SetVisibilityState(isActive);
return NS_OK;
}
}
}

View File

@ -8,13 +8,16 @@
#define AudioDestinationNode_h_
#include "AudioNode.h"
#include "nsIDOMEventListener.h"
namespace mozilla {
namespace dom {
class AudioContext;
class AudioChannelAgent;
class AudioDestinationNode : public AudioNode
, public nsIDOMEventListener
{
public:
// This node type knows what MediaStreamGraph to use based on
@ -28,6 +31,7 @@ public:
virtual void DestroyMediaStream() MOZ_OVERRIDE;
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioDestinationNode, AudioNode)
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
@ -48,9 +52,17 @@ public:
void OfflineShutdown();
// nsIDOMEventListener
NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent);
// Used by AudioChannelAgentCallback
void SetCanPlay(bool aCanPlay);
private:
SelfReference<AudioDestinationNode> mOfflineRenderingRef;
uint32_t mFramesToProduce;
nsRefPtr<AudioChannelAgent> mAudioChannelAgent;
};
}