void TrackUnionStream::RemoveAllDirectListenersImpl() { for (TrackMapEntry& entry : mTrackMap) { nsTArray<RefPtr<DirectMediaStreamTrackListener>> listeners( entry.mOwnedDirectListeners); for (const auto& listener : listeners) { RemoveDirectTrackListenerImpl(listener, entry.mOutputTrackID); } MOZ_DIAGNOSTIC_ASSERT(entry.mOwnedDirectListeners.IsEmpty()); } nsTArray<TrackBound<DirectMediaStreamTrackListener>> boundListeners( mPendingDirectTrackListeners); for (const auto& binding : boundListeners) { RemoveDirectTrackListenerImpl(binding.mListener, binding.mTrackID); } MOZ_DIAGNOSTIC_ASSERT(mPendingDirectTrackListeners.IsEmpty()); }
void TrackUnionStream::RemoveInput(MediaInputPort* aPort) { STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing input %p", this, aPort)); for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mTrackMap[i].mInputPort == aPort) { STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing trackmap entry %d", this, i)); EndTrack(i); for (auto listener : mTrackMap[i].mOwnedDirectListeners) { // Remove listeners while the entry still exists. RemoveDirectTrackListenerImpl(listener, mTrackMap[i].mOutputTrackID); } mTrackMap.RemoveElementAt(i); } } ProcessedMediaStream::RemoveInput(aPort); }
void TrackUnionStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) { if (IsFinishedOnGraphThread()) { return; } AutoTArray<bool,8> mappedTracksFinished; AutoTArray<bool,8> mappedTracksWithMatchingInputTracks; for (uint32_t i = 0; i < mTrackMap.Length(); ++i) { mappedTracksFinished.AppendElement(true); mappedTracksWithMatchingInputTracks.AppendElement(false); } bool allFinished = !mInputs.IsEmpty(); bool allHaveCurrentData = !mInputs.IsEmpty(); for (uint32_t i = 0; i < mInputs.Length(); ++i) { MediaStream* stream = mInputs[i]->GetSource(); if (!stream->IsFinishedOnGraphThread()) { // XXX we really should check whether 'stream' has finished within time aTo, // not just that it's finishing when all its queued data eventually runs // out. allFinished = false; } if (!stream->HasCurrentData()) { allHaveCurrentData = false; } bool trackAdded = false; for (StreamTracks::TrackIter tracks(stream->GetStreamTracks()); !tracks.IsEnded(); tracks.Next()) { bool found = false; for (uint32_t j = 0; j < mTrackMap.Length(); ++j) { TrackMapEntry* map = &mTrackMap[j]; if (map->mInputPort == mInputs[i] && map->mInputTrackID == tracks->GetID()) { bool trackFinished = false; StreamTracks::Track* outputTrack = mTracks.FindTrack(map->mOutputTrackID); found = true; if (!outputTrack || outputTrack->IsEnded() || !mInputs[i]->PassTrackThrough(tracks->GetID())) { trackFinished = true; } else { CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished); } mappedTracksFinished[j] = trackFinished; mappedTracksWithMatchingInputTracks[j] = true; break; } } if (!found && mInputs[i]->AllowCreationOf(tracks->GetID())) { bool trackFinished = false; trackAdded = true; uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom); CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished); mappedTracksFinished.AppendElement(trackFinished); mappedTracksWithMatchingInputTracks.AppendElement(true); } } if (trackAdded) { for (MediaStreamListener* l : mListeners) { l->NotifyFinishedTrackCreation(Graph()); } } } for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) { if (mappedTracksFinished[i]) { EndTrack(i); } else { allFinished = false; } if (!mappedTracksWithMatchingInputTracks[i]) { for (auto listener : mTrackMap[i].mOwnedDirectListeners) { // Remove listeners while the entry still exists. RemoveDirectTrackListenerImpl(listener, mTrackMap[i].mOutputTrackID); } mTrackMap.RemoveElementAt(i); } } if (allFinished && mAutofinish && (aFlags & ALLOW_FINISH)) { // All streams have finished and won't add any more tracks, and // all our tracks have actually finished and been removed from our map, // so we're finished now. FinishOnGraphThread(); } else { mTracks.AdvanceKnownTracksTime(GraphTimeToStreamTimeWithBlocking(aTo)); } if (allHaveCurrentData) { // We can make progress if we're not blocked mHasCurrentData = true; } }