Bug 1709474 send selectAudioOutput requests to app r=jib

Differential Revision: https://phabricator.services.mozilla.com/D108385
This commit is contained in:
Karl Tomlinson 2021-05-06 08:02:39 +00:00
Родитель bd3b9693bd
Коммит fd16b4ad67
3 изменённых файлов: 110 добавлений и 2 удалений

Просмотреть файл

@ -305,8 +305,29 @@ already_AddRefed<Promise> MediaDevices::SelectAudioOutput(
"selectAudioOutput requires transient user activation.");
return p.forget();
}
aRv.ThrowNotSupportedError("Under implementation");
return nullptr;
RefPtr<MediaDevices> self(this);
MediaManager::Get()
->SelectAudioOutput(owner, aOptions, aCallerType)
->Then(
GetCurrentSerialEventTarget(), __func__,
[this, self, p](RefPtr<MediaDevice> aDevice) {
nsPIDOMWindowInner* window = GetWindowIfCurrent();
if (!window) {
return; // Leave Promise pending after navigation by design.
}
MOZ_ASSERT(aDevice->mKind == dom::MediaDeviceKind::Audiooutput);
p->MaybeResolve(
MakeRefPtr<MediaDeviceInfo>(aDevice->mID, aDevice->mKind,
aDevice->mName, aDevice->mGroupID));
},
[this, self, p](const RefPtr<MediaMgrError>& error) {
nsPIDOMWindowInner* window = GetWindowIfCurrent();
if (!window) {
return; // Leave Promise pending after navigation by design.
}
error->Reject(p);
});
return p.forget();
}
NS_IMPL_ADDREF_INHERITED(MediaDevices, DOMEventTargetHelper)

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/dom/GetUserMediaRequestBinding.h"
#include "mozilla/dom/MediaDeviceInfo.h"
#include "mozilla/dom/MediaDevices.h"
#include "mozilla/dom/MediaDevicesBinding.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/dom/Promise.h"
@ -3164,6 +3165,88 @@ RefPtr<MediaManager::DeviceSetPromise> MediaManager::EnumerateDevices(
});
}
RefPtr<MediaManager::DevicePromise> MediaManager::SelectAudioOutput(
nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
CallerType aCallerType) {
bool isHandlingUserInput = UserActivation::IsHandlingUserInput();
nsCOMPtr<nsIPrincipal> principal =
nsGlobalWindowInner::Cast(aWindow)->GetPrincipal();
if (NS_WARN_IF(!principal)) {
return DevicePromise::CreateAndReject(
MakeRefPtr<MediaMgrError>(MediaMgrError::Name::SecurityError),
__func__);
}
// Disallow access to null principal.
if (principal->GetIsNullPrincipal()) {
return DevicePromise::CreateAndReject(
MakeRefPtr<MediaMgrError>(MediaMgrError::Name::NotAllowedError),
__func__);
}
ipc::PrincipalInfo principalInfo;
nsresult rv = PrincipalToPrincipalInfo(principal, &principalInfo);
if (NS_WARN_IF(NS_FAILED(rv))) {
return DevicePromise::CreateAndReject(
MakeRefPtr<MediaMgrError>(MediaMgrError::Name::SecurityError),
__func__);
}
uint64_t windowID = aWindow->WindowID();
auto devices = MakeRefPtr<MediaDeviceSetRefCnt>();
return EnumerateDevicesImpl(aWindow, MediaSourceEnum::Other,
MediaSourceEnum::Other, MediaSinkEnum::Speaker,
DeviceEnumerationType::Normal,
DeviceEnumerationType::Normal, true, devices)
->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr<MediaManager>(this), windowID, devices, aOptions,
aCallerType, isHandlingUserInput, principalInfo](bool) mutable {
// Ensure that the window is still good.
RefPtr<nsPIDOMWindowInner> window =
nsGlobalWindowInner::GetInnerWindowWithId(windowID);
if (!window) {
LOG("SelectAudioOutput: bad window (%" PRIu64
") in post enumeration success callback!",
windowID);
return DevicePromise::CreateAndReject(
MakeRefPtr<MediaMgrError>(MediaMgrError::Name::AbortError),
__func__);
}
MozPromiseHolder<DevicePromise> holder;
RefPtr<DevicePromise> p = holder.Ensure(__func__);
auto task = MakeRefPtr<SelectAudioOutputTask>(
std::move(holder), windowID, aCallerType, principalInfo);
nsString callID;
nsresult rv = GenerateUUID(callID);
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
size_t taskCount =
self->AddTaskAndGetCount(windowID, callID, std::move(task));
bool askPermission =
!Preferences::GetBool("media.navigator.permission.disabled") ||
Preferences::GetBool("media.navigator.permission.force");
if (!askPermission) {
self->NotifyAllowed(callID, *devices);
} else {
MOZ_ASSERT(window->IsSecureContext());
auto req = MakeRefPtr<GetUserMediaRequest>(
window, callID, std::move(devices), aOptions, true,
isHandlingUserInput);
if (taskCount > 1) {
// there is at least 1 pending gUM request
self->mPendingGUMRequest.AppendElement(req.forget());
} else {
nsCOMPtr<nsIObserverService> obs =
services::GetObserverService();
obs->NotifyObservers(req, "getUserMedia:request", nullptr);
}
}
return p;
},
[](RefPtr<MediaMgrError> aError) {
LOG("SelectAudioOutput: EnumerateDevicesImpl "
"failure callback called!");
return DevicePromise::CreateAndReject(std::move(aError), __func__);
});
}
RefPtr<AudioDeviceInfo> CopyWithNullDeviceId(AudioDeviceInfo* aDeviceInfo) {
MOZ_ASSERT(aDeviceInfo->Preferred());

Просмотреть файл

@ -44,6 +44,7 @@ namespace mozilla {
class TaskQueue;
class MediaTimer;
namespace dom {
struct AudioOutputOptions;
struct MediaStreamConstraints;
struct MediaTrackConstraints;
struct MediaTrackConstraintSet;
@ -238,6 +239,9 @@ class MediaManager final : public nsIMediaManagerService,
nsresult EnumerateDevices(nsPIDOMWindowInner* aWindow,
dom::Promise& aPromise);
RefPtr<DevicePromise> SelectAudioOutput(
nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
dom::CallerType aCallerType);
// Get the sink that corresponds to the given device id.
// It is resposible to check if an application is
// authorized to play audio through the requested device.