зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
53a6c38d0d
Коммит
937747498a
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче