diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index ec7315ae222e..33daa0675d37 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -185,9 +185,11 @@ using dom::Sequence; using dom::UserActivation; using dom::WindowGlobalChild; using ConstDeviceSetPromise = MediaManager::ConstDeviceSetPromise; +using DeviceSetPromise = MediaManager::DeviceSetPromise; using LocalDevicePromise = MediaManager::LocalDevicePromise; using LocalDeviceSetPromise = MediaManager::LocalDeviceSetPromise; using LocalMediaDeviceSetRefCnt = MediaManager::LocalMediaDeviceSetRefCnt; +using MediaDeviceSetRefCnt = MediaManager::MediaDeviceSetRefCnt; using media::NewRunnableFrom; using media::NewTaskFrom; using media::Refcountable; @@ -1796,12 +1798,36 @@ void MediaManager::GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices, } } +namespace { + +// Class to hold the promise returned by EnumerateRawDevices() and to resolve +// even if |task| does not run, either because GeckoViewPermissionProcessChild +// gets destroyed before ask-device-permission receives its +// got-device-permission reply, or because the media thread is no longer +// available. In either case, the process is shutting down so the result is +// not important. Resolve with an empty set, so that callers do not need to +// handle rejection. +class DeviceSetPromiseHolderWithFallback + : public MozPromiseHolder { + public: + DeviceSetPromiseHolderWithFallback() = default; + DeviceSetPromiseHolderWithFallback(DeviceSetPromiseHolderWithFallback&&) = + default; + ~DeviceSetPromiseHolderWithFallback() { + if (!IsEmpty()) { + Resolve(new MediaDeviceSetRefCnt(), __func__); + } + } +}; + +} // anonymous namespace + /** * EnumerateRawDevices - Enumerate a list of audio & video devices that * satisfy passed-in constraints. List contains raw id's. */ -RefPtr MediaManager::EnumerateRawDevices( +RefPtr MediaManager::EnumerateRawDevices( MediaSourceEnum aVideoInputType, MediaSourceEnum aAudioInputType, EnumerationFlags aFlags) { MOZ_ASSERT(NS_IsMainThread()); @@ -1813,13 +1839,11 @@ RefPtr MediaManager::EnumerateRawDevices( static_cast(aVideoInputType), static_cast(aAudioInputType)); - MozPromiseHolder holder; + DeviceSetPromiseHolderWithFallback holder; RefPtr promise = holder.Ensure(__func__); if (sHasMainThreadShutdown) { // The media thread is no longer available but the result will not be - // observable. Resolve with an empty set, so that callers do not need to - // handle rejection. - holder.Resolve(new MediaDeviceSetRefCnt(), __func__); + // observable. |holder| will resolve |promise| on destruction. return promise; } diff --git a/dom/media/webrtc/tests/crashtests/crashtests.list b/dom/media/webrtc/tests/crashtests/crashtests.list index 735a1b495e70..2afaa4042b45 100644 --- a/dom/media/webrtc/tests/crashtests/crashtests.list +++ b/dom/media/webrtc/tests/crashtests/crashtests.list @@ -5,3 +5,4 @@ load 1789908.html load 1799168.html load 1816708.html load 1821477.html +pref(media.navigator.permission.device,true) pref(media.audio_loopback_dev,"real-device-request-with-clear-cache") load getUserMedia-audio.html # bug 1767893 diff --git a/dom/media/webrtc/tests/crashtests/getUserMedia-audio.html b/dom/media/webrtc/tests/crashtests/getUserMedia-audio.html new file mode 100644 index 000000000000..14b6d0d7a287 --- /dev/null +++ b/dom/media/webrtc/tests/crashtests/getUserMedia-audio.html @@ -0,0 +1,7 @@ + + +