Bug 1274221 - Ensure MediaStreamListeners are always notified of created and ended tracks. r=ctai, r=jesup

This means that when a MediaStreamListener is added to a stream, we'll call
NotifyQueuedTrackChanges with TRACK_EVENT_CREATE for all tracks that already
exist.

Likewise, we'll call NotifyQueuedTrackChanges with TRACK_EVENT_ENDED for all
tracks that exist and have ended.

This fixes potential race conditions where a track was created and/or ended
before the listener was asynchronously added.

MozReview-Commit-ID: G3juhfiZMtg

--HG--
extra : rebase_source : 6f4fe68b888b6dd0d9ee370b6a390ff17da5f1de
extra : source : 70e8c5a785a9866e6205b54bd1c45faaf834717d
This commit is contained in:
Andreas Pehrson 2016-05-24 13:23:50 +02:00
Родитель 9c625f8d0f
Коммит e9c91bddf6
4 изменённых файлов: 54 добавлений и 0 удалений

Просмотреть файл

@ -2380,6 +2380,31 @@ MediaStream::AddListenerImpl(already_AddRefed<MediaStreamListener> aListener)
MediaStreamListener* listener = *mListeners.AppendElement() = aListener;
listener->NotifyBlockingChanged(GraphImpl(),
mNotifiedBlocked ? MediaStreamListener::BLOCKED : MediaStreamListener::UNBLOCKED);
for (StreamTracks::TrackIter it(mTracks); !it.IsEnded(); it.Next()) {
MediaStream* inputStream = nullptr;
TrackID inputTrackID = TRACK_INVALID;
if (ProcessedMediaStream* ps = AsProcessedStream()) {
// The only ProcessedMediaStream where we should have listeners is
// TrackUnionStream - it's what's used as owned stream in DOMMediaStream,
// the only main-thread exposed stream type.
// TrackUnionStream guarantees that each of its tracks has an input track.
// Other types do not implement GetInputStreamFor() and will return null.
inputStream = ps->GetInputStreamFor(it->GetID());
MOZ_ASSERT(inputStream);
inputTrackID = ps->GetInputTrackIDFor(it->GetID());
MOZ_ASSERT(IsTrackIDExplicit(inputTrackID));
}
uint32_t flags = MediaStreamListener::TRACK_EVENT_CREATED;
if (it->IsEnded()) {
flags |= MediaStreamListener::TRACK_EVENT_ENDED;
}
nsAutoPtr<MediaSegment> segment(it->GetSegment()->CreateEmptyClone());
listener->NotifyQueuedTrackChanges(Graph(), it->GetID(), it->GetEnd(),
flags, *segment,
inputStream, inputTrackID);
}
if (mNotifiedFinished) {
listener->NotifyEvent(GraphImpl(), MediaStreamListener::EVENT_FINISHED);
}

Просмотреть файл

@ -1439,6 +1439,8 @@ public:
{
return mInputs.Length();
}
virtual MediaStream* GetInputStreamFor(TrackID aTrackID) { return nullptr; }
virtual TrackID GetInputTrackIDFor(TrackID aTrackID) { return TRACK_NONE; }
void DestroyImpl() override;
/**
* This gets called after we've computed the blocking states for all

Просмотреть файл

@ -374,6 +374,30 @@ TrackUnionStream::SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) {
MediaStream::SetTrackEnabledImpl(aTrackID, aEnabled);
}
MediaStream*
TrackUnionStream::GetInputStreamFor(TrackID aTrackID)
{
for (TrackMapEntry& entry : mTrackMap) {
if (entry.mOutputTrackID == aTrackID && entry.mInputPort) {
return entry.mInputPort->GetSource();
}
}
return nullptr;
}
TrackID
TrackUnionStream::GetInputTrackIDFor(TrackID aTrackID)
{
for (TrackMapEntry& entry : mTrackMap) {
if (entry.mOutputTrackID == aTrackID) {
return entry.mInputTrackID;
}
}
return TRACK_NONE;
}
void
TrackUnionStream::AddDirectTrackListenerImpl(already_AddRefed<MediaStreamTrackDirectListener> aListener,
TrackID aTrackID)

Просмотреть файл

@ -23,6 +23,9 @@ public:
void SetTrackEnabledImpl(TrackID aTrackID, bool aEnabled) override;
MediaStream* GetInputStreamFor(TrackID aTrackID) override;
TrackID GetInputTrackIDFor(TrackID aTrackID) override;
protected:
// Only non-ended tracks are allowed to persist in this map.
struct TrackMapEntry {