Bug 1208373 - Introduce a new blocking mode to MediaInputPort. r=jesup

This lets us notify about a created TrackUnionStream track (and since it was
created, we can notify when it ends), even though it has been blocked from main
thread.

MozReview-Commit-ID: HyopzISBfbb

--HG--
extra : rebase_source : 55d6dd5d6a34a0b499b45e0b72f900fc37cff1bf
extra : source : 690904309e169aa74f95163f0d796493ef882972
This commit is contained in:
Andreas Pehrson 2016-06-07 16:20:29 +02:00
parent f726141050
commit 5b155d5add
6 changed files with 73 additions and 21 deletions

View File

@ -98,10 +98,10 @@ DOMMediaStream::TrackPort::GetSourceTrackId() const
}
already_AddRefed<Pledge<bool>>
DOMMediaStream::TrackPort::BlockSourceTrackId(TrackID aTrackId)
DOMMediaStream::TrackPort::BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode)
{
if (mInputPort) {
return mInputPort->BlockSourceTrackId(aTrackId);
return mInputPort->BlockSourceTrackId(aTrackId, aBlockingMode);
}
RefPtr<Pledge<bool>> rejected = new Pledge<bool>();
rejected->Reject(NS_ERROR_FAILURE);
@ -1040,8 +1040,10 @@ DOMMediaStream::CloneDOMTrack(MediaStreamTrack& aTrack,
if (aTrack.Ended()) {
// For extra suspenders, make sure that we don't forward data by mistake
// to the clone when the original has already ended.
// We only block END_EXISTING to allow any pending clones to end.
RefPtr<Pledge<bool, nsresult>> blockingPledge =
inputPort->BlockSourceTrackId(inputTrackID);
inputPort->BlockSourceTrackId(inputTrackID,
BlockingMode::END_EXISTING);
Unused << blockingPledge;
}
@ -1249,7 +1251,9 @@ DOMMediaStream::BlockPlaybackTrack(TrackPort* aTrack)
{
MOZ_ASSERT(aTrack);
++mTracksPendingRemoval;
RefPtr<Pledge<bool>> p = aTrack->BlockSourceTrackId(aTrack->GetTrack()->mTrackID);
RefPtr<Pledge<bool>> p =
aTrack->BlockSourceTrackId(aTrack->GetTrack()->mTrackID,
BlockingMode::CREATION);
RefPtr<DOMMediaStream> self = this;
p->Then([self] (const bool& aIgnore) { self->NotifyPlaybackTrackBlocked(); },
[] (const nsresult& aIgnore) { NS_ERROR("Could not remove track from MSG"); }

View File

@ -33,6 +33,8 @@ class MediaStreamDirectListener;
class MediaStreamGraph;
class ProcessedMediaStream;
enum class BlockingMode;
namespace dom {
class AudioNode;
class HTMLCanvasElement;
@ -303,7 +305,8 @@ public:
* destroyed. Returns a pledge that gets resolved when the MediaStreamGraph
* has applied the block in the playback stream.
*/
already_AddRefed<media::Pledge<bool, nsresult>> BlockSourceTrackId(TrackID aTrackId);
already_AddRefed<media::Pledge<bool, nsresult>>
BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode);
private:
RefPtr<MediaInputPort> mInputPort;

View File

@ -3136,24 +3136,26 @@ MediaInputPort::SetGraphImpl(MediaStreamGraphImpl* aGraph)
}
void
MediaInputPort::BlockSourceTrackIdImpl(TrackID aTrackId)
MediaInputPort::BlockSourceTrackIdImpl(TrackID aTrackId, BlockingMode aBlockingMode)
{
mBlockedTracks.AppendElement(aTrackId);
mBlockedTracks.AppendElement(Pair<TrackID, BlockingMode>(aTrackId, aBlockingMode));
}
already_AddRefed<Pledge<bool>>
MediaInputPort::BlockSourceTrackId(TrackID aTrackId)
MediaInputPort::BlockSourceTrackId(TrackID aTrackId, BlockingMode aBlockingMode)
{
class Message : public ControlMessage {
public:
explicit Message(MediaInputPort* aPort,
TrackID aTrackId,
BlockingMode aBlockingMode,
already_AddRefed<nsIRunnable> aRunnable)
: ControlMessage(aPort->GetDestination()),
mPort(aPort), mTrackId(aTrackId), mRunnable(aRunnable) {}
mPort(aPort), mTrackId(aTrackId), mBlockingMode(aBlockingMode),
mRunnable(aRunnable) {}
void Run() override
{
mPort->BlockSourceTrackIdImpl(mTrackId);
mPort->BlockSourceTrackIdImpl(mTrackId, mBlockingMode);
if (mRunnable) {
mStream->Graph()->DispatchToMainThreadAfterStreamStateUpdate(mRunnable.forget());
}
@ -3164,6 +3166,7 @@ MediaInputPort::BlockSourceTrackId(TrackID aTrackId)
}
RefPtr<MediaInputPort> mPort;
TrackID mTrackId;
BlockingMode mBlockingMode;
nsCOMPtr<nsIRunnable> mRunnable;
};
@ -3176,7 +3179,7 @@ MediaInputPort::BlockSourceTrackId(TrackID aTrackId)
pledge->Resolve(true);
return NS_OK;
});
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aTrackId, runnable.forget()));
GraphImpl()->AppendMessage(MakeUnique<Message>(this, aTrackId, aBlockingMode, runnable.forget()));
return pledge.forget();
}
@ -3219,7 +3222,7 @@ ProcessedMediaStream::AllocateInputPort(MediaStream* aStream, TrackID aTrackID,
aInputNumber, aOutputNumber);
if (aBlockedTracks) {
for (TrackID trackID : *aBlockedTracks) {
port->BlockSourceTrackIdImpl(trackID);
port->BlockSourceTrackIdImpl(trackID, BlockingMode::CREATION);
}
}
port->SetGraphImpl(GraphImpl());

View File

@ -1176,6 +1176,23 @@ protected:
bool mNeedsMixing;
};
/**
* The blocking mode decides how a track should be blocked in a MediaInputPort.
*/
enum class BlockingMode
{
/**
* BlockingMode CREATION blocks the source track from being created
* in the destination. It'll end if it already exists.
*/
CREATION,
/**
* BlockingMode END_EXISTING allows a track to be created in the destination
* but will end it before any data has been passed through.
*/
END_EXISTING,
};
/**
* Represents a connection between a ProcessedMediaStream and one of its
* input streams.
@ -1257,16 +1274,39 @@ public:
* Returns a pledge that resolves on the main thread after the track block has
* been applied by the MSG.
*/
already_AddRefed<media::Pledge<bool, nsresult>> BlockSourceTrackId(TrackID aTrackId);
already_AddRefed<media::Pledge<bool, nsresult>> BlockSourceTrackId(TrackID aTrackId,
BlockingMode aBlockingMode);
private:
void BlockSourceTrackIdImpl(TrackID aTrackId);
void BlockSourceTrackIdImpl(TrackID aTrackId, BlockingMode aBlockingMode);
public:
// Returns true if aTrackId has not been blocked and this port has not
// been locked to another track.
// Returns true if aTrackId has not been blocked for any reason and this port
// has not been locked to another track.
bool PassTrackThrough(TrackID aTrackId) {
return !mBlockedTracks.Contains(aTrackId) &&
(mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
bool blocked = false;
for (auto pair : mBlockedTracks) {
if (pair.first() == aTrackId &&
(pair.second() == BlockingMode::CREATION ||
pair.second() == BlockingMode::END_EXISTING)) {
blocked = true;
break;
}
}
return !blocked && (mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
}
// Returns true if aTrackId has not been blocked for track creation and this
// port has not been locked to another track.
bool AllowCreationOf(TrackID aTrackId) {
bool blocked = false;
for (auto pair : mBlockedTracks) {
if (pair.first() == aTrackId &&
pair.second() == BlockingMode::CREATION) {
blocked = true;
break;
}
}
return !blocked && (mSourceTrack == TRACK_ANY || mSourceTrack == aTrackId);
}
uint16_t InputNumber() const { return mInputNumber; }
@ -1321,7 +1361,9 @@ private:
// Web Audio.
const uint16_t mInputNumber;
const uint16_t mOutputNumber;
nsTArray<TrackID> mBlockedTracks;
typedef Pair<TrackID, BlockingMode> BlockedTrack;
nsTArray<BlockedTrack> mBlockedTracks;
// Our media stream graph
MediaStreamGraphImpl* mGraph;

View File

@ -237,7 +237,7 @@ MediaStreamTrack::Stop()
MOZ_ASSERT(mOwningStream, "Every MediaStreamTrack needs an owning DOMMediaStream");
DOMMediaStream::TrackPort* port = mOwningStream->FindOwnedTrackPort(*this);
MOZ_ASSERT(port, "A MediaStreamTrack must exist in its owning DOMMediaStream");
RefPtr<Pledge<bool>> p = port->BlockSourceTrackId(mInputTrackID);
RefPtr<Pledge<bool>> p = port->BlockSourceTrackId(mInputTrackID, BlockingMode::CREATION);
Unused << p;
mReadyState = MediaStreamTrackState::Ended;

View File

@ -107,7 +107,7 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
break;
}
}
if (!found && mInputs[i]->PassTrackThrough(tracks->GetID())) {
if (!found && mInputs[i]->AllowCreationOf(tracks->GetID())) {
bool trackFinished = false;
trackAdded = true;
uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom);