author | Randell Jesup <rjesup@jesup.org> |
Wed, 24 Oct 2012 19:21:32 -0400 | |
changeset 111313 | 0b3cc07a299a0e6a30dc6d6f38acdb1839361e84 |
parent 111312 | d6a3f003d316a4ee20c0010fdb67e3bc089618c3 |
child 111314 | 593c26e36849b7eac66cf3c96166d68f629350b5 |
push id | 23740 |
push user | ryanvm@gmail.com |
push date | Thu, 25 Oct 2012 12:13:42 +0000 |
treeherder | mozilla-central@5374fb480634 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | roc, anant |
bugs | 803976 |
milestone | 19.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -2002,21 +2002,24 @@ SourceMediaStream::AddTrack(TrackID aID, GraphImpl()->EnsureNextIteration(); } } void SourceMediaStream::AppendToTrack(TrackID aID, MediaSegment* aSegment) { MutexAutoLock lock(mMutex); - TrackData *track = FindDataForTrack(aID); - if (track) { - track->mData->AppendFrom(aSegment); - } else { - NS_ERROR("Append to non-existent track!"); + // ::EndAllTrackAndFinished() can end these before the sources notice + if (!mFinished) { + TrackData *track = FindDataForTrack(aID); + if (track) { + track->mData->AppendFrom(aSegment); + } else { + NS_ERROR("Append to non-existent track!"); + } } if (!mDestroyed) { GraphImpl()->EnsureNextIteration(); } } bool SourceMediaStream::HaveEnoughBuffered(TrackID aID) @@ -2047,21 +2050,24 @@ SourceMediaStream::DispatchWhenNotEnough aSignalThread->Dispatch(aSignalRunnable, 0); } } void SourceMediaStream::EndTrack(TrackID aID) { MutexAutoLock lock(mMutex); - TrackData *track = FindDataForTrack(aID); - if (track) { - track->mCommands |= TRACK_END; - } else { - NS_ERROR("End of non-existant track"); + // ::EndAllTrackAndFinished() can end these before the sources call this + if (!mFinished) { + TrackData *track = FindDataForTrack(aID); + if (track) { + track->mCommands |= TRACK_END; + } else { + NS_ERROR("End of non-existant track"); + } } if (!mDestroyed) { GraphImpl()->EnsureNextIteration(); } } void SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime) @@ -2069,26 +2075,39 @@ SourceMediaStream::AdvanceKnownTracksTim MutexAutoLock lock(mMutex); mUpdateKnownTracksTime = aKnownTime; if (!mDestroyed) { GraphImpl()->EnsureNextIteration(); } } void -SourceMediaStream::Finish() +SourceMediaStream::FinishWithLockHeld() { - MutexAutoLock lock(mMutex); mUpdateFinished = true; if (!mDestroyed) { GraphImpl()->EnsureNextIteration(); } } void +SourceMediaStream::EndAllTrackAndFinish() +{ + { + MutexAutoLock lock(mMutex); + for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) { + SourceMediaStream::TrackData* data = &mUpdateTracks[i]; + data->mCommands |= TRACK_END; + } + } + FinishWithLockHeld(); + // we will call NotifyFinished() to let GetUserMedia know +} + +void MediaInputPort::Init() { LOG(PR_LOG_DEBUG, ("Adding MediaInputPort %p (from %p to %p) to the graph", this, mSource, mDest)); mSource->AddConsumer(this); mDest->AddInput(this); // mPortCount decremented via MediaInputPort::Destroy's message ++mDest->GraphImpl()->mPortCount;
--- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -548,17 +548,29 @@ public: */ void AdvanceKnownTracksTime(StreamTime aKnownTime); /** * Indicate that this stream should enter the "finished" state. All tracks * must have been ended via EndTrack. The finish time of the stream is * when all tracks have ended and when latest time sent to * AdvanceKnownTracksTime() has been reached. */ - void Finish(); + void FinishWithLockHeld(); + void Finish() + { + MutexAutoLock lock(mMutex); + FinishWithLockHeld(); + } + + + /** + * End all tracks and Finish() this stream. Used to voluntarily revoke access + * to a LocalMediaStream. + */ + void EndAllTrackAndFinish(); // XXX need a Reset API friend class MediaStreamGraphImpl; struct ThreadAndRunnable { void Init(nsIThread* aThread, nsIRunnable* aRunnable) {
--- a/content/media/nsDOMMediaStream.cpp +++ b/content/media/nsDOMMediaStream.cpp @@ -23,46 +23,97 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMe NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMMediaStream) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMMediaStream) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMMediaStream) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END +// LocalMediaStream currently is the same C++ class as MediaStream; +// they may eventually split +DOMCI_DATA(LocalMediaStream, nsDOMLocalMediaStream) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMLocalMediaStream) + NS_INTERFACE_MAP_ENTRY(nsIDOMLocalMediaStream) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIDOMMediaStream, nsDOMMediaStream) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMLocalMediaStream) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(LocalMediaStream) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMLocalMediaStream) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMLocalMediaStream) + +NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMLocalMediaStream) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMLocalMediaStream) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMLocalMediaStream) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + + nsDOMMediaStream::~nsDOMMediaStream() { if (mStream) { mStream->Destroy(); } } NS_IMETHODIMP nsDOMMediaStream::GetCurrentTime(double *aCurrentTime) { *aCurrentTime = mStream ? MediaTimeToSeconds(mStream->GetCurrentTime()) : 0.0; return NS_OK; } +NS_IMETHODIMP +nsDOMLocalMediaStream::Stop() +{ + if (mStream && mStream->AsSourceStream()) { + mStream->AsSourceStream()->EndAllTrackAndFinish(); + } + return NS_OK; +} + already_AddRefed<nsDOMMediaStream> nsDOMMediaStream::CreateInputStream(uint32_t aHintContents) { nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream(); stream->SetHintContents(aHintContents); MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); stream->mStream = gm->CreateInputStream(stream); return stream.forget(); } +already_AddRefed<nsDOMLocalMediaStream> +nsDOMLocalMediaStream::CreateInputStream(uint32_t aHintContents) +{ + nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream(); + stream->SetHintContents(aHintContents); + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + stream->mStream = gm->CreateInputStream(stream); + return stream.forget(); +} + already_AddRefed<nsDOMMediaStream> nsDOMMediaStream::CreateTrackUnionStream() { nsRefPtr<nsDOMMediaStream> stream = new nsDOMMediaStream(); MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); stream->mStream = gm->CreateTrackUnionStream(stream); return stream.forget(); } +already_AddRefed<nsDOMLocalMediaStream> +nsDOMLocalMediaStream::CreateTrackUnionStream() +{ + nsRefPtr<nsDOMLocalMediaStream> stream = new nsDOMLocalMediaStream(); + MediaStreamGraph* gm = MediaStreamGraph::GetInstance(); + stream->mStream = gm->CreateTrackUnionStream(stream); + return stream.forget(); +} + bool nsDOMMediaStream::CombineWithPrincipal(nsIPrincipal* aPrincipal) { return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal); }
--- a/content/media/nsDOMMediaStream.h +++ b/content/media/nsDOMMediaStream.h @@ -6,28 +6,31 @@ #ifndef NSDOMMEDIASTREAM_H_ #define NSDOMMEDIASTREAM_H_ #include "nsIDOMMediaStream.h" #include "MediaStreamGraph.h" #include "nsCycleCollectionParticipant.h" #include "nsIPrincipal.h" +class nsXPCClassInfo; + // GetCurrentTime is defined in winbase.h as zero argument macro forwarding to // GetTickCount() and conflicts with NS_DECL_NSIDOMMEDIASTREAM, containing // currentTime getter. #ifdef GetCurrentTime #undef GetCurrentTime #endif /** * DOM wrapper for MediaStreams. */ class nsDOMMediaStream : public nsIDOMMediaStream { + friend class nsDOMLocalMediaStream; typedef mozilla::MediaStream MediaStream; public: nsDOMMediaStream() : mStream(nullptr), mHintContents(0) {} virtual ~nsDOMMediaStream(); NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMMediaStream) NS_DECL_CYCLE_COLLECTING_ISUPPORTS @@ -77,9 +80,33 @@ protected: // If null, this stream can be used by anyone because it has no content yet. nsCOMPtr<nsIPrincipal> mPrincipal; // tells the SDP generator about whether this // MediaStream probably has audio and/or video uint32_t mHintContents; }; +class nsDOMLocalMediaStream : public nsDOMMediaStream, + public nsIDOMLocalMediaStream +{ +public: + nsDOMLocalMediaStream() {} + virtual ~nsDOMLocalMediaStream() {} + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsDOMLocalMediaStream, nsDOMMediaStream) + NS_DECL_NSIDOMLOCALMEDIASTREAM + + NS_FORWARD_NSIDOMMEDIASTREAM(nsDOMMediaStream::) + + /** + * Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream. + */ + static already_AddRefed<nsDOMLocalMediaStream> CreateInputStream(uint32_t aHintContents); + + /** + * Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream. + */ + static already_AddRefed<nsDOMLocalMediaStream> CreateTrackUnionStream(); +}; + #endif /* NSDOMMEDIASTREAM_H_ */
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1513,16 +1513,18 @@ static nsDOMClassInfoData sClassInfoData NS_DEFINE_CLASSINFO_DATA(MediaError, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(HTMLAudioElement, nsElementSH, ELEMENT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(TimeRanges, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MediaStream, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(LocalMediaStream, nsDOMGenericSH, + DOM_DEFAULT_SCRIPTABLE_FLAGS) #endif NS_DEFINE_CLASSINFO_DATA(XMLHttpRequestUpload, nsEventTargetSH, EVENTTARGET_SCRIPTABLE_FLAGS) // DOM Traversal NodeIterator class NS_DEFINE_CLASSINFO_DATA(NodeIterator, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -4123,16 +4125,20 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_MAP_BEGIN(TimeRanges, nsIDOMTimeRanges) DOM_CLASSINFO_MAP_ENTRY(nsIDOMTimeRanges) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(MediaStream, nsIDOMMediaStream) DOM_CLASSINFO_MAP_ENTRY(nsIDOMMediaStream) DOM_CLASSINFO_MAP_END + + DOM_CLASSINFO_MAP_BEGIN(LocalMediaStream, nsIDOMLocalMediaStream) + DOM_CLASSINFO_MAP_ENTRY(nsIDOMLocalMediaStream) + DOM_CLASSINFO_MAP_END #endif DOM_CLASSINFO_MAP_BEGIN(XMLHttpRequestUpload, nsIXMLHttpRequestUpload) DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequestEventTarget) DOM_CLASSINFO_MAP_ENTRY(nsIXMLHttpRequestUpload) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -421,16 +421,17 @@ DOMCI_CLASS(CSSFontFaceStyleDecl) DOMCI_CLASS(HTMLVideoElement) DOMCI_CLASS(HTMLSourceElement) DOMCI_CLASS(MediaError) DOMCI_CLASS(HTMLAudioElement) DOMCI_CLASS(TimeRanges) // Media streams DOMCI_CLASS(MediaStream) +DOMCI_CLASS(LocalMediaStream) #endif DOMCI_CLASS(XMLHttpRequestUpload) // DOM Traversal NodeIterator class DOMCI_CLASS(NodeIterator) DOMCI_CLASS(DataTransfer)
--- a/dom/camera/DOMCameraPreview.cpp +++ b/dom/camera/DOMCameraPreview.cpp @@ -39,17 +39,17 @@ public: NS_ASSERTION(NS_IsMainThread(), "PreviewControl not run on main thread"); switch (mControl) { case START: mDOMPreview->Start(); break; case STOP: - mDOMPreview->Stop(); + mDOMPreview->StopPreview(); break; case STARTED: mDOMPreview->SetStateStarted(); break; case STOPPED: mDOMPreview->SetStateStopped(); @@ -233,19 +233,19 @@ DOMCameraPreview::Started() nsCOMPtr<nsIRunnable> started = new PreviewControl(this, PreviewControl::STARTED); nsresult rv = NS_DispatchToMainThread(started); if (NS_FAILED(rv)) { DOM_CAMERA_LOGE("failed to set statrted state (%d), POTENTIAL MEMORY LEAK!\n", rv); } } void -DOMCameraPreview::Stop() +DOMCameraPreview::StopPreview() { - NS_ASSERTION(NS_IsMainThread(), "Stop() not called from main thread"); + NS_ASSERTION(NS_IsMainThread(), "StopPreview() not called from main thread"); if (mState != STARTED) { return; } DOM_CAMERA_LOGI("Stopping preview stream\n"); mState = STOPPING; mCameraControl->StopPreview(); mInput->EndTrack(TRACK_VIDEO);
--- a/dom/camera/DOMCameraPreview.h +++ b/dom/camera/DOMCameraPreview.h @@ -35,17 +35,17 @@ public: NS_IMETHODIMP GetCurrentTime(double* aCurrentTime) { return nsDOMMediaStream::GetCurrentTime(aCurrentTime); } void Start(); // called by the MediaStreamListener to start preview void Started(); // called by the CameraControl when preview is started - void Stop(); // called by the MediaStreamListener to stop preview + void StopPreview(); // called by the MediaStreamListener to stop preview void Stopped(bool aForced = false); // called by the CameraControl when preview is stopped void Error(); // something went wrong, NS_RELEASE needed void SetStateStarted(); void SetStateStopped(); protected:
--- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -239,21 +239,21 @@ public: ~GetUserMediaStreamRunnable() {} NS_IMETHOD Run() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); // Create a media stream. - nsCOMPtr<nsDOMMediaStream> stream; + nsRefPtr<nsDOMLocalMediaStream> stream; uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0); hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0); - stream = nsDOMMediaStream::CreateInputStream(hints); + stream = nsDOMLocalMediaStream::CreateInputStream(hints); nsPIDOMWindow *window = static_cast<nsPIDOMWindow*> (nsGlobalWindow::GetInnerWindowWithId(mWindowID)); WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); { MutexAutoLock lock(MediaManager::Get()->GetMutex()); if (!stream) { @@ -294,17 +294,17 @@ public: // We're in the main thread, so no worries here either. nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess); nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError); { MutexAutoLock lock(MediaManager::Get()->GetMutex()); if (activeWindows->Get(mWindowID)) { LOG(("Returning success for getUserMedia()")); - success->OnSuccess(stream); + success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(stream)); } } return NS_OK; } private: already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
--- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -127,17 +127,17 @@ public: if (mVideoSource) { rv = mVideoSource->Start(mSourceStream, kVideoTrack); if (NS_FAILED(rv)) { MM_LOG(("Starting video failed, rv=%d",rv)); } } MM_LOG(("started all sources")); - nsCOMPtr<GetUserMediaNotificationEvent> event = + nsRefPtr<GetUserMediaNotificationEvent> event = new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } break; case MEDIA_STOP: { @@ -148,17 +148,17 @@ public: } if (mVideoSource) { mVideoSource->Stop(); mVideoSource->Deallocate(); } // Do this after stopping all tracks with EndTrack() mSourceStream->Finish(); - nsCOMPtr<GetUserMediaNotificationEvent> event = + nsRefPtr<GetUserMediaNotificationEvent> event = new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING); NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); } break; case MEDIA_RELEASE: // We go to MainThread to die break; @@ -170,17 +170,17 @@ public: } return NS_OK; } private: MediaOperation mType; nsRefPtr<MediaEngineSource> mAudioSource; nsRefPtr<MediaEngineSource> mVideoSource; - nsCOMPtr<nsDOMMediaStream> mStream; + nsRefPtr<nsDOMMediaStream> mStream; SourceMediaStream *mSourceStream; }; /** * This class is an implementation of MediaStreamListener. This is used * to Start() and Stop() the underlying MediaEngineSource when MediaStreams * are assigned and deassigned in content. */ @@ -223,21 +223,27 @@ public: if (mAudioSource) { mAudioSource->NotifyPull(aGraph, aDesiredTime); } if (mVideoSource) { mVideoSource->NotifyPull(aGraph, aDesiredTime); } } + void + NotifyFinished(MediaStreamGraph* aGraph) + { + Invalidate(); + } + private: nsCOMPtr<nsIThread> mMediaThread; nsRefPtr<MediaEngineSource> mAudioSource; nsRefPtr<MediaEngineSource> mVideoSource; - nsCOMPtr<nsDOMMediaStream> mStream; + nsRefPtr<nsDOMMediaStream> mStream; bool mValid; }; typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners; typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable; class MediaDevice : public nsIMediaDevice {
--- a/dom/media/nsIDOMMediaStream.idl +++ b/dom/media/nsIDOMMediaStream.idl @@ -5,8 +5,15 @@ #include "nsISupports.idl" [scriptable, builtinclass, uuid(f37c2871-4cb7-4672-bb28-c2d601f7cc9e)] interface nsIDOMMediaStream : nsISupports { readonly attribute double currentTime; }; + +[scriptable, builtinclass, uuid(210a16e3-2a38-4ae9-b0f6-0fb5a8252814)] +interface nsIDOMLocalMediaStream : nsIDOMMediaStream +{ + void stop(); +}; +
--- a/dom/media/nsIDOMNavigatorUserMedia.idl +++ b/dom/media/nsIDOMNavigatorUserMedia.idl @@ -19,17 +19,17 @@ interface nsIGetUserMediaDevicesSuccessC void onSuccess(in nsIVariant devices); }; [scriptable, function, uuid(f2a144fc-3534-4761-8c5d-989ae720f89a)] interface nsIDOMGetUserMediaSuccessCallback : nsISupports { /* * value must be a nsIDOMBlob if picture is true and a - * nsIDOMMediaStream if either audio or video are true. + * nsIDOMLocalMediaStream if either audio or video are true. */ void onSuccess(in nsISupports value); }; [scriptable, function, uuid(2614bbcf-85cc-43e5-8740-964f52bdc7ca)] interface nsIDOMGetUserMediaErrorCallback : nsISupports { void onError(in DOMString error);