michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "MediaStreamAudioDestinationNode.h" michael@0: #include "nsIDocument.h" michael@0: #include "mozilla/dom/MediaStreamAudioDestinationNodeBinding.h" michael@0: #include "AudioNodeEngine.h" michael@0: #include "AudioNodeStream.h" michael@0: #include "DOMMediaStream.h" michael@0: #include "TrackUnionStream.h" michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaStreamAudioDestinationNode, AudioNode, mDOMStream) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamAudioDestinationNode) michael@0: NS_INTERFACE_MAP_END_INHERITING(AudioNode) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(MediaStreamAudioDestinationNode, AudioNode) michael@0: NS_IMPL_RELEASE_INHERITED(MediaStreamAudioDestinationNode, AudioNode) michael@0: michael@0: static const int MEDIA_STREAM_DEST_TRACK_ID = 2; michael@0: static_assert(MEDIA_STREAM_DEST_TRACK_ID != AudioNodeStream::AUDIO_TRACK, michael@0: "MediaStreamAudioDestinationNode::MEDIA_STREAM_DEST_TRACK_ID must be a different value than AudioNodeStream::AUDIO_TRACK"); michael@0: michael@0: class MediaStreamDestinationEngine : public AudioNodeEngine { michael@0: public: michael@0: MediaStreamDestinationEngine(AudioNode* aNode, ProcessedMediaStream* aOutputStream) michael@0: : AudioNodeEngine(aNode) michael@0: , mOutputStream(aOutputStream) michael@0: { michael@0: MOZ_ASSERT(mOutputStream); michael@0: } michael@0: michael@0: virtual void ProcessBlock(AudioNodeStream* aStream, michael@0: const AudioChunk& aInput, michael@0: AudioChunk* aOutput, michael@0: bool* aFinished) MOZ_OVERRIDE michael@0: { michael@0: *aOutput = aInput; michael@0: StreamBuffer::Track* track = mOutputStream->EnsureTrack(MEDIA_STREAM_DEST_TRACK_ID, michael@0: aStream->SampleRate()); michael@0: AudioSegment* segment = track->Get(); michael@0: segment->AppendAndConsumeChunk(aOutput); michael@0: } michael@0: michael@0: virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE michael@0: { michael@0: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: michael@0: private: michael@0: ProcessedMediaStream* mOutputStream; michael@0: }; michael@0: michael@0: // This callback is used to ensure that only the audio data for this track is audible michael@0: static bool FilterAudioNodeStreamTrack(StreamBuffer::Track* aTrack) michael@0: { michael@0: return aTrack->GetID() == MEDIA_STREAM_DEST_TRACK_ID; michael@0: } michael@0: michael@0: MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* aContext) michael@0: : AudioNode(aContext, michael@0: 2, michael@0: ChannelCountMode::Explicit, michael@0: ChannelInterpretation::Speakers) michael@0: , mDOMStream(DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(), michael@0: MOZ_THIS_IN_INITIALIZER_LIST(), michael@0: DOMMediaStream::HINT_CONTENTS_AUDIO)) michael@0: { michael@0: TrackUnionStream* tus = static_cast(mDOMStream->GetStream()); michael@0: MOZ_ASSERT(tus == mDOMStream->GetStream()->AsProcessedStream()); michael@0: tus->SetTrackIDFilter(FilterAudioNodeStreamTrack); michael@0: michael@0: MediaStreamDestinationEngine* engine = new MediaStreamDestinationEngine(this, tus); michael@0: mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); michael@0: mPort = tus->AllocateInputPort(mStream, 0); michael@0: michael@0: nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc(); michael@0: if (doc) { michael@0: mDOMStream->CombineWithPrincipal(doc->NodePrincipal()); michael@0: } michael@0: } michael@0: michael@0: size_t michael@0: MediaStreamAudioDestinationNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: // Future: michael@0: // - mDOMStream michael@0: size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf); michael@0: amount += mPort->SizeOfIncludingThis(aMallocSizeOf); michael@0: return amount; michael@0: } michael@0: michael@0: size_t michael@0: MediaStreamAudioDestinationNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const michael@0: { michael@0: return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); michael@0: } michael@0: michael@0: void michael@0: MediaStreamAudioDestinationNode::DestroyMediaStream() michael@0: { michael@0: AudioNode::DestroyMediaStream(); michael@0: if (mPort) { michael@0: mPort->Destroy(); michael@0: mPort = nullptr; michael@0: } michael@0: } michael@0: michael@0: JSObject* michael@0: MediaStreamAudioDestinationNode::WrapObject(JSContext* aCx) michael@0: { michael@0: return MediaStreamAudioDestinationNodeBinding::Wrap(aCx, this); michael@0: } michael@0: michael@0: } michael@0: }