1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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 "MediaStreamGraph.h"
8 #include "OutputStreamManager.h"
9
10 namespace mozilla {
11
~OutputStreamData()12 OutputStreamData::~OutputStreamData() {
13 MOZ_ASSERT(NS_IsMainThread());
14 // Break the connection to the input stream if necessary.
15 for (RefPtr<MediaInputPort>& port : mPorts) {
16 port->Destroy();
17 }
18 }
19
Init(OutputStreamManager * aOwner,ProcessedMediaStream * aStream,TrackID aNextAvailableTrackID)20 void OutputStreamData::Init(OutputStreamManager* aOwner,
21 ProcessedMediaStream* aStream,
22 TrackID aNextAvailableTrackID) {
23 mOwner = aOwner;
24 mStream = aStream;
25 mNextAvailableTrackID = aNextAvailableTrackID;
26 }
27
Connect(MediaStream * aStream,TrackID aInputAudioTrackID,TrackID aInputVideoTrackID)28 bool OutputStreamData::Connect(MediaStream* aStream, TrackID aInputAudioTrackID,
29 TrackID aInputVideoTrackID) {
30 MOZ_ASSERT(NS_IsMainThread());
31 MOZ_ASSERT(mPorts.IsEmpty(), "Already connected?");
32
33 if (mStream->IsDestroyed()) {
34 return false;
35 }
36
37 for (TrackID tid : {aInputAudioTrackID, aInputVideoTrackID}) {
38 if (tid == TRACK_NONE) {
39 continue;
40 }
41 MOZ_ASSERT(IsTrackIDExplicit(tid));
42 mPorts.AppendElement(
43 mStream->AllocateInputPort(aStream, tid, mNextAvailableTrackID++));
44 }
45 return true;
46 }
47
Disconnect()48 bool OutputStreamData::Disconnect() {
49 MOZ_ASSERT(NS_IsMainThread());
50
51 // During cycle collection, DOMMediaStream can be destroyed and send
52 // its Destroy message before this decoder is destroyed. So we have to
53 // be careful not to send any messages after the Destroy().
54 if (mStream->IsDestroyed()) {
55 return false;
56 }
57
58 // Disconnect any existing port.
59 for (RefPtr<MediaInputPort>& port : mPorts) {
60 port->Destroy();
61 }
62 mPorts.Clear();
63 return true;
64 }
65
Equals(MediaStream * aStream) const66 bool OutputStreamData::Equals(MediaStream* aStream) const {
67 return mStream == aStream;
68 }
69
Graph() const70 MediaStreamGraph* OutputStreamData::Graph() const { return mStream->Graph(); }
71
NextAvailableTrackID() const72 TrackID OutputStreamData::NextAvailableTrackID() const {
73 return mNextAvailableTrackID;
74 }
75
Add(ProcessedMediaStream * aStream,TrackID aNextAvailableTrackID,bool aFinishWhenEnded)76 void OutputStreamManager::Add(ProcessedMediaStream* aStream,
77 TrackID aNextAvailableTrackID,
78 bool aFinishWhenEnded) {
79 MOZ_ASSERT(NS_IsMainThread());
80 // All streams must belong to the same graph.
81 MOZ_ASSERT(!Graph() || Graph() == aStream->Graph());
82
83 // Ensure that aStream finishes the moment mDecodedStream does.
84 if (aFinishWhenEnded) {
85 aStream->QueueSetAutofinish(true);
86 }
87
88 OutputStreamData* p = mStreams.AppendElement();
89 p->Init(this, aStream, aNextAvailableTrackID);
90
91 // Connect to the input stream if we have one. Otherwise the output stream
92 // will be connected in Connect().
93 if (mInputStream) {
94 p->Connect(mInputStream, mInputAudioTrackID, mInputVideoTrackID);
95 }
96 }
97
Remove(MediaStream * aStream)98 void OutputStreamManager::Remove(MediaStream* aStream) {
99 MOZ_ASSERT(NS_IsMainThread());
100 for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
101 if (mStreams[i].Equals(aStream)) {
102 mStreams.RemoveElementAt(i);
103 break;
104 }
105 }
106 }
107
Clear()108 void OutputStreamManager::Clear() {
109 MOZ_ASSERT(NS_IsMainThread());
110 mStreams.Clear();
111 }
112
NextAvailableTrackIDFor(MediaStream * aOutputStream) const113 TrackID OutputStreamManager::NextAvailableTrackIDFor(
114 MediaStream* aOutputStream) const {
115 MOZ_ASSERT(NS_IsMainThread());
116 for (const OutputStreamData& out : mStreams) {
117 if (out.Equals(aOutputStream)) {
118 return out.NextAvailableTrackID();
119 }
120 }
121 return TRACK_INVALID;
122 }
123
Connect(MediaStream * aStream,TrackID aAudioTrackID,TrackID aVideoTrackID)124 void OutputStreamManager::Connect(MediaStream* aStream, TrackID aAudioTrackID,
125 TrackID aVideoTrackID) {
126 MOZ_ASSERT(NS_IsMainThread());
127 mInputStream = aStream;
128 mInputAudioTrackID = aAudioTrackID;
129 mInputVideoTrackID = aVideoTrackID;
130 for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
131 if (!mStreams[i].Connect(aStream, mInputAudioTrackID, mInputVideoTrackID)) {
132 // Probably the DOMMediaStream was GCed. Clean up.
133 mStreams.RemoveElementAt(i);
134 }
135 }
136 }
137
Disconnect()138 void OutputStreamManager::Disconnect() {
139 MOZ_ASSERT(NS_IsMainThread());
140 mInputStream = nullptr;
141 mInputAudioTrackID = TRACK_INVALID;
142 mInputVideoTrackID = TRACK_INVALID;
143 for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
144 if (!mStreams[i].Disconnect()) {
145 // Probably the DOMMediaStream was GCed. Clean up.
146 mStreams.RemoveElementAt(i);
147 }
148 }
149 }
150
151 } // namespace mozilla
152