зеркало из https://github.com/mozilla/gecko-dev.git
Bug 874508 - Web Audio is connected to AudioChannelService, r=ehsan
This commit is contained in:
Родитель
68bf49d79c
Коммит
eef83fde31
|
@ -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(©Chunk);
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче