From 4fbccc5b502515cc901b2aacaec4eac993a9e342 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Sun, 20 Sep 2015 10:04:51 -0400 Subject: [PATCH] Bug 912342 - get Promise out. r=jesup --HG-- extra : commitid : L54TpPNzEgB extra : rebase_source : 29eceb81efe9ab96053b37a202714319be13fc80 --- dom/media/MediaManager.cpp | 192 ++++++++++++------ dom/media/MediaManager.h | 12 +- .../test_getUserMedia_constraints.html | 7 +- .../webrtc/MediaEngineRemoteVideoSource.cpp | 23 ++- 4 files changed, 157 insertions(+), 77 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index d7af03430787..a87a507d4d2e 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -333,32 +333,6 @@ public: } break; - case MEDIA_APPLYCONSTRAINTS_TRACK: - { - nsRefPtr mgr = MediaManager::GetInstance(); - - NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); - if (mAudioDevice) { - mAudioDevice->Restart(mConstraints, mgr->mPrefs); - } - if (mVideoDevice) { - mVideoDevice->Restart(mConstraints, mgr->mPrefs); - } - - // Need to dispatch something back to main to resolve promise - // redo this with pledge? - nsIRunnable *event = - new GetUserMediaNotificationEvent(mListener, - GetUserMediaNotificationEvent::APPLIED_CONSTRAINTS, - mAudioDevice != nullptr, - mVideoDevice != nullptr, - mWindowID); - // event must always be released on mainthread due to the JS callbacks - // in the TracksAvailableCallback - NS_DispatchToMainThread(event); - } - break; - case MEDIA_DIRECT_LISTENERS: { NS_ASSERTION(!NS_IsMainThread(), "Never call on main thread"); @@ -726,9 +700,10 @@ public: // 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()); + mListener->StopTrack(aTrackID, + !!GetDOMTrackFor(aTrackID)->AsAudioStreamTrack()); } else { - LOG(("StopTrack(%d) on non-existant track", aTrackID)); + LOG(("StopTrack(%d) on non-existent track", aTrackID)); } } } @@ -738,22 +713,45 @@ public: const MediaTrackConstraints& aConstraints, ErrorResult &aRv) override { - if (mSourceStream) { - nsRefPtr track = GetDOMTrackFor(aTrackID); - if (track) { - mListener->ApplyConstraintsToTrack(aTrackID, - !!track->AsAudioStreamTrack(), - aConstraints); - } else { - LOG(("ApplyConstraintsToTrack(%d) on non-existant track", aTrackID)); - } - } - nsPIDOMWindow* window = static_cast(mWindow.get()); nsCOMPtr go = do_QueryInterface(window); - nsRefPtr p = Promise::Create(go, aRv); - p->MaybeResolve(false); - return p.forget(); + nsRefPtr promise = Promise::Create(go, aRv); + + if (sInShutdown) { + nsRefPtr error = new MediaStreamError(window, + NS_LITERAL_STRING("AbortError"), + NS_LITERAL_STRING("In shutdown")); + promise->MaybeReject(error); + return promise.forget(); + } + if (!mSourceStream) { + nsRefPtr error = new MediaStreamError(window, + NS_LITERAL_STRING("InternalError"), + NS_LITERAL_STRING("No stream.")); + promise->MaybeReject(error); + return promise.forget(); + } + + nsRefPtr track = GetDOMTrackFor(aTrackID); + if (!track) { + LOG(("ApplyConstraintsToTrack(%d) on non-existent track", aTrackID)); + nsRefPtr error = new MediaStreamError(window, + NS_LITERAL_STRING("InternalError"), + NS_LITERAL_STRING("No track.")); + promise->MaybeReject(error); + return promise.forget(); + } + + typedef media::Pledge PledgeVoid; + + nsRefPtr p = mListener->ApplyConstraintsToTrack(window, + aTrackID, !!track->AsAudioStreamTrack(), aConstraints); + p->Then([promise](bool& aDummy) mutable { + promise->MaybeResolve(false); + }, [promise](MediaStreamError*& reason) mutable { + promise->MaybeReject(reason); + }); + return promise.forget(); } #if 0 @@ -804,14 +802,14 @@ public: } // let us intervene for direct listeners when someone does track.enabled = false - virtual void SetTrackEnabled(TrackID aID, bool aEnabled) override + virtual void SetTrackEnabled(TrackID aTrackID, bool aEnabled) override { // We encapsulate the SourceMediaStream and TrackUnion into one entity, so // we can handle the disabling at the SourceMediaStream - // We need to find the input track ID for output ID aID, so we let the TrackUnion + // 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(aID, aEnabled); + GetStream()->AsProcessedStream()->ForwardTrackEnabled(aTrackID, aEnabled); } virtual DOMLocalMediaStream* AsDOMLocalMediaStream() override @@ -3067,33 +3065,102 @@ GetUserMediaCallbackMediaStreamListener::StopSharing() // ApplyConstraints for track -void +already_AddRefed GetUserMediaCallbackMediaStreamListener::ApplyConstraintsToTrack( - TrackID aID, + nsPIDOMWindow* aWindow, + TrackID aTrackID, bool aIsAudio, const MediaTrackConstraints& aConstraints) { - if (((aIsAudio && mAudioDevice) || - (!aIsAudio && mVideoDevice)) && !mStopped) + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr p = new PledgeVoid(); + + if (!(((aIsAudio && mAudioDevice) || + (!aIsAudio && mVideoDevice)) && !mStopped)) { - // XXX to support multiple tracks of a type in a stream, this should key off - // the TrackID and not just the type - MediaManager::PostTask(FROM_HERE, - new MediaOperationTask(MEDIA_APPLYCONSTRAINTS_TRACK, - this, nullptr, nullptr, - aIsAudio ? mAudioDevice.get() : nullptr, - !aIsAudio ? mVideoDevice.get() : nullptr, - mFinished, mWindowID, nullptr, aConstraints)); - } else { LOG(("gUM track %d applyConstraints, but we don't have type %s", - aID, aIsAudio ? "audio" : "video")); + aTrackID, aIsAudio ? "audio" : "video")); + p->Resolve(false); + return p.forget(); } + + // XXX to support multiple tracks of a type in a stream, this should key off + // the TrackID and not just the type + nsRefPtr audioDevice = aIsAudio ? mAudioDevice.get() : nullptr; + nsRefPtr videoDevice = !aIsAudio ? mVideoDevice.get() : nullptr; + + nsRefPtr mgr = MediaManager::GetInstance(); + uint32_t id = mgr->mOutstandingVoidPledges.Append(*p); + uint64_t windowId = aWindow->WindowID(); + + MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, windowId, + audioDevice, videoDevice, + aConstraints]() mutable { + MOZ_ASSERT(MediaManager::IsInMediaThread()); + nsRefPtr mgr = MediaManager::GetInstance(); + const char* badConstraint = nullptr; + nsresult rv = NS_OK; + + if (audioDevice) { + rv = audioDevice->Restart(aConstraints, mgr->mPrefs); + if (rv == NS_ERROR_NOT_AVAILABLE) { + nsTArray> audios; + audios.AppendElement(audioDevice); + badConstraint = MediaConstraintsHelper::SelectSettings(aConstraints, + audios); + } + } else { + rv = videoDevice->Restart(aConstraints, mgr->mPrefs); + if (rv == NS_ERROR_NOT_AVAILABLE) { + nsTArray> videos; + videos.AppendElement(videoDevice); + badConstraint = MediaConstraintsHelper::SelectSettings(aConstraints, + videos); + } + } + NS_DispatchToMainThread(do_AddRef(NewRunnableFrom([id, windowId, rv, + badConstraint]() mutable { + MOZ_ASSERT(NS_IsMainThread()); + nsRefPtr mgr = MediaManager_GetInstance(); + if (!mgr) { + return NS_OK; + } + nsRefPtr p = mgr->mOutstandingVoidPledges.Remove(id); + if (p) { + if (NS_SUCCEEDED(rv)) { + p->Resolve(false); + } else { + nsPIDOMWindow *window = static_cast + (nsGlobalWindow::GetInnerWindowWithId(windowId)); + if (window) { + if (rv == NS_ERROR_NOT_AVAILABLE) { + nsString constraint; + constraint.AssignASCII(badConstraint); + nsRefPtr error = + new MediaStreamError(window, + NS_LITERAL_STRING("OverconstrainedError"), + NS_LITERAL_STRING(""), + constraint); + p->Reject(error); + } else { + nsRefPtr error = + new MediaStreamError(window, + NS_LITERAL_STRING("InternalError")); + p->Reject(error); + } + } + } + } + return NS_OK; + }))); + })); + return p.forget(); } // Stop backend for track void -GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio) +GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aTrackID, bool aIsAudio) { if (((aIsAudio && mAudioDevice) || (!aIsAudio && mVideoDevice)) && !mStopped) @@ -3108,7 +3175,7 @@ GetUserMediaCallbackMediaStreamListener::StopTrack(TrackID aID, bool aIsAudio) mFinished, mWindowID, nullptr)); } else { LOG(("gUM track %d ended, but we don't have type %s", - aID, aIsAudio ? "audio" : "video")); + aTrackID, aIsAudio ? "audio" : "video")); } } @@ -3174,9 +3241,6 @@ GetUserMediaNotificationEvent::Run() case STOPPED_TRACK: msg = NS_LITERAL_STRING("shutdown"); break; - case APPLIED_CONSTRAINTS: - msg = NS_LITERAL_STRING("constraints-changed"); - break; } nsCOMPtr window = nsGlobalWindow::GetInnerWindowWithId(mWindowID); diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 41dcb1a472d3..b87a15191885 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -167,8 +167,12 @@ public: void StopTrack(TrackID aID, bool aIsAudio); - void ApplyConstraintsToTrack(TrackID aID, bool aIsAudio, - const dom::MediaTrackConstraints& aConstraints); + typedef media::Pledge PledgeVoid; + + already_AddRefed + ApplyConstraintsToTrack(nsPIDOMWindow* aWindow, + TrackID aID, bool aIsAudio, + const dom::MediaTrackConstraints& aConstraints); // mVideo/AudioDevice are set by Activate(), so we assume they're capturing // if set and represent a real capture device. @@ -323,7 +327,6 @@ class GetUserMediaNotificationEvent: public nsRunnable STARTING, STOPPING, STOPPED_TRACK, - APPLIED_CONSTRAINTS, }; GetUserMediaNotificationEvent(GetUserMediaCallbackMediaStreamListener* aListener, GetUserMediaStatus aStatus, @@ -362,7 +365,6 @@ typedef enum { MEDIA_STOP, MEDIA_STOP_TRACK, MEDIA_DIRECT_LISTENERS, - MEDIA_APPLYCONSTRAINTS_TRACK, } MediaOperation; class MediaManager; @@ -393,6 +395,7 @@ typedef void (*WindowListenerCallback)(MediaManager *aThis, class MediaManager final : public nsIMediaManagerService, public nsIObserver { + friend GetUserMediaCallbackMediaStreamListener; public: static already_AddRefed GetInstance(); @@ -520,6 +523,7 @@ private: static StaticRefPtr sSingleton; media::CoatCheck mOutstandingPledges; + media::CoatCheck mOutstandingVoidPledges; #if defined(MOZ_B2G_CAMERA) && defined(MOZ_WIDGET_GONK) nsRefPtr mCameraManager; #endif diff --git a/dom/media/tests/mochitest/test_getUserMedia_constraints.html b/dom/media/tests/mochitest/test_getUserMedia_constraints.html index e076060914df..eb1a39e7b20c 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html +++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html @@ -117,7 +117,12 @@ runTest(function() { is(e.constraint, test.constraint, test.message + " w/correct constraint."); } - }), p); + }), p) + .then(() => navigator.mediaDevices.getUserMedia({video: true, audio: true})) + .then(stream => stream.getVideoTracks()[0].applyConstraints({ width: 320 }) + .then(() => stream.getAudioTracks()[0].applyConstraints({ }))) + .then(() => ok(true, "applyConstraints code exercised")) + // TODO: Test outcome once fake devices support constraints (Bug 1088621) }); diff --git a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp index ecc786e9b4dd..1c2872926e05 100644 --- a/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp +++ b/dom/media/webrtc/MediaEngineRemoteVideoSource.cpp @@ -217,16 +217,23 @@ MediaEngineRemoteVideoSource::Restart(const dom::MediaTrackConstraints& aConstra const MediaEnginePrefs& aPrefs, const nsString& aDeviceId) { - if (mState == kStarted && mInitDone && - ChooseCapability(aConstraints, aPrefs, aDeviceId)) { - mozilla::camera::StopCapture(mCapEngine, mCaptureIndex); - if (mozilla::camera::StartCapture(mCapEngine, - mCaptureIndex, mCapability, this)) { - LOG(("StartCapture failed")); - return NS_ERROR_FAILURE; - } + if (!mInitDone) { + LOG(("Init not done")); + return NS_ERROR_FAILURE; + } + if (!ChooseCapability(aConstraints, aPrefs, aDeviceId)) { + return NS_ERROR_NOT_AVAILABLE; + } + if (mState != kStarted) { + return NS_OK; } + mozilla::camera::StopCapture(mCapEngine, mCaptureIndex); + if (mozilla::camera::StartCapture(mCapEngine, + mCaptureIndex, mCapability, this)) { + LOG(("StartCapture failed")); + return NS_ERROR_FAILURE; + } return NS_OK; }