diff --git a/content/media/webrtc/MediaEngineWebRTCAudio.cpp b/content/media/webrtc/MediaEngineWebRTCAudio.cpp index 720c85be02b..03a36cf598b 100644 --- a/content/media/webrtc/MediaEngineWebRTCAudio.cpp +++ b/content/media/webrtc/MediaEngineWebRTCAudio.cpp @@ -139,13 +139,6 @@ MediaEngineWebRTCAudioSource::NotifyPull(MediaStreamGraph* aGraph, StreamTime aDesiredTime) { // Ignore - we push audio data -#ifdef DEBUG - static TrackTicks mLastEndTime = 0; - TrackTicks target = TimeToTicksRoundUp(SAMPLE_FREQUENCY, aDesiredTime); - TrackTicks delta = target - mLastEndTime; - LOG(("Audio:NotifyPull: target %lu, delta %lu",(uint32_t) target, (uint32_t) delta)); - mLastEndTime = target; -#endif } nsresult diff --git a/content/media/webrtc/MediaEngineWebRTCVideo.cpp b/content/media/webrtc/MediaEngineWebRTCVideo.cpp index 4b39b1731c3..42b549e6d05 100644 --- a/content/media/webrtc/MediaEngineWebRTCVideo.cpp +++ b/content/media/webrtc/MediaEngineWebRTCVideo.cpp @@ -251,7 +251,6 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID) mSource->AddTrack(aID, USECS_PER_S, 0, new VideoSegment()); mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX); mLastEndTime = 0; - mState = kStarted; error = mViERender->AddRenderer(mCaptureIndex, webrtc::kVideoI420, (webrtc::ExternalRenderer*)this); if (error == -1) { @@ -267,6 +266,7 @@ MediaEngineWebRTCVideoSource::Start(SourceMediaStream* aStream, TrackID aID) return NS_ERROR_FAILURE; } + mState = kStarted; return NS_OK; } diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 21af6f724e3..ac1caf77274 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -62,12 +62,9 @@ public: nsCOMPtr success(mSuccess); nsCOMPtr error(mError); - { - MutexAutoLock lock(MediaManager::Get()->GetMutex()); - WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); - if (activeWindows->Get(mWindowID)) { - error->OnError(mErrorMsg); - } + WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); + if (activeWindows->Get(mWindowID)) { + error->OnError(mErrorMsg); } return NS_OK; } @@ -106,13 +103,10 @@ public: nsCOMPtr success(mSuccess); nsCOMPtr error(mError); - { - MutexAutoLock lock(MediaManager::Get()->GetMutex()); - WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); - if (activeWindows->Get(mWindowID)) { - // XPConnect is a magical unicorn. - success->OnSuccess(mFile); - } + WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); + if (activeWindows->Get(mWindowID)) { + // XPConnect is a magical unicorn. + success->OnSuccess(mFile); } return NS_OK; } @@ -215,7 +209,7 @@ MediaDevice::GetSource() * Note that the various GetUserMedia Runnable classes currently allow for * two streams. If we ever need to support getting more than two streams * at once, we could convert everything to nsTArray >'s, - * though that would complicate the constructors some. Currently the + * though that would complicate the constructors some. Currently the * GetUserMedia spec does not allow for more than 2 streams to be obtained in * one call, to simplify handling of constraints. */ @@ -253,54 +247,38 @@ public: nsPIDOMWindow *window = static_cast (nsGlobalWindow::GetInnerWindowWithId(mWindowID)); WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows(); - { - MutexAutoLock lock(MediaManager::Get()->GetMutex()); - if (!stream) { - if (activeWindows->Get(mWindowID)) { - nsCOMPtr error(mError); - LOG(("Returning error for getUserMedia() - no stream")); - error->OnError(NS_LITERAL_STRING("NO_STREAM")); - } - return NS_OK; + if (!stream) { + if (activeWindows->Get(mWindowID)) { + nsCOMPtr error(mError); + LOG(("Returning error for getUserMedia() - no stream")); + error->OnError(NS_LITERAL_STRING("NO_STREAM")); } + return NS_OK; } + if (window && window->GetExtantDoc()) { stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal()); } - // Ensure there's a thread for gum to proxy to off main thread - nsIThread *mediaThread = MediaManager::GetThread(); - // Add our listener. We'll call Start() on the source when get a callback // that the MediaStream has started consuming. The listener is freed // when the page is invalidated (on navigation or close). GetUserMediaCallbackMediaStreamListener* listener = - new GetUserMediaCallbackMediaStreamListener(mediaThread, stream, - mAudioSource, + new GetUserMediaCallbackMediaStreamListener(stream, mAudioSource, mVideoSource); stream->GetStream()->AddListener(listener); // No need for locking because we always do this in the main thread. mListeners->AppendElement(listener); - // Dispatch to the media thread to ask it to start the sources, - // because that can take a while - nsRefPtr runnable( - new MediaOperationRunnable(MEDIA_START, stream, - mAudioSource, mVideoSource)); - mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - // We're in the main thread, so no worries here either. nsCOMPtr success(mSuccess); nsCOMPtr error(mError); - { - MutexAutoLock lock(MediaManager::Get()->GetMutex()); - if (activeWindows->Get(mWindowID)) { - LOG(("Returning success for getUserMedia()")); - success->OnSuccess(stream); - } + if (activeWindows->Get(mWindowID)) { + LOG(("Returning success for getUserMedia()")); + success->OnSuccess(stream); } return NS_OK; @@ -334,7 +312,7 @@ public: GetUserMediaRunnable(bool aAudio, bool aVideo, bool aPicture, already_AddRefed aSuccess, already_AddRefed aError, - StreamListeners* aListeners, uint64_t aWindowID, + StreamListeners* aListeners, uint64_t aWindowID, MediaDevice* aAudioDevice, MediaDevice* aVideoDevice) : mAudio(aAudio) , mVideo(aVideo) @@ -348,7 +326,7 @@ public: { if (mAudio) { mAudioDevice = aAudioDevice; - } + } if (mVideo) { mVideoDevice = aVideoDevice; } @@ -781,52 +759,48 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow, // Store the WindowID in a hash table and mark as active. The entry is removed // when this window is closed or navigated away from. uint64_t windowID = aWindow->WindowID(); - nsRefPtr gUMRunnable; - { - MutexAutoLock lock(mMutex); - StreamListeners* listeners = mActiveWindows.Get(windowID); - if (!listeners) { - listeners = new StreamListeners; - mActiveWindows.Put(windowID, listeners); - } - - // Developer preference for turning off permission check. - if (Preferences::GetBool("media.navigator.permission.disabled", false)) { - aPrivileged = true; - } - - /** - * Pass runnables along to GetUserMediaRunnable so it can add the - * MediaStreamListener to the runnable list. The last argument can - * optionally be a MediaDevice object, which should provided if one was - * selected by the user via the UI, or was provided by privileged code - * via the device: attribute via nsIMediaStreamOptions. - * - * If a fake stream was requested, we force the use of the default backend. - */ - if (fake) { - // Fake stream from default backend. - gUMRunnable = new GetUserMediaRunnable( - audio, video, onSuccess.forget(), onError.forget(), listeners, - windowID, new MediaEngineDefault() - ); - } else if (audiodevice || videodevice) { - // Stream from provided device. - gUMRunnable = new GetUserMediaRunnable( - audio, video, picture, onSuccess.forget(), onError.forget(), listeners, - windowID, - static_cast(audiodevice.get()), - static_cast(videodevice.get()) - ); - } else { - // Stream from default device from WebRTC backend. - gUMRunnable = new GetUserMediaRunnable( - audio, video, picture, onSuccess.forget(), onError.forget(), listeners, - windowID - ); - } + StreamListeners* listeners = mActiveWindows.Get(windowID); + if (!listeners) { + listeners = new StreamListeners; + mActiveWindows.Put(windowID, listeners); } + // Developer preference for turning off permission check. + if (Preferences::GetBool("media.navigator.permission.disabled", false)) { + aPrivileged = true; + } + + /** + * Pass runnables along to GetUserMediaRunnable so it can add the + * MediaStreamListener to the runnable list. The last argument can + * optionally be a MediaDevice object, which should provided if one was + * selected by the user via the UI, or was provided by privileged code + * via the device: attribute via nsIMediaStreamOptions. + * + * If a fake stream was requested, we force the use of the default backend. + */ + nsRefPtr gUMRunnable; + if (fake) { + // Fake stream from default backend. + gUMRunnable = new GetUserMediaRunnable( + audio, video, onSuccess.forget(), onError.forget(), listeners, + windowID, new MediaEngineDefault() + ); + } else if (audiodevice || videodevice) { + // Stream from provided device. + gUMRunnable = new GetUserMediaRunnable( + audio, video, picture, onSuccess.forget(), onError.forget(), listeners, + windowID, + static_cast(audiodevice.get()), + static_cast(videodevice.get()) + ); + } else { + // Stream from default device from WebRTC backend. + gUMRunnable = new GetUserMediaRunnable( + audio, video, picture, onSuccess.forget(), onError.forget(), listeners, + windowID + ); + } #ifdef ANDROID if (picture) { @@ -837,7 +811,11 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow, #else // XXX No full support for picture in Desktop yet (needs proper UI) if (aPrivileged || fake) { - (void) MediaManager::GetThread(); + if (!mMediaThread) { + nsresult rv = NS_NewThread(getter_AddRefs(mMediaThread)); + NS_ENSURE_SUCCESS(rv, rv); + LOG(("New Media thread for gum")); + } mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL); } else { // Ask for user permission, and dispatch runnable (or not) when a response @@ -858,10 +836,7 @@ MediaManager::GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow, NS_ConvertUTF8toUTF16 callID(buffer); // Store the current callback. - { - MutexAutoLock lock(mMutex); - mActiveCallbacks.Put(callID, gUMRunnable); - } + mActiveCallbacks.Put(callID, gUMRunnable); // Construct JSON structure with both the windowID and the callID. nsAutoString data; @@ -937,24 +912,21 @@ MediaManager::OnNavigation(uint64_t aWindowID) { // Invalidate this window. The runnables check this value before making // a call to content. - { - MutexAutoLock lock(mMutex); - StreamListeners* listeners = mActiveWindows.Get(aWindowID); - if (!listeners) { - return; - } - - uint32_t length = listeners->Length(); - for (uint32_t i = 0; i < length; i++) { - nsRefPtr listener = - listeners->ElementAt(i); - listener->Invalidate(); - listener = nullptr; - } - listeners->Clear(); - - mActiveWindows.Remove(aWindowID); + StreamListeners* listeners = mActiveWindows.Get(aWindowID); + if (!listeners) { + return; } + + uint32_t length = listeners->Length(); + for (uint32_t i = 0; i < length; i++) { + nsRefPtr listener = + listeners->ElementAt(i); + listener->Invalidate(); + listener = nullptr; + } + listeners->Clear(); + + mActiveWindows.Remove(aWindowID); } nsresult @@ -970,12 +942,9 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, obs->RemoveObserver(this, "getUserMedia:response:deny"); // Close off any remaining active windows. - { - MutexAutoLock lock(mMutex); - mActiveWindows.Clear(); - mActiveCallbacks.Clear(); - sSingleton = nullptr; - } + mActiveWindows.Clear(); + mActiveCallbacks.Clear(); + sSingleton = nullptr; return NS_OK; } @@ -983,15 +952,18 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, if (!strcmp(aTopic, "getUserMedia:response:allow")) { nsString key(aData); nsRefPtr runnable; - { - MutexAutoLock lock(mMutex); - if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) { - return NS_OK; - } + if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) { + return NS_OK; } // Reuse the same thread to save memory. - (void) MediaManager::GetThread(); + if (!mMediaThread) { + LOG(("New Media thread for gum on allow")); + nsresult rv = NS_NewThread(getter_AddRefs(mMediaThread)); + NS_ENSURE_SUCCESS(rv, rv); + } else { + LOG(("Reused Media thread for gum on allow")); + } if (aSubject) { // A particular device was chosen by the user. @@ -1013,25 +985,20 @@ MediaManager::Observe(nsISupports* aSubject, const char* aTopic, } mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - { - MutexAutoLock lock(mMutex); - mActiveCallbacks.Remove(key); - } + mActiveCallbacks.Remove(key); return NS_OK; } if (!strcmp(aTopic, "getUserMedia:response:deny")) { nsString key(aData); nsRefPtr runnable; - { - MutexAutoLock lock(mMutex); - if (mActiveCallbacks.Get(key, getter_AddRefs(runnable))) { - GetUserMediaRunnable* gUMRunnable = + if (mActiveCallbacks.Get(key, getter_AddRefs(runnable))) { + GetUserMediaRunnable* gUMRunnable = static_cast(runnable.get()); - gUMRunnable->Denied(); - mActiveCallbacks.Remove(key); - } + gUMRunnable->Denied(); + mActiveCallbacks.Remove(key); } + return NS_OK; } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 4cde1eb276d..0c6d57b88e5 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -65,120 +65,6 @@ class GetUserMediaNotificationEvent: public nsRunnable GetUserMediaStatus mStatus; }; -typedef enum { - MEDIA_START, - MEDIA_STOP, - MEDIA_RELEASE -} MediaOperation; - -// Generic class for running long media operations off the main thread, and -// then (because nsDOMMediaStreams aren't threadsafe), re-sends itseld to -// MainThread to release mStream. This is part of the reason we use an -// operation type - we can change it to repost the runnable to MainThread -// to do operations with the nsDOMMediaStreams, while we can't assign or -// copy a nsRefPtr to a nsDOMMediaStream -class MediaOperationRunnable : public nsRunnable -{ -public: - MediaOperationRunnable(MediaOperation aType, - nsDOMMediaStream* aStream, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource) - : mType(aType) - , mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) - , mStream(aStream) - {} - - MediaOperationRunnable(MediaOperation aType, - SourceMediaStream* aStream, - MediaEngineSource* aAudioSource, - MediaEngineSource* aVideoSource) - : mType(aType) - , mAudioSource(aAudioSource) - , mVideoSource(aVideoSource) - , mStream(nullptr) - , mSourceStream(aStream) - {} - - NS_IMETHOD - Run() - { - // No locking between these is required as all the callbacks (other - // than MEDIA_RELEASE) for the same MediaStream will occur on the same - // thread. - if (mStream) { - mSourceStream = mStream->GetStream()->AsSourceStream(); - } - switch (mType) { - case MEDIA_START: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - nsresult rv; - - mSourceStream->SetPullEnabled(true); - - if (mAudioSource) { - rv = mAudioSource->Start(mSourceStream, kAudioTrack); - if (NS_FAILED(rv)) { - MM_LOG(("Starting audio failed, rv=%d",rv)); - } - } - 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 event = - new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING); - - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - } - break; - - case MEDIA_STOP: - { - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioSource) { - mAudioSource->Stop(); - mAudioSource->Deallocate(); - } - if (mVideoSource) { - mVideoSource->Stop(); - mVideoSource->Deallocate(); - } - // Do this after stopping all tracks with EndTrack() - mSourceStream->Finish(); - - nsCOMPtr event = - new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING); - - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - } - break; - case MEDIA_RELEASE: - // We go to MainThread to die - break; - } - if (mType != MEDIA_RELEASE) { - // nsDOMMediaStreams aren't thread-safe... sigh. - mType = MEDIA_RELEASE; - NS_DispatchToMainThread(this); - } - return NS_OK; - } - -private: - MediaOperation mType; - nsRefPtr mAudioSource; - nsRefPtr mVideoSource; - nsCOMPtr mStream; - SourceMediaStream *mSourceStream; -}; - /** * This class is an implementation of MediaStreamListener. This is used * to Start() and Stop() the underlying MediaEngineSource when MediaStreams @@ -187,12 +73,10 @@ private: class GetUserMediaCallbackMediaStreamListener : public MediaStreamListener { public: - GetUserMediaCallbackMediaStreamListener(nsIThread *aThread, - nsDOMMediaStream* aStream, + GetUserMediaCallbackMediaStreamListener(nsDOMMediaStream* aStream, MediaEngineSource* aAudioSource, MediaEngineSource* aVideoSource) - : mMediaThread(aThread) - , mAudioSource(aAudioSource) + : mAudioSource(aAudioSource) , mVideoSource(aVideoSource) , mStream(aStream) , mValid(true) {} @@ -200,17 +84,60 @@ public: void Invalidate() { - nsRefPtr runnable; + if (!mValid) { + return; + } - // We can't take a chance on blocking here, so proxy this to another - // thread. - // XXX FIX! I'm cheating and passing a raw pointer to the sourcestream - // which is valid as long as the mStream pointer here is. Need a better solution. - runnable = new MediaOperationRunnable(MEDIA_STOP, - mStream->GetStream()->AsSourceStream(), - mAudioSource, mVideoSource); - mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL); + mValid = false; + if (mAudioSource) { + mAudioSource->Stop(); + mAudioSource->Deallocate(); + } + if (mVideoSource) { + mVideoSource->Stop(); + mVideoSource->Deallocate(); + } + // Do this after stopping all tracks with EndTrack() + mStream->GetStream()->AsSourceStream()->Finish(); + nsCOMPtr event = + new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STOPPING); + + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + } + + void + NotifyConsumptionChanged(MediaStreamGraph* aGraph, Consumption aConsuming) + { + if (aConsuming == CONSUMED) { + nsresult rv; + + SourceMediaStream* stream = mStream->GetStream()->AsSourceStream(); + stream->SetPullEnabled(true); + + if (mAudioSource) { + rv = mAudioSource->Start(stream, kAudioTrack); + if (NS_FAILED(rv)) { + MM_LOG(("Starting audio failed, rv=%d",rv)); + } + } + if (mVideoSource) { + rv = mVideoSource->Start(stream, kVideoTrack); + if (NS_FAILED(rv)) { + MM_LOG(("Starting video failed, rv=%d",rv)); + } + } + + MM_LOG(("started all sources")); + nsCOMPtr event = + new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING); + + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + return; + } + + // NOT_CONSUMED + Invalidate(); return; } @@ -229,7 +156,6 @@ public: } private: - nsCOMPtr mMediaThread; nsRefPtr mAudioSource; nsRefPtr mVideoSource; nsCOMPtr mStream; @@ -278,17 +204,6 @@ public: } return sSingleton; } - static Mutex& GetMutex() { - return Get()->mMutex; - } - static nsIThread* GetThread() { - MutexAutoLock lock(Get()->mMutex); // only need to call Get() once - if (!sSingleton->mMediaThread) { - NS_NewThread(getter_AddRefs(sSingleton->mMediaThread)); - MM_LOG(("New Media thread for gum")); - } - return sSingleton->mMediaThread; - } NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER @@ -308,19 +223,17 @@ public: private: // Make private because we want only one instance of this class MediaManager() - : mMutex("mozilla::MediaManager") - , mBackend(nullptr) + : mBackend(nullptr) , mMediaThread(nullptr) { mActiveWindows.Init(); mActiveCallbacks.Init(); }; + MediaManager(MediaManager const&) {}; ~MediaManager() { delete mBackend; }; - Mutex mMutex; - // protected with mMutex: MediaEngine* mBackend; nsCOMPtr mMediaThread; WindowTable mActiveWindows;