MediaStreamAudioDestinationNode.cpp (5640B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "MediaStreamAudioDestinationNode.h" 8 9 #include "AudioNodeEngine.h" 10 #include "AudioNodeTrack.h" 11 #include "AudioStreamTrack.h" 12 #include "DOMMediaStream.h" 13 #include "ForwardedInputTrack.h" 14 #include "mozilla/dom/Document.h" 15 #include "mozilla/dom/MediaStreamAudioDestinationNodeBinding.h" 16 #include "nsGlobalWindowInner.h" 17 18 namespace mozilla::dom { 19 20 class AudioDestinationTrackSource final : public MediaStreamTrackSource { 21 public: 22 NS_DECL_ISUPPORTS_INHERITED 23 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(AudioDestinationTrackSource, 24 MediaStreamTrackSource) 25 26 AudioDestinationTrackSource(MediaStreamAudioDestinationNode* aNode, 27 mozilla::MediaTrack* aInputTrack, 28 ProcessedMediaTrack* aTrack, 29 nsIPrincipal* aPrincipal) 30 : MediaStreamTrackSource( 31 aPrincipal, nsString(), 32 // We pass 0 here because tracking ids are video only for now. 33 TrackingId(TrackingId::Source::AudioDestinationNode, 0)), 34 mTrack(aTrack), 35 mPort(mTrack->AllocateInputPort(aInputTrack)), 36 mNode(aNode) {} 37 38 void Destroy() override { 39 if (!mTrack->IsDestroyed()) { 40 mTrack->Destroy(); 41 mPort->Destroy(); 42 } 43 if (mNode) { 44 mNode->DestroyMediaTrack(); 45 mNode = nullptr; 46 } 47 } 48 49 MediaSourceEnum GetMediaSource() const override { 50 return MediaSourceEnum::AudioCapture; 51 } 52 53 void GetSettings(MediaTrackSettings& aSettings) override {} 54 55 void Stop() override { Destroy(); } 56 57 void Disable() override {} 58 59 void Enable() override {} 60 61 const RefPtr<ProcessedMediaTrack> mTrack; 62 const RefPtr<MediaInputPort> mPort; 63 64 private: 65 ~AudioDestinationTrackSource() = default; 66 67 RefPtr<MediaStreamAudioDestinationNode> mNode; 68 }; 69 70 NS_IMPL_ADDREF_INHERITED(AudioDestinationTrackSource, MediaStreamTrackSource) 71 NS_IMPL_RELEASE_INHERITED(AudioDestinationTrackSource, MediaStreamTrackSource) 72 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AudioDestinationTrackSource) 73 NS_INTERFACE_MAP_END_INHERITING(MediaStreamTrackSource) 74 NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationTrackSource, 75 MediaStreamTrackSource, mNode) 76 77 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaStreamAudioDestinationNode, AudioNode, 78 mDOMStream) 79 80 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamAudioDestinationNode) 81 NS_INTERFACE_MAP_END_INHERITING(AudioNode) 82 83 NS_IMPL_ADDREF_INHERITED(MediaStreamAudioDestinationNode, AudioNode) 84 NS_IMPL_RELEASE_INHERITED(MediaStreamAudioDestinationNode, AudioNode) 85 86 MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode( 87 AudioContext* aContext) 88 : AudioNode(aContext, 2, ChannelCountMode::Explicit, 89 ChannelInterpretation::Speakers), 90 mDOMStream(MakeAndAddRef<DOMMediaStream>(GetOwnerWindow())) { 91 // Ensure an audio track with the correct ID is exposed to JS. If we can't get 92 // a principal here because the document is not available, pass in a null 93 // principal. This happens in edge cases when the document is being unloaded 94 // and it does not matter too much to have something working as long as it's 95 // not dangerous. 96 nsCOMPtr<nsIPrincipal> principal = nullptr; 97 if (nsGlobalWindowInner* win = aContext->GetOwnerWindow()) { 98 Document* doc = win->GetExtantDoc(); 99 principal = doc->NodePrincipal(); 100 } 101 mTrack = AudioNodeTrack::Create(aContext, new AudioNodeEngine(this), 102 AudioNodeTrack::EXTERNAL_OUTPUT, 103 aContext->Graph()); 104 auto source = MakeRefPtr<AudioDestinationTrackSource>( 105 this, mTrack, 106 aContext->Graph()->CreateForwardedInputTrack(MediaSegment::AUDIO), 107 principal); 108 auto track = 109 MakeRefPtr<AudioStreamTrack>(GetOwnerWindow(), source->mTrack, source); 110 mDOMStream->AddTrackInternal(track); 111 } 112 113 /* static */ 114 already_AddRefed<MediaStreamAudioDestinationNode> 115 MediaStreamAudioDestinationNode::Create(AudioContext& aAudioContext, 116 const AudioNodeOptions& aOptions, 117 ErrorResult& aRv) { 118 // The spec has a pointless check here. See 119 // https://github.com/WebAudio/web-audio-api/issues/2149 120 MOZ_RELEASE_ASSERT(!aAudioContext.IsOffline(), "Bindings messed up?"); 121 122 RefPtr<MediaStreamAudioDestinationNode> audioNode = 123 new MediaStreamAudioDestinationNode(&aAudioContext); 124 125 audioNode->Initialize(aOptions, aRv); 126 if (NS_WARN_IF(aRv.Failed())) { 127 return nullptr; 128 } 129 130 return audioNode.forget(); 131 } 132 133 size_t MediaStreamAudioDestinationNode::SizeOfExcludingThis( 134 MallocSizeOf aMallocSizeOf) const { 135 // Future: 136 // - mDOMStream 137 size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf); 138 return amount; 139 } 140 141 size_t MediaStreamAudioDestinationNode::SizeOfIncludingThis( 142 MallocSizeOf aMallocSizeOf) const { 143 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); 144 } 145 146 void MediaStreamAudioDestinationNode::DestroyMediaTrack() { 147 AudioNode::DestroyMediaTrack(); 148 } 149 150 JSObject* MediaStreamAudioDestinationNode::WrapObject( 151 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { 152 return MediaStreamAudioDestinationNode_Binding::Wrap(aCx, this, aGivenProto); 153 } 154 155 } // namespace mozilla::dom