Bug 1208371 - Lock MediaStreamAudioSourceNode onto the first AudioStreamTrack in mInputStream at time of construction. r?mt,padenot
MozReview-Commit-ID: GLE5dVLEdEL
--- a/dom/media/webaudio/MediaStreamAudioSourceNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioSourceNode.cpp
@@ -13,21 +13,27 @@
#include "mozilla/CORSMode.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamAudioSourceNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaStreamAudioSourceNode)
+ if (tmp->mInputStream) {
+ tmp->mInputStream->UnregisterTrackListener(tmp);
+ }
+ tmp->DetachFromTrack();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputStream)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputTrack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(AudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaStreamAudioSourceNode, AudioNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputStream)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputTrack)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamAudioSourceNode)
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(MediaStreamAudioSourceNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(MediaStreamAudioSourceNode, AudioNode)
@@ -63,62 +69,120 @@ MediaStreamAudioSourceNode::Init(DOMMedi
if (NS_WARN_IF(graph != inputStream->Graph())) {
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
mInputStream = aMediaStream;
AudioNodeEngine* engine = new MediaStreamAudioSourceNodeEngine(this);
mStream = AudioNodeExternalInputStream::Create(graph, engine);
- ProcessedMediaStream* outputStream = static_cast<ProcessedMediaStream*>(mStream.get());
- mInputPort = outputStream->AllocateInputPort(inputStream);
mInputStream->AddConsumerToKeepAlive(static_cast<nsIDOMEventTarget*>(this));
- PrincipalChanged(mInputStream); // trigger enabling/disabling of the connector
- mInputStream->AddPrincipalChangeObserver(this);
+ mInputStream->RegisterTrackListener(this);
+ AttachToFirstTrack(mInputStream);
}
-MediaStreamAudioSourceNode::~MediaStreamAudioSourceNode()
+MediaStreamAudioSourceNode::~MediaStreamAudioSourceNode() {}
+
+void
+MediaStreamAudioSourceNode::AttachToTrack(const RefPtr<MediaStreamTrack>& aTrack)
{
- if (mInputStream) {
- mInputStream->RemovePrincipalChangeObserver(this);
+ MOZ_ASSERT(!mInputTrack);
+ if (!mStream) {
+ return;
+ }
+
+ mInputTrack = aTrack;
+ ProcessedMediaStream* outputStream =
+ static_cast<ProcessedMediaStream*>(mStream.get());
+ mInputPort = mInputTrack->ForwardTrackContentsTo(outputStream);
+ PrincipalChanged(mInputTrack); // trigger enabling/disabling of the connector
+ mInputTrack->AddPrincipalChangeObserver(this);
+}
+
+void
+MediaStreamAudioSourceNode::DetachFromTrack()
+{
+ if (mInputTrack) {
+ mInputTrack->RemovePrincipalChangeObserver(this);
+ mInputTrack = nullptr;
+ }
+ if (mInputPort) {
+ mInputPort->Destroy();
+ mInputPort = nullptr;
}
}
+void
+MediaStreamAudioSourceNode::AttachToFirstTrack(const RefPtr<DOMMediaStream>& aMediaStream)
+{
+ nsTArray<RefPtr<AudioStreamTrack>> tracks;
+ aMediaStream->GetAudioTracks(tracks);
+
+ if (tracks.IsEmpty()) {
+ return;
+ }
+
+ AttachToTrack(tracks[0]);
+}
+
+void
+MediaStreamAudioSourceNode::NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack)
+{
+ if (mInputTrack) {
+ return;
+ }
+
+ AttachToTrack(aTrack);
+}
+
+void
+MediaStreamAudioSourceNode::NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack)
+{
+ if (aTrack != mInputTrack) {
+ return;
+ }
+
+ DetachFromTrack();
+ AttachToFirstTrack(mInputStream);
+}
+
/**
- * Changes the principal. Note that this will be called on the main thread, but
- * changes will be enacted on the MediaStreamGraph thread. If the principal
+ * Changes the principal. Note that this will be called on the main thread, but
+ * changes will be enacted on the MediaStreamGraph thread. If the principal
* change results in the document principal losing access to the stream, then
* there needs to be other measures in place to ensure that any media that is
- * governed by the new stream principal is not available to the Media Stream
- * Graph before this change completes. Otherwise, a site could get access to
+ * governed by the new stream principal is not available to the MediaStreamGraph
+ * before this change completes. Otherwise, a site could get access to
* media that they are not authorized to receive.
*
* One solution is to block the altered content, call this method, then dispatch
* another change request to the MediaStreamGraph thread that allows the content
- * under the new principal to flow. This might be unnecessary if the principal
+ * under the new principal to flow. This might be unnecessary if the principal
* change is changing to be the document principal.
*/
void
-MediaStreamAudioSourceNode::PrincipalChanged(DOMMediaStream* aDOMMediaStream)
+MediaStreamAudioSourceNode::PrincipalChanged(MediaStreamTrack* aMediaStreamTrack)
{
+ MOZ_ASSERT(aMediaStreamTrack == mInputTrack);
+
bool subsumes = false;
if (nsPIDOMWindowInner* parent = Context()->GetParentObject()) {
nsIDocument* doc = parent->GetExtantDoc();
if (doc) {
nsIPrincipal* docPrincipal = doc->NodePrincipal();
- nsIPrincipal* streamPrincipal = mInputStream->GetPrincipal();
- if (!streamPrincipal || NS_FAILED(docPrincipal->Subsumes(streamPrincipal, &subsumes))) {
+ nsIPrincipal* trackPrincipal = aMediaStreamTrack->GetPrincipal();
+ if (!trackPrincipal || NS_FAILED(docPrincipal->Subsumes(trackPrincipal, &subsumes))) {
subsumes = false;
}
}
}
auto stream = static_cast<AudioNodeExternalInputStream*>(mStream.get());
stream->SetInt32Parameter(MediaStreamAudioSourceNodeEngine::ENABLE,
- subsumes || aDOMMediaStream->GetCORSMode() != CORS_NONE);
+ subsumes || aMediaStreamTrack->GetCORSMode() != CORS_NONE);
}
size_t
MediaStreamAudioSourceNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
// Future:
// - mInputStream
size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
--- a/dom/media/webaudio/MediaStreamAudioSourceNode.h
+++ b/dom/media/webaudio/MediaStreamAudioSourceNode.h
@@ -36,17 +36,18 @@ public:
}
}
private:
bool mEnabled;
};
class MediaStreamAudioSourceNode : public AudioNode,
- public PrincipalChangeObserver<DOMMediaStream>
+ public DOMMediaStream::TrackListener,
+ public PrincipalChangeObserver<MediaStreamTrack>
{
public:
static already_AddRefed<MediaStreamAudioSourceNode>
Create(AudioContext* aContext, DOMMediaStream* aStream, ErrorResult& aRv);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamAudioSourceNode, AudioNode)
@@ -59,24 +60,41 @@ public:
const char* NodeType() const override
{
return "MediaStreamAudioSourceNode";
}
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
- void PrincipalChanged(DOMMediaStream* aMediaStream) override;
+ // Attaches to aTrack so that its audio content will be used as input.
+ void AttachToTrack(const RefPtr<MediaStreamTrack>& aTrack);
+
+ // Detaches from the currently attached track if there is one.
+ void DetachFromTrack();
+
+ // Attaches to the first available audio track in aMediaStream.
+ void AttachToFirstTrack(const RefPtr<DOMMediaStream>& aMediaStream);
+
+ // From DOMMediaStream::TrackListener.
+ void NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack) override;
+ void NotifyTrackRemoved(const RefPtr<MediaStreamTrack>& aTrack) override;
+
+ // From PrincipalChangeObserver<MediaStreamTrack>.
+ void PrincipalChanged(MediaStreamTrack* aMediaStreamTrack) override;
protected:
explicit MediaStreamAudioSourceNode(AudioContext* aContext);
void Init(DOMMediaStream* aMediaStream, ErrorResult& aRv);
virtual ~MediaStreamAudioSourceNode();
private:
RefPtr<MediaInputPort> mInputPort;
RefPtr<DOMMediaStream> mInputStream;
+
+ // On construction we set this to the first audio track of mInputStream.
+ RefPtr<MediaStreamTrack> mInputTrack;
};
} // namespace dom
} // namespace mozilla
#endif