Bug 1170958 - Refactor DOMMediaStream to contain a 3-stage track chain. r=roc

This lets us separate tracks by ownership like so:
* Input    - Owned by the producer of the DOMMediaStream (gUM etc.)
* Owned    - Contains Input tracks (per above) or tracks cloned tracks
             if this DOMMediaStream is a clone.
* Playback - Contains Owned tracks plus tracks addTrack()ed to this
             DOMMediaStream minus tracks removeTrack()ed from this
             DOMMediaStream.

--HG--
extra : commitid : GPSNwBVyD4j
extra : rebase_source : fba22e96c6c65a74e012509f3da67a4d7df7a244
This commit is contained in:
Andreas Pehrson 2015-09-30 09:31:54 +08:00
Родитель 53a6c38d0d
Коммит 937747498a
25 изменённых файлов: 518 добавлений и 194 удалений

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

@ -42,7 +42,6 @@ class CameraPreviewMediaStream : public MediaStream
public:
explicit CameraPreviewMediaStream(DOMMediaStream* aWrapper);
virtual CameraPreviewMediaStream* AsCameraPreviewStream() override { return this; };
virtual void AddAudioOutput(void* aKey) override;
virtual void SetAudioOutputVolume(void* aKey, float aVolume) override;
virtual void RemoveAudioOutput(void* aKey) override;

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

@ -279,8 +279,13 @@ nsDOMCameraControl::nsDOMCameraControl(uint32_t aCameraId,
#endif
mCurrentConfiguration = initialConfig.forget();
// Attach our DOM-facing media stream to our viewfinder stream.
InitStreamCommon(mInput);
// Register the playback listener directly on the camera input stream.
// We want as low latency as possible for the camera, thus avoiding
// MediaStreamGraph altogether. Don't do the regular InitStreamCommon()
// to avoid initializing the Owned and Playback streams. This is OK since
// we are not user/DOM facing anyway.
CreateAndAddPlaybackStreamListener(mInput);
MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
if (mWindow->GetExtantDoc()) {
CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
@ -324,6 +329,11 @@ nsDOMCameraControl::~nsDOMCameraControl()
DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
/*invoke DOMMediaStream destroy*/
Destroy();
if (mInput) {
mInput->Destroy();
mInput = nullptr;
}
}
JSObject*
@ -459,6 +469,12 @@ nsDOMCameraControl::Get(uint32_t aKey, nsTArray<CameraRegion>& aValue)
return NS_OK;
}
MediaStream*
nsDOMCameraControl::GetCameraStream() const
{
return mInput;
}
#define THROW_IF_NO_CAMERACONTROL(...) \
do { \
if (!mCameraControl) { \

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

@ -71,6 +71,8 @@ public:
nsPIDOMWindow* GetParentObject() const { return mWindow; }
MediaStream* GetCameraStream() const override;
// Attributes.
void GetEffect(nsString& aEffect, ErrorResult& aRv);
void SetEffect(const nsAString& aEffect, ErrorResult& aRv);

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

@ -542,7 +542,7 @@ HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
return nullptr;
}
stream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO);
stream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO);
RegisterFrameCaptureListener(stream->FrameCaptureListener());
return stream.forget();
}

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

@ -561,7 +561,7 @@ HTMLMediaElement::GetMozMediaSourceObject() const
already_AddRefed<DOMMediaStream>
HTMLMediaElement::GetSrcObject() const
{
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetStream(),
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetPlaybackStream(),
"MediaStream should have been set up properly");
nsRefPtr<DOMMediaStream> stream = mSrcAttrStream;
return stream.forget();
@ -585,7 +585,7 @@ HTMLMediaElement::SetSrcObject(DOMMediaStream* aValue)
already_AddRefed<DOMMediaStream>
HTMLMediaElement::GetMozSrcObject() const
{
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetStream(),
NS_ASSERTION(!mSrcAttrStream || mSrcAttrStream->GetPlaybackStream(),
"MediaStream should have been set up properly");
nsRefPtr<DOMMediaStream> stream = mSrcAttrStream;
return stream.forget();
@ -1876,17 +1876,17 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
mAudioCaptured = true;
if (mDecoder) {
mDecoder->AddOutputStream(out->mStream->GetStream()->AsProcessedStream(),
mDecoder->AddOutputStream(out->mStream->GetInputStream()->AsProcessedStream(),
aFinishWhenEnded);
if (mReadyState >= HAVE_METADATA) {
// Expose the tracks to JS directly.
if (HasAudio()) {
TrackID audioTrackId = mMediaInfo.mAudio.mTrackId;
out->mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO);
out->mStream->CreateOwnDOMTrack(audioTrackId, MediaSegment::AUDIO);
}
if (HasVideo()) {
TrackID videoTrackId = mMediaInfo.mVideo.mTrackId;
out->mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO);
out->mStream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO);
}
}
}
@ -2446,7 +2446,7 @@ bool HTMLMediaElement::ParseAttribute(int32_t aNamespaceID,
mAudioChannel = audioChannel;
if (mSrcStream) {
nsRefPtr<MediaStream> stream = mSrcStream->GetStream();
nsRefPtr<MediaStream> stream = GetSrcMediaStream();
if (stream) {
stream->SetAudioChannelType(mAudioChannel);
}
@ -2861,7 +2861,7 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
for (uint32_t i = 0; i < mOutputStreams.Length(); ++i) {
OutputMediaStream* ms = &mOutputStreams[i];
aDecoder->AddOutputStream(ms->mStream->GetStream()->AsProcessedStream(),
aDecoder->AddOutputStream(ms->mStream->GetInputStream()->AsProcessedStream(),
ms->mFinishWhenEnded);
}
@ -3105,10 +3105,10 @@ void HTMLMediaElement::UpdateSrcMediaStreamPlaying(uint32_t aFlags)
if (!mSrcStream) {
return;
}
// We might be in cycle collection with mSrcStream->GetStream() already
// We might be in cycle collection with mSrcStream->GetPlaybackStream() already
// returning null due to unlinking.
MediaStream* stream = mSrcStream->GetStream();
MediaStream* stream = GetSrcMediaStream();
bool shouldPlay = !(aFlags & REMOVING_SRC_STREAM) && !mPaused &&
!mPausedForInactiveDocumentOrChannel && stream;
if (shouldPlay == mSrcStreamIsPlaying) {
@ -3183,7 +3183,7 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
return;
}
nsRefPtr<MediaStream> stream = mSrcStream->GetStream();
nsRefPtr<MediaStream> stream = GetSrcMediaStream();
if (stream) {
stream->SetAudioChannelType(mAudioChannel);
}
@ -3282,11 +3282,11 @@ void HTMLMediaElement::MetadataLoaded(const MediaInfo* aInfo,
for (OutputMediaStream& out : mOutputStreams) {
if (aInfo->HasAudio()) {
TrackID audioTrackId = aInfo->mAudio.mTrackId;
out.mStream->CreateDOMTrack(audioTrackId, MediaSegment::AUDIO);
out.mStream->CreateOwnDOMTrack(audioTrackId, MediaSegment::AUDIO);
}
if (aInfo->HasVideo()) {
TrackID videoTrackId = aInfo->mVideo.mTrackId;
out.mStream->CreateDOMTrack(videoTrackId, MediaSegment::VIDEO);
out.mStream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO);
}
}
@ -4789,11 +4789,11 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
AudioChannel::Normal);
if (mSrcStream) {
mCaptureStreamPort = msg->ConnectToCaptureStream(id, mSrcStream->GetStream());
if (GetSrcMediaStream()) {
mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());
} else {
nsRefPtr<DOMMediaStream> stream = CaptureStreamInternal(false, msg);
mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetStream());
mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetPlaybackStream());
}
} else {
mAudioCapturedByWindow = false;
@ -4803,7 +4803,7 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
MOZ_ASSERT(ps);
for (uint32_t i = 0; i < mOutputStreams.Length(); i++) {
if (mOutputStreams[i].mStream->GetStream() == ps) {
if (mOutputStreams[i].mStream->GetPlaybackStream() == ps) {
mOutputStreams.RemoveElementAt(i);
break;
}

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

@ -349,12 +349,19 @@ public:
/**
* This will return null if mSrcStream is null, or if mSrcStream is not
* null but its GetStream() returns null --- which can happen during
* null but its GetPlaybackStream() returns null --- which can happen during
* cycle collection unlinking!
*/
MediaStream* GetSrcMediaStream() const
{
return mSrcStream ? mSrcStream->GetStream() : nullptr;
if (!mSrcStream) {
return nullptr;
}
if (mSrcStream->GetCameraStream()) {
// XXX Remove this check with CameraPreviewMediaStream per bug 1124630.
return mSrcStream->GetCameraStream();
}
return mSrcStream->GetPlaybackStream();
}
// WebIDL
@ -1093,11 +1100,6 @@ protected:
// Holds a reference to the stream connecting this stream to the capture sink.
nsRefPtr<MediaInputPort> mCaptureStreamPort;
// Holds a reference to a stream with mSrcStream as input but intended for
// playback. Used so we don't block playback of other video elements
// playing the same mSrcStream.
nsRefPtr<DOMMediaStream> mPlaybackStream;
// Holds references to the DOM wrappers for the MediaStreams that we're
// writing to.
struct OutputMediaStream {
@ -1106,8 +1108,8 @@ protected:
};
nsTArray<OutputMediaStream> mOutputStreams;
// Holds a reference to the MediaStreamListener attached to mPlaybackStream
// (or mSrcStream if mPlaybackStream is null).
// Holds a reference to the MediaStreamListener attached to mSrcStream's
// playback stream.
nsRefPtr<StreamListener> mMediaStreamListener;
// Holds a reference to the size-getting MediaStreamListener attached to
// mSrcStream.

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

@ -241,14 +241,14 @@ CanvasCaptureMediaStream::Init(const dom::Optional<double>& aFPS,
{
if (!aFPS.WasPassed()) {
mOutputStreamDriver =
new AutoDriver(GetStream()->AsSourceStream(), aTrackId);
new AutoDriver(GetInputStream()->AsSourceStream(), aTrackId);
} else if (aFPS.Value() < 0) {
return NS_ERROR_ILLEGAL_VALUE;
} else {
// Cap frame rate to 60 FPS for sanity
double fps = std::min(60.0, aFPS.Value());
mOutputStreamDriver =
new TimerDriver(GetStream()->AsSourceStream(), fps, aTrackId);
new TimerDriver(GetInputStream()->AsSourceStream(), fps, aTrackId);
}
return NS_OK;
}

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

@ -27,9 +27,97 @@ using namespace mozilla::layers;
const TrackID TRACK_VIDEO_PRIMARY = 1;
class DOMMediaStream::StreamListener : public MediaStreamListener {
/**
* TrackPort is a representation of a MediaStreamTrack-MediaInputPort pair
* that make up a link between the Owned stream and the Playback stream.
*
* Semantically, the track is the identifier/key and the port the value of this
* connection.
*
* The input port can be shared between several TrackPorts. This is the case
* for DOMMediaStream's mPlaybackPort which forwards all tracks in its
* mOwnedStream automatically.
*
* If the MediaStreamTrack is owned by another DOMMediaStream (called A) than
* the one owning the TrackPort (called B), the input port (locked to the
* MediaStreamTrack's TrackID) connects A's mOwnedStream to B's mPlaybackStream.
*
* A TrackPort may never leave the DOMMediaStream it was created in. Internal
* use only.
*/
class DOMMediaStream::TrackPort
{
public:
explicit StreamListener(DOMMediaStream* aStream)
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TrackPort)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(TrackPort)
enum class InputPortOwnership {
OWNED = 1,
EXTERNAL
};
TrackPort(MediaInputPort* aInputPort,
MediaStreamTrack* aTrack,
const InputPortOwnership aOwnership)
: mInputPort(aInputPort)
, mTrack(aTrack)
, mOwnership(aOwnership)
{
MOZ_ASSERT(mInputPort);
MOZ_ASSERT(mTrack);
MOZ_COUNT_CTOR(TrackPort);
}
protected:
virtual ~TrackPort()
{
MOZ_COUNT_DTOR(TrackPort);
if (mOwnership == InputPortOwnership::OWNED && mInputPort) {
mInputPort->Destroy();
mInputPort = nullptr;
}
}
public:
/**
* Returns the source stream of the input port.
*/
MediaStream* GetSource() const { return mInputPort ? mInputPort->GetSource()
: nullptr; }
/**
* Returns the track ID this track is locked to in the source stream of the
* input port.
*/
TrackID GetSourceTrackId() const { return mInputPort ? mInputPort->GetSourceTrackId()
: TRACK_INVALID; }
MediaInputPort* GetInputPort() const { return mInputPort; }
MediaStreamTrack* GetTrack() const { return mTrack; }
private:
nsRefPtr<MediaInputPort> mInputPort;
nsRefPtr<MediaStreamTrack> mTrack;
// Defines if we've been given ownership of the input port or if it's owned
// externally. The owner is responsible for destroying the port.
const InputPortOwnership mOwnership;
};
NS_IMPL_CYCLE_COLLECTION(DOMMediaStream::TrackPort, mTrack)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMMediaStream::TrackPort, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMMediaStream::TrackPort, Release)
/**
* Listener registered on the Playback stream to detect when tracks end and when
* all new tracks this iteration have been created - for when several tracks are
* queued by the source and committed all at once.
*/
class DOMMediaStream::PlaybackStreamListener : public MediaStreamListener {
public:
explicit PlaybackStreamListener(DOMMediaStream* aStream)
: mStream(aStream)
{}
@ -39,7 +127,7 @@ public:
class TrackChange : public nsRunnable {
public:
TrackChange(StreamListener* aListener,
TrackChange(PlaybackStreamListener* aListener,
TrackID aID, StreamTime aTrackOffset,
uint32_t aEvents, MediaSegment::Type aType,
MediaStream* aInputStream, TrackID aInputTrackID)
@ -57,30 +145,21 @@ public:
return NS_OK;
}
nsRefPtr<MediaStreamTrack> track;
if (mEvents & MediaStreamListener::TRACK_EVENT_CREATED) {
track = stream->BindDOMTrack(mID, mType);
if (!track) {
stream->CreateDOMTrack(mID, mType);
track = stream->BindDOMTrack(mID, mType);
}
stream->NotifyMediaStreamTrackCreated(track);
} else {
track = stream->GetDOMTrackFor(mID);
MOZ_ASSERT(mEvents & MediaStreamListener::TRACK_EVENT_ENDED);
nsRefPtr<MediaStreamTrack> track = stream->FindOwnedDOMTrack(mInputStream, mID);
if (track) {
track->NotifyEnded();
}
if (mEvents & MediaStreamListener::TRACK_EVENT_ENDED) {
if (track) {
track->NotifyEnded();
stream->NotifyMediaStreamTrackEnded(track);
} else {
NS_ERROR("track ended but not found");
}
track = stream->FindPlaybackDOMTrack(mInputStream, mInputTrackID);
if (track) {
stream->NotifyMediaStreamTrackEnded(track);
}
return NS_OK;
}
StreamTime mEndTime;
nsRefPtr<StreamListener> mListener;
nsRefPtr<PlaybackStreamListener> mListener;
TrackID mID;
uint32_t mEvents;
MediaSegment::Type mType;
@ -88,13 +167,6 @@ public:
TrackID mInputTrackID;
};
/**
* Notify that changes to one of the stream tracks have been queued.
* aTrackEvents can be any combination of TRACK_EVENT_CREATED and
* TRACK_EVENT_ENDED. aQueuedMedia is the data being added to the track
* at aTrackOffset (relative to the start of the stream).
* aQueuedMedia can be null if there is no output.
*/
virtual void NotifyQueuedTrackChanges(MediaStreamGraph* aGraph, TrackID aID,
StreamTime aTrackOffset,
uint32_t aTrackEvents,
@ -102,7 +174,7 @@ public:
MediaStream* aInputStream,
TrackID aInputTrackID) override
{
if (aTrackEvents & (TRACK_EVENT_CREATED | TRACK_EVENT_ENDED)) {
if (aTrackEvents & TRACK_EVENT_ENDED) {
nsRefPtr<TrackChange> runnable =
new TrackChange(this, aID, aTrackOffset, aTrackEvents,
aQueuedMedia.GetType(), aInputStream, aInputTrackID);
@ -112,7 +184,7 @@ public:
class TracksCreatedRunnable : public nsRunnable {
public:
explicit TracksCreatedRunnable(StreamListener* aListener)
explicit TracksCreatedRunnable(PlaybackStreamListener* aListener)
: mListener(aListener)
{
}
@ -130,7 +202,7 @@ public:
return NS_OK;
}
nsRefPtr<StreamListener> mListener;
nsRefPtr<PlaybackStreamListener> mListener;
};
virtual void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) override
@ -150,6 +222,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMMediaStream,
DOMEventTargetHelper)
tmp->Destroy();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwnedTracks)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTracks)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsumersToKeepAlive)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -157,6 +230,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMMediaStream,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwnedTracks)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTracks)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsumersToKeepAlive)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -185,9 +259,10 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream)
NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
DOMMediaStream::DOMMediaStream()
: mLogicalStreamStartTime(0),
mStream(nullptr), mTracksCreated(false),
mNotifiedOfMediaStreamGraphShutdown(false), mCORSMode(CORS_NONE)
: mLogicalStreamStartTime(0), mInputStream(nullptr), mOwnedStream(nullptr),
mPlaybackStream(nullptr), mOwnedPort(nullptr), mPlaybackPort(nullptr),
mTracksCreated(false), mNotifiedOfMediaStreamGraphShutdown(false),
mCORSMode(CORS_NONE)
{
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
@ -217,9 +292,25 @@ DOMMediaStream::Destroy()
mListener->Forget();
mListener = nullptr;
}
if (mStream) {
mStream->Destroy();
mStream = nullptr;
if (mPlaybackPort) {
mPlaybackPort->Destroy();
mPlaybackPort = nullptr;
}
if (mOwnedPort) {
mOwnedPort->Destroy();
mOwnedPort = nullptr;
}
if (mPlaybackStream) {
mPlaybackStream->Destroy();
mPlaybackStream = nullptr;
}
if (mOwnedStream) {
mOwnedStream->Destroy();
mOwnedStream = nullptr;
}
if (mInputStream) {
mInputStream->Destroy();
mInputStream = nullptr;
}
}
@ -232,11 +323,11 @@ DOMMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
double
DOMMediaStream::CurrentTime()
{
if (!mStream) {
if (!mPlaybackStream) {
return 0.0;
}
return mStream->
StreamTimeToSeconds(mStream->GetCurrentTime() - mLogicalStreamStartTime);
return mPlaybackStream->
StreamTimeToSeconds(mPlaybackStream->GetCurrentTime() - mLogicalStreamStartTime);
}
void
@ -248,8 +339,8 @@ DOMMediaStream::GetId(nsAString& aID) const
void
DOMMediaStream::GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks)
{
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
AudioStreamTrack* t = mTracks[i]->AsAudioStreamTrack();
for (const nsRefPtr<TrackPort>& info : mTracks) {
AudioStreamTrack* t = info->GetTrack()->AsAudioStreamTrack();
if (t) {
aTracks.AppendElement(t);
}
@ -259,8 +350,8 @@ DOMMediaStream::GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks)
void
DOMMediaStream::GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks)
{
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
VideoStreamTrack* t = mTracks[i]->AsVideoStreamTrack();
for (const nsRefPtr<TrackPort>& info : mTracks) {
VideoStreamTrack* t = info->GetTrack()->AsVideoStreamTrack();
if (t) {
aTracks.AppendElement(t);
}
@ -270,19 +361,27 @@ DOMMediaStream::GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks)
void
DOMMediaStream::GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks)
{
aTracks.AppendElements(mTracks);
for (const nsRefPtr<TrackPort>& info : mTracks) {
aTracks.AppendElement(info->GetTrack());
}
}
bool
DOMMediaStream::HasTrack(const MediaStreamTrack& aTrack) const
{
return mTracks.Contains(&aTrack);
return !!FindPlaybackDOMTrack(aTrack.GetStream()->GetOwnedStream(), aTrack.GetTrackID());
}
bool
DOMMediaStream::OwnsTrack(const MediaStreamTrack& aTrack) const
{
return (aTrack.GetStream() == this) && HasTrack(aTrack);
}
bool
DOMMediaStream::IsFinished()
{
return !mStream || mStream->IsFinished();
return !mPlaybackStream || mPlaybackStream->IsFinished();
}
void
@ -290,7 +389,7 @@ DOMMediaStream::InitSourceStream(nsIDOMWindow* aWindow,
MediaStreamGraph* aGraph)
{
mWindow = aWindow;
InitStreamCommon(aGraph->CreateSourceStream(this));
InitStreamCommon(aGraph->CreateSourceStream(nullptr), aGraph);
}
void
@ -298,8 +397,7 @@ DOMMediaStream::InitTrackUnionStream(nsIDOMWindow* aWindow,
MediaStreamGraph* aGraph)
{
mWindow = aWindow;
InitStreamCommon(aGraph->CreateTrackUnionStream(this));
InitStreamCommon(aGraph->CreateTrackUnionStream(nullptr), aGraph);
}
void
@ -310,18 +408,29 @@ DOMMediaStream::InitAudioCaptureStream(nsIDOMWindow* aWindow,
const TrackID AUDIO_TRACK = 1;
InitStreamCommon(aGraph->CreateAudioCaptureStream(this, AUDIO_TRACK));
CreateDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO);
InitStreamCommon(aGraph->CreateAudioCaptureStream(this, AUDIO_TRACK), aGraph);
CreateOwnDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO);
}
void
DOMMediaStream::InitStreamCommon(MediaStream* aStream)
DOMMediaStream::InitStreamCommon(MediaStream* aStream,
MediaStreamGraph* aGraph)
{
mStream = aStream;
mInputStream = aStream;
// We pass null as the wrapper since it is only used to signal finished
// streams. This is only needed for the playback stream.
mOwnedStream = aGraph->CreateTrackUnionStream(nullptr);
mOwnedStream->SetAutofinish(true);
mOwnedPort = mOwnedStream->AllocateInputPort(mInputStream);
mPlaybackStream = aGraph->CreateTrackUnionStream(this);
mPlaybackStream->SetAutofinish(true);
mPlaybackPort = mPlaybackStream->AllocateInputPort(mOwnedStream);
// Setup track listener
mListener = new StreamListener(this);
aStream->AddListener(mListener);
mListener = new PlaybackStreamListener(this);
mPlaybackStream->AddListener(mListener);
}
already_AddRefed<DOMMediaStream>
@ -354,16 +463,16 @@ DOMMediaStream::CreateAudioCaptureStream(nsIDOMWindow* aWindow,
void
DOMMediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled)
{
if (mStream) {
mStream->SetTrackEnabled(aTrackID, aEnabled);
if (mOwnedStream) {
mOwnedStream->SetTrackEnabled(aTrackID, aEnabled);
}
}
void
DOMMediaStream::StopTrack(TrackID aTrackID)
{
if (mStream && mStream->AsSourceStream()) {
mStream->AsSourceStream()->EndTrack(aTrackID);
if (mInputStream && mInputStream->AsSourceStream()) {
mInputStream->AsSourceStream()->EndTrack(aTrackID);
}
}
@ -429,8 +538,10 @@ DOMMediaStream::RemovePrincipalChangeObserver(PrincipalChangeObserver* aObserver
}
MediaStreamTrack*
DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
DOMMediaStream::CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
{
MOZ_ASSERT(FindOwnedDOMTrack(GetOwnedStream(), aTrackID) == nullptr);
MediaStreamTrack* track;
switch (aType) {
case MediaSegment::AUDIO:
@ -442,52 +553,51 @@ DOMMediaStream::CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
default:
MOZ_CRASH("Unhandled track type");
}
mTracks.AppendElement(track);
nsRefPtr<TrackPort> ownedTrackPort =
new TrackPort(mOwnedPort, track, TrackPort::InputPortOwnership::EXTERNAL);
mOwnedTracks.AppendElement(ownedTrackPort.forget());
nsRefPtr<TrackPort> playbackTrackPort =
new TrackPort(mPlaybackPort, track, TrackPort::InputPortOwnership::EXTERNAL);
mTracks.AppendElement(playbackTrackPort.forget());
NotifyMediaStreamTrackCreated(track);
return track;
}
MediaStreamTrack*
DOMMediaStream::BindDOMTrack(TrackID aTrackID, MediaSegment::Type aType)
DOMMediaStream::FindOwnedDOMTrack(MediaStream* aOwningStream, TrackID aTrackID) const
{
MediaStreamTrack* track = nullptr;
bool bindSuccess = false;
switch (aType) {
case MediaSegment::AUDIO: {
for (size_t i = 0; i < mTracks.Length(); ++i) {
track = mTracks[i]->AsAudioStreamTrack();
if (track && track->GetTrackID() == aTrackID) {
bindSuccess = true;
break;
}
if (aOwningStream != mOwnedStream) {
return nullptr;
}
for (const nsRefPtr<TrackPort>& info : mOwnedTracks) {
if (info->GetTrack()->GetTrackID() == aTrackID) {
return info->GetTrack();
}
break;
}
case MediaSegment::VIDEO: {
for (size_t i = 0; i < mTracks.Length(); ++i) {
track = mTracks[i]->AsVideoStreamTrack();
if (track && track->GetTrackID() == aTrackID) {
bindSuccess = true;
break;
}
}
break;
}
default:
MOZ_CRASH("Unhandled track type");
}
return bindSuccess ? track : nullptr;
return nullptr;
}
MediaStreamTrack*
DOMMediaStream::GetDOMTrackFor(TrackID aTrackID)
DOMMediaStream::FindPlaybackDOMTrack(MediaStream* aInputStream, TrackID aInputTrackID) const
{
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
MediaStreamTrack* t = mTracks[i];
// We may add streams to our track list that are actually owned by
// a different DOMMediaStream. Ignore those.
if (t->GetTrackID() == aTrackID && t->GetStream() == this) {
return t;
for (const nsRefPtr<TrackPort>& info : mTracks) {
if (info->GetInputPort() == mPlaybackPort &&
aInputStream == mOwnedStream &&
aInputTrackID == info->GetTrack()->GetTrackID()) {
// This track is in our owned and playback streams.
return info->GetTrack();
}
if (info->GetInputPort()->GetSource() == aInputStream &&
info->GetSourceTrackId() == aInputTrackID) {
// This track is owned externally but in our playback stream.
MOZ_ASSERT(aInputTrackID != TRACK_NONE);
MOZ_ASSERT(aInputTrackID != TRACK_INVALID);
MOZ_ASSERT(aInputTrackID != TRACK_ANY);
return info->GetTrack();
}
}
return nullptr;
@ -526,7 +636,6 @@ DOMMediaStream::OnTracksAvailable(OnTracksAvailableCallback* aRunnable)
void
DOMMediaStream::TracksCreated()
{
MOZ_ASSERT(!mTracks.IsEmpty());
mTracksCreated = true;
CheckTracksAvailable();
}
@ -545,6 +654,14 @@ DOMMediaStream::CheckTracksAvailable()
}
}
void
DOMMediaStream::CreateAndAddPlaybackStreamListener(MediaStream* aStream)
{
MOZ_ASSERT(GetCameraStream(), "I'm a hack. Only DOMCameraControl may use me.");
mListener = new PlaybackStreamListener(this);
aStream->AddListener(mListener);
}
already_AddRefed<AudioTrack>
DOMMediaStream::CreateAudioTrack(AudioStreamTrack* aStreamTrack)
{
@ -580,11 +697,11 @@ DOMMediaStream::ConstructMediaTracks(AudioTrackList* aAudioTrackList,
mMediaTrackListListeners.AppendElement(videoListener);
int firstEnabledVideo = -1;
for (uint32_t i = 0; i < mTracks.Length(); ++i) {
if (AudioStreamTrack* t = mTracks[i]->AsAudioStreamTrack()) {
for (const nsRefPtr<TrackPort>& info : mTracks) {
if (AudioStreamTrack* t = info->GetTrack()->AsAudioStreamTrack()) {
nsRefPtr<AudioTrack> track = CreateAudioTrack(t);
aAudioTrackList->AddTrack(track);
} else if (VideoStreamTrack* t = mTracks[i]->AsVideoStreamTrack()) {
} else if (VideoStreamTrack* t = info->GetTrack()->AsVideoStreamTrack()) {
nsRefPtr<VideoTrack> track = CreateVideoTrack(t);
aVideoTrackList->AddTrack(track);
firstEnabledVideo = (t->Enabled() && firstEnabledVideo < 0)
@ -645,7 +762,7 @@ DOMMediaStream::NotifyMediaStreamTrackEnded(MediaStreamTrack* aTrack)
DOMLocalMediaStream::~DOMLocalMediaStream()
{
if (mStream) {
if (mInputStream) {
// Make sure Listeners of this stream know it's going away
Stop();
}
@ -660,8 +777,8 @@ DOMLocalMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProt
void
DOMLocalMediaStream::Stop()
{
if (mStream && mStream->AsSourceStream()) {
mStream->AsSourceStream()->EndAllTrackAndFinish();
if (mInputStream && mInputStream->AsSourceStream()) {
mInputStream->AsSourceStream()->EndAllTrackAndFinish();
}
}
@ -736,7 +853,7 @@ DOMHwMediaStream::CreateHwStream(nsIDOMWindow* aWindow)
MediaStreamGraph::GetInstance(MediaStreamGraph::SYSTEM_THREAD_DRIVER,
AudioChannel::Normal);
stream->InitSourceStream(aWindow, graph);
stream->Init(stream->GetStream());
stream->Init(stream->GetInputStream());
return stream.forget();
}
@ -789,7 +906,7 @@ DOMHwMediaStream::SetImageSize(uint32_t width, uint32_t height)
mOverlayImage->SetData(imgData);
#endif
SourceMediaStream* srcStream = GetStream()->AsSourceStream();
SourceMediaStream* srcStream = GetInputStream()->AsSourceStream();
StreamBuffer::Track* track = srcStream->FindTrack(TRACK_VIDEO_PRIMARY);
if (!track || !track->GetSegment()) {

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

@ -35,7 +35,9 @@ class DOMHwMediaStream;
class DOMLocalMediaStream;
class MediaStream;
class MediaEngineSource;
class MediaInputPort;
class MediaStreamGraph;
class ProcessedMediaStream;
namespace dom {
class AudioNode;
@ -64,9 +66,114 @@ class MediaStreamDirectListener;
/**
* DOM wrapper for MediaStreams.
*
* To account for track operations such as clone(), addTrack() and
* removeTrack(), a DOMMediaStream wraps three internal (and chained)
* MediaStreams:
* 1. mInputStream
* - Controlled by the owner/source of the DOMMediaStream.
* It's a stream of the type indicated by
* - DOMMediaStream::CreateSourceStream/CreateTrackUnionStream. A source
* typically creates its DOMMediaStream, creates the MediaStreamTracks
* owned by said stream, then gets the internal input stream to which it
* feeds data for the previously created tracks.
* - When necessary it can create tracks on the internal stream only and
* their corresponding MediaStreamTracks will be asynchronously created.
* 2. mOwnedStream
* - A TrackUnionStream containing tracks owned by this stream.
* - The internal model of a MediaStreamTrack consists of its owning
* DOMMediaStream and the TrackID of the corresponding internal track in
* the owning DOMMediaStream's mOwnedStream.
* - The owned stream is different from the input stream since a cloned
* DOMMediaStream is also the owner of its (cloned) MediaStreamTracks.
* - Stopping an original track shall not stop its clone. This is
* solved by stopping it at the owned stream, while the clone's owned
* stream gets data directly from the original input stream.
* - A DOMMediaStream (original or clone) gets all tracks dynamically
* added by the source automatically forwarded by having a TRACK_ANY
* MediaInputPort set up from the owning DOMMediaStream's input stream
* to this DOMMediaStream's owned stream.
* 3. mPlaybackStream
* - A TrackUnionStream containing the tracks corresponding to the
* MediaStreamTracks currently in this DOMMediaStream (per getTracks()).
* - Similarly as for mOwnedStream, there's a TRACK_ANY MediaInputPort set
* up from the owned stream to the playback stream to allow tracks
* dynamically added by the source to be automatically forwarded to any
* audio or video sinks.
* - MediaStreamTracks added by addTrack() are set up with a MediaInputPort
* locked to their internal TrackID, from their owning DOMMediaStream's
* owned stream to this playback stream.
*
*
* A graphical representation of how tracks are connected in various cases as
* follows:
*
* addTrack()ed case:
* DOMStream A
* Input Owned Playback
* t1 ---------> t1 ------------> t1 <- MediaStreamTrack X
* (pointing to t1 in A)
* --------> t2 <- MediaStreamTrack Y
* / (pointing to t1 in B)
* DOMStream B /
* Input Owned / Playback
* t1 ---------> t1 ------------> t1 <- MediaStreamTrack Y
* (pointing to t1 in B)
*
* removeTrack()ed case:
* DOMStream A
* Input Owned Playback
* t1 ---------> t1 <- No tracks
*
*
* clone()d case:
* DOMStream A
* Input Owned Playback
* t1 ---------> t1 ------------> t1 <- MediaStreamTrack X
* \ (pointing to t1 in A)
* -----
* DOMStream B \
* Input \ Owned Playback
* -> t1 ------------> t1 <- MediaStreamTrack Y
* (pointing to t1 in B)
*
*
* addTrack()ed, removeTrack()ed and clone()d case:
*
* Here we have done the following:
* var A = someStreamWithTwoTracks;
* var B = someStreamWithOneTrack;
* var X = A.getTracks()[0];
* var Y = A.getTracks()[1];
* var Z = B.getTracks()[0];
* A.addTrack(Z);
* A.removeTrack(X);
* B.removeTrack(Z);
* var A' = A.clone();
*
* DOMStream A
* Input Owned Playback
* t1 ---------> t1 <- MediaStreamTrack X (removed)
* (pointing to t1 in A)
* t2 ---------> t2 ------------> t2 <- MediaStreamTrack Y
* \ (pointing to t2 in A)
* \ ------> t3 <- MediaStreamTrack Z
* \ / (pointing to t1 in B)
* DOMStream B \ /
* Input \ Owned / Playback
* t1 ---^-----> t1 --- <- MediaStreamTrack Z (removed)
* \ \ (pointing to t1 in B)
* \ \
* DOMStream A' \ \
* Input \ \ Owned Playback
* \ -> t1 ------------> t1 <- MediaStreamTrack Y'
* \ (pointing to t1 in A')
* ----> t2 ------------> t2 <- MediaStreamTrack Z'
* (pointing to t2 in A')
*/
class DOMMediaStream : public DOMEventTargetHelper
{
class TrackPort;
friend class DOMLocalMediaStream;
typedef dom::MediaStreamTrack MediaStreamTrack;
typedef dom::AudioStreamTrack AudioStreamTrack;
@ -103,9 +210,38 @@ public:
void GetAudioTracks(nsTArray<nsRefPtr<AudioStreamTrack> >& aTracks);
void GetVideoTracks(nsTArray<nsRefPtr<VideoStreamTrack> >& aTracks);
void GetTracks(nsTArray<nsRefPtr<MediaStreamTrack> >& aTracks);
// NON-WebIDL
/**
* Returns true if this DOMMediaStream has aTrack in its mPlaybackStream.
*/
bool HasTrack(const MediaStreamTrack& aTrack) const;
MediaStream* GetStream() const { return mStream; }
/**
* Returns true if this DOMMediaStream owns aTrack.
*/
bool OwnsTrack(const MediaStreamTrack& aTrack) const;
/**
* Returns the corresponding MediaStreamTrack if it's in our mOwnedStream.
*/
MediaStreamTrack* FindOwnedDOMTrack(MediaStream* aOwningStream, TrackID aTrackID) const;
/**
* Returns the corresponding MediaStreamTrack if it's in our mPlaybackStream.
*/
MediaStreamTrack* FindPlaybackDOMTrack(MediaStream* aOwningStream, TrackID aTrackID) const;
MediaStream* GetInputStream() const { return mInputStream; }
ProcessedMediaStream* GetOwnedStream() const { return mOwnedStream; }
ProcessedMediaStream* GetPlaybackStream() const { return mPlaybackStream; }
/**
* Allows a video element to identify this stream as a camera stream, which
* needs special treatment.
*/
virtual MediaStream* GetCameraStream() const { return nullptr; }
/**
* Overridden in DOMLocalMediaStreams to allow getUserMedia to pass
@ -217,11 +353,13 @@ public:
mLogicalStreamStartTime = aTime;
}
// Notifications from StreamListener.
// BindDOMTrack should only be called when it's safe to run script.
MediaStreamTrack* BindDOMTrack(TrackID aTrackID, MediaSegment::Type aType);
MediaStreamTrack* CreateDOMTrack(TrackID aTrackID, MediaSegment::Type aType);
MediaStreamTrack* GetDOMTrackFor(TrackID aTrackID);
/**
* Called for each track in our owned stream to indicate to JS that we
* are carrying that track.
*
* Creates a MediaStreamTrack, adds it to mTracks and returns it.
*/
MediaStreamTrack* CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType);
class OnTracksAvailableCallback {
public:
@ -271,13 +409,10 @@ protected:
virtual ~DOMMediaStream();
void Destroy();
void InitSourceStream(nsIDOMWindow* aWindow,
MediaStreamGraph* aGraph);
void InitTrackUnionStream(nsIDOMWindow* aWindow,
MediaStreamGraph* aGraph);
void InitAudioCaptureStream(nsIDOMWindow* aWindow,
MediaStreamGraph* aGraph);
void InitStreamCommon(MediaStream* aStream);
void InitSourceStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph);
void InitTrackUnionStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph);
void InitAudioCaptureStream(nsIDOMWindow* aWindow, MediaStreamGraph* aGraph);
void InitStreamCommon(MediaStream* aStream, MediaStreamGraph* aGraph);
already_AddRefed<AudioTrack> CreateAudioTrack(AudioStreamTrack* aStreamTrack);
already_AddRefed<VideoTrack> CreateVideoTrack(VideoStreamTrack* aStreamTrack);
@ -287,8 +422,11 @@ protected:
void CheckTracksAvailable();
class StreamListener;
friend class StreamListener;
class PlaybackStreamListener;
friend class PlaybackStreamListener;
// XXX Bug 1124630. Remove with CameraPreviewMediaStream.
void CreateAndAddPlaybackStreamListener(MediaStream*);
// StreamTime at which the currentTime attribute would return 0.
StreamTime mLogicalStreamStartTime;
@ -296,16 +434,40 @@ protected:
// We need this to track our parent object.
nsCOMPtr<nsIDOMWindow> mWindow;
// MediaStream is owned by the graph, but we tell it when to die, and it won't
// die until we let it.
MediaStream* mStream;
// MediaStreams are owned by the graph, but we tell them when to die,
// and they won't die until we let them.
nsAutoTArray<nsRefPtr<MediaStreamTrack>,2> mTracks;
nsRefPtr<StreamListener> mListener;
// This stream contains tracks used as input by us. Cloning happens from this
// stream. Tracks may exist in these stream but not in |mOwnedStream| if they
// have been stopped.
MediaStream* mInputStream;
// This stream contains tracks owned by us (if we were created directly from
// source, or cloned from some other stream). Tracks map to |mOwnedTracks|.
ProcessedMediaStream* mOwnedStream;
// This stream contains tracks currently played by us, despite of owner.
// Tracks map to |mTracks|.
ProcessedMediaStream* mPlaybackStream;
// This port connects mInputStream to mOwnedStream. All tracks forwarded.
nsRefPtr<MediaInputPort> mOwnedPort;
// This port connects mOwnedStream to mPlaybackStream. All tracks not
// explicitly blocked due to removal are forwarded.
nsRefPtr<MediaInputPort> mPlaybackPort;
// MediaStreamTracks corresponding to tracks in our mOwnedStream.
nsAutoTArray<nsRefPtr<TrackPort>, 2> mOwnedTracks;
// MediaStreamTracks corresponding to tracks in our mPlaybackStream.
nsAutoTArray<nsRefPtr<TrackPort>, 2> mTracks;
nsRefPtr<PlaybackStreamListener> mListener;
nsTArray<nsAutoPtr<OnTracksAvailableCallback> > mRunOnTracksAvailable;
// Set to true after MediaStreamGraph has created tracks for mStream.
// Set to true after MediaStreamGraph has created tracks for mPlaybackStream.
bool mTracksCreated;
nsString mID;

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

@ -701,9 +701,9 @@ public:
// We could override NotifyMediaStreamTrackEnded(), and maybe should, but it's
// risky to do late in a release since that will affect all track ends, and not
// just StopTrack()s.
if (GetDOMTrackFor(aTrackID)) {
mListener->StopTrack(aTrackID,
!!GetDOMTrackFor(aTrackID)->AsAudioStreamTrack());
nsRefPtr<dom::MediaStreamTrack> ownedTrack = FindOwnedDOMTrack(mOwnedStream, aTrackID);
if (ownedTrack) {
mListener->StopTrack(aTrackID, !!ownedTrack->AsAudioStreamTrack());
} else {
LOG(("StopTrack(%d) on non-existent track", aTrackID));
}
@ -734,7 +734,7 @@ public:
return promise.forget();
}
nsRefPtr<dom::MediaStreamTrack> track = GetDOMTrackFor(aTrackID);
nsRefPtr<dom::MediaStreamTrack> track = FindOwnedDOMTrack(mOwnedStream, aTrackID);
if (!track) {
LOG(("ApplyConstraintsToTrack(%d) on non-existent track", aTrackID));
nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
@ -811,7 +811,7 @@ public:
// We need to find the input track ID for output ID aTrackID, so we let the TrackUnion
// forward the request to the source and translate the ID
GetStream()->AsProcessedStream()->ForwardTrackEnabled(aTrackID, aEnabled);
GetInputStream()->AsProcessedStream()->ForwardTrackEnabled(aTrackID, aEnabled);
}
virtual DOMLocalMediaStream* AsDOMLocalMediaStream() override
@ -927,7 +927,7 @@ public:
// Start currentTime from the point where this stream was successfully
// returned.
aStream->SetLogicalStreamStartTime(aStream->GetStream()->GetCurrentTime());
aStream->SetLogicalStreamStartTime(aStream->GetPlaybackStream()->GetCurrentTime());
// This is safe since we're on main-thread, and the windowlist can only
// be invalidated from the main-thread (see OnNavigation)
@ -1013,7 +1013,7 @@ public:
// not a problem here, we got explicit user content.
domStream->SetPrincipal(window->GetExtantDoc()->NodePrincipal());
msg->RegisterCaptureStreamForWindow(
mWindowID, domStream->GetStream()->AsProcessedStream());
mWindowID, domStream->GetInputStream()->AsProcessedStream());
window->SetAudioCapture(true);
} else {
// Normal case, connect the source stream to the track union stream to
@ -1022,8 +1022,8 @@ public:
nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener,
mAudioDevice, mVideoDevice,
msg);
trackunion->GetStream()->AsProcessedStream()->SetAutofinish(true);
nsRefPtr<MediaInputPort> port = trackunion->GetStream()->AsProcessedStream()->
trackunion->GetInputStream()->AsProcessedStream()->SetAutofinish(true);
nsRefPtr<MediaInputPort> port = trackunion->GetInputStream()->AsProcessedStream()->
AllocateInputPort(stream);
trackunion->mSourceStream = stream;
trackunion->mPort = port.forget();
@ -1031,8 +1031,8 @@ public:
// Make sure logger starts before capture
AsyncLatencyLogger::Get(true);
LogLatency(AsyncLatencyLogger::MediaStreamCreate,
reinterpret_cast<uint64_t>(stream.get()),
reinterpret_cast<int64_t>(trackunion->GetStream()));
reinterpret_cast<uint64_t>(stream.get()),
reinterpret_cast<int64_t>(trackunion->GetInputStream()));
nsCOMPtr<nsIPrincipal> principal;
if (mPeerIdentity) {

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

@ -1173,7 +1173,7 @@ MediaStream*
MediaRecorder::GetSourceMediaStream()
{
if (mDOMStream != nullptr) {
return mDOMStream->GetStream();
return mDOMStream->GetPlaybackStream();
}
MOZ_ASSERT(mAudioNode != nullptr);
return mPipeStream ? mPipeStream.get() : mAudioNode->GetStream();

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

@ -1601,7 +1601,7 @@ MediaStream::MediaStream(DOMMediaStream* aWrapper)
// aWrapper should not already be connected to a MediaStream! It needs
// to be hooked up to this stream, and since this stream is only just
// being created now, aWrapper must not be connected to anything.
NS_ASSERTION(!aWrapper || !aWrapper->GetStream(),
NS_ASSERTION(!aWrapper || !aWrapper->GetPlaybackStream(),
"Wrapper already has another media stream hooked up to it!");
}

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

@ -427,7 +427,6 @@ public:
virtual SourceMediaStream* AsSourceStream() { return nullptr; }
virtual ProcessedMediaStream* AsProcessedStream() { return nullptr; }
virtual AudioNodeStream* AsAudioNodeStream() { return nullptr; }
virtual CameraPreviewMediaStream* AsCameraPreviewStream() { return nullptr; }
// These Impl methods perform the core functionality of the control methods
// above, on the media graph thread.

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

@ -13,7 +13,7 @@ namespace mozilla {
namespace dom {
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID)
: mStream(aStream), mTrackID(aTrackID), mEnded(false), mEnabled(true)
: mOwningStream(aStream), mTrackID(aTrackID), mEnded(false), mEnabled(true)
{
nsresult rv;
@ -36,7 +36,7 @@ MediaStreamTrack::~MediaStreamTrack()
}
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaStreamTrack, DOMEventTargetHelper,
mStream)
mOwningStream)
NS_IMPL_ADDREF_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
@ -53,20 +53,20 @@ void
MediaStreamTrack::SetEnabled(bool aEnabled)
{
mEnabled = aEnabled;
mStream->SetTrackEnabled(mTrackID, aEnabled);
mOwningStream->SetTrackEnabled(mTrackID, aEnabled);
}
void
MediaStreamTrack::Stop()
{
mStream->StopTrack(mTrackID);
mOwningStream->StopTrack(mTrackID);
}
already_AddRefed<Promise>
MediaStreamTrack::ApplyConstraints(const MediaTrackConstraints& aConstraints,
ErrorResult &aRv)
{
return mStream->ApplyConstraintsToTrack(mTrackID, aConstraints, aRv);
return GetStream()->ApplyConstraintsToTrack(mTrackID, aConstraints, aRv);
}
} // namespace dom

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

@ -35,10 +35,18 @@ public:
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrack,
DOMEventTargetHelper)
DOMMediaStream* GetParentObject() const { return mStream; }
DOMMediaStream* GetParentObject() const { return mOwningStream; }
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override = 0;
DOMMediaStream* GetStream() const { return mStream; }
/**
* Returns the DOMMediaStream owning this track.
*/
DOMMediaStream* GetStream() const { return mOwningStream; }
/**
* Returns the TrackID this stream has in its owning DOMMediaStream's Owned
* stream.
*/
TrackID GetTrackID() const { return mTrackID; }
virtual AudioStreamTrack* AsAudioStreamTrack() { return nullptr; }
virtual VideoStreamTrack* AsVideoStreamTrack() { return nullptr; }
@ -63,7 +71,7 @@ public:
protected:
virtual ~MediaStreamTrack();
nsRefPtr<DOMMediaStream> mStream;
nsRefPtr<DOMMediaStream> mOwningStream;
TrackID mTrackID;
nsString mID;
bool mEnded;

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

@ -57,7 +57,7 @@ CaptureTask::AttachStream()
nsRefPtr<DOMMediaStream> domStream = track->GetStream();
domStream->AddPrincipalChangeObserver(this);
nsRefPtr<MediaStream> stream = domStream->GetStream();
nsRefPtr<MediaStream> stream = domStream->GetPlaybackStream();
stream->AddListener(this);
}
@ -71,7 +71,7 @@ CaptureTask::DetachStream()
nsRefPtr<DOMMediaStream> domStream = track->GetStream();
domStream->RemovePrincipalChangeObserver(this);
nsRefPtr<MediaStream> stream = domStream->GetStream();
nsRefPtr<MediaStream> stream = domStream->GetPlaybackStream();
stream->RemoveListener(this);
}

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

@ -34,9 +34,9 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a
aContext->Graph()))
{
// Ensure an audio track with the correct ID is exposed to JS
mDOMStream->CreateDOMTrack(AudioNodeStream::AUDIO_TRACK, MediaSegment::AUDIO);
mDOMStream->CreateOwnDOMTrack(AudioNodeStream::AUDIO_TRACK, MediaSegment::AUDIO);
ProcessedMediaStream* outputStream = mDOMStream->GetStream()->AsProcessedStream();
ProcessedMediaStream* outputStream = mDOMStream->GetInputStream()->AsProcessedStream();
MOZ_ASSERT(!!outputStream);
AudioNodeEngine* engine = new AudioNodeEngine(this);
mStream = AudioNodeStream::Create(aContext, engine,

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

@ -42,7 +42,7 @@ MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext,
AudioNodeEngine* engine = new MediaStreamAudioSourceNodeEngine(this);
mStream = AudioNodeExternalInputStream::Create(aContext->Graph(), engine);
ProcessedMediaStream* outputStream = static_cast<ProcessedMediaStream*>(mStream.get());
mInputPort = outputStream->AllocateInputPort(aMediaStream->GetStream());
mInputPort = outputStream->AllocateInputPort(aMediaStream->GetPlaybackStream());
mInputStream->AddConsumerToKeepAlive(static_cast<nsIDOMEventTarget*>(this));
PrincipalChanged(mInputStream); // trigger enabling/disabling of the connector

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

@ -559,11 +559,11 @@ SpeechRecognition::StartRecording(DOMMediaStream* aDOMStream)
// doesn't get Destroy()'ed
mDOMStream = aDOMStream;
if (NS_WARN_IF(!mDOMStream->GetStream())) {
if (NS_WARN_IF(!mDOMStream->GetPlaybackStream())) {
return NS_ERROR_UNEXPECTED;
}
mSpeechListener = new SpeechStreamListener(this);
mDOMStream->GetStream()->AddListener(mSpeechListener);
mDOMStream->GetPlaybackStream()->AddListener(mSpeechListener);
mEndpointer.StartSession();
@ -577,7 +577,7 @@ SpeechRecognition::StopRecording()
// we only really need to remove the listener explicitly when testing,
// as our JS code still holds a reference to mDOMStream and only assigning
// it to nullptr isn't guaranteed to free the stream and the listener.
mDOMStream->GetStream()->RemoveListener(mSpeechListener);
mDOMStream->GetPlaybackStream()->RemoveListener(mSpeechListener);
mSpeechListener = nullptr;
mDOMStream = nullptr;

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

@ -683,7 +683,7 @@ nsresult MediaPipelineTransmit::ReplaceTrack(DOMMediaStream *domstream,
const std::string& track_id) {
// MainThread, checked in calls we make
MOZ_MTLOG(ML_DEBUG, "Reattaching pipeline " << description_ << " to stream "
<< static_cast<void *>(domstream->GetStream())
<< static_cast<void *>(domstream->GetOwnedStream())
<< " track " << track_id << " conduit type=" <<
(conduit_->type() == MediaSessionConduit::AUDIO ?"audio":"video"));
@ -691,7 +691,7 @@ nsresult MediaPipelineTransmit::ReplaceTrack(DOMMediaStream *domstream,
DetachMediaStream();
}
domstream_ = domstream; // Detach clears it
stream_ = domstream->GetStream();
stream_ = domstream->GetOwnedStream();
// Unsets the track id after RemoveListener() takes effect.
listener_->UnsetTrackId(stream_->GraphImpl());
track_id_ = track_id;

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

@ -388,7 +388,7 @@ public:
RefPtr<TransportFlow> rtcp_transport,
nsAutoPtr<MediaPipelineFilter> filter) :
MediaPipeline(pc, TRANSMIT, main_thread, sts_thread,
domstream->GetStream(), track_id, level,
domstream->GetOwnedStream(), track_id, level,
conduit, rtp_transport, rtcp_transport, filter),
listener_(new PipelineListener(conduit)),
domstream_(domstream),

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

@ -461,7 +461,7 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
mPC->GetHandle(),
mPC->GetMainThread().get(),
mPC->GetSTSThread(),
stream->GetMediaStream()->GetStream(),
stream->GetMediaStream()->GetInputStream(),
aTrack.GetTrackId(),
numericTrackId,
aLevel,
@ -475,7 +475,7 @@ MediaPipelineFactory::CreateMediaPipelineReceiving(
mPC->GetHandle(),
mPC->GetMainThread().get(),
mPC->GetSTSThread(),
stream->GetMediaStream()->GetStream(),
stream->GetMediaStream()->GetInputStream(),
aTrack.GetTrackId(),
numericTrackId,
aLevel,

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

@ -242,7 +242,7 @@ public:
// Start currentTime from the point where this stream was successfully
// returned.
aStream->SetLogicalStreamStartTime(
aStream->GetStream()->GetCurrentTime());
aStream->GetPlaybackStream()->GetCurrentTime());
JSErrorResult rv;
CSFLogInfo(logTag, "Calling OnAddStream(%s)", streamId.c_str());
@ -471,7 +471,7 @@ PeerConnectionImpl::MakeMediaStream()
}
#endif
CSFLogDebug(logTag, "Created media stream %p, inner: %p", stream.get(), stream->GetStream());
CSFLogDebug(logTag, "Created media stream %p, inner: %p", stream.get(), stream->GetInputStream());
return stream.forget();
}

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

@ -1304,7 +1304,7 @@ RemoteSourceStreamInfo::StartReceiving()
mReceiving = true;
SourceMediaStream* source = GetMediaStream()->GetStream()->AsSourceStream();
SourceMediaStream* source = GetMediaStream()->GetInputStream()->AsSourceStream();
source->FinishAddTracks();
source->SetPullEnabled(true);
// AdvanceKnownTracksTicksTime(HEAT_DEATH_OF_UNIVERSE) means that in

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

@ -366,6 +366,9 @@ public:
virtual bool AddDirectListener(Fake_MediaStreamListener *aListener) { return false; }
virtual void RemoveDirectListener(Fake_MediaStreamListener *aListener) {}
Fake_MediaStream *GetInputStream() { return mMediaStream; }
Fake_MediaStream *GetOwnedStream() { return mMediaStream; }
Fake_MediaStream *GetPlaybackStream() { return mMediaStream; }
Fake_MediaStream *GetStream() { return mMediaStream; }
std::string GetId() const { return mID; }
void AssignId(const std::string& id) { mID = id; }
@ -411,6 +414,22 @@ public:
void SetTrackEnabled(mozilla::TrackID aTrackID, bool aEnabled) {}
Fake_MediaStreamTrack*
CreateOwnDOMTrack(mozilla::TrackID aTrackID, mozilla::MediaSegment::Type aType)
{
switch(aType) {
case mozilla::MediaSegment::AUDIO: {
return mAudioTrack;
}
case mozilla::MediaSegment::VIDEO: {
return mVideoTrack;
}
default: {
MOZ_CRASH("Unkown media type");
}
}
}
class PrincipalChangeObserver
{
public: