Bug 1732409 consolidate camera and microphone preference handling into EnumerateRawDevices r=jib

This is performed for
"media.navigator.streams.fake"
"media.video_loopback_dev"
"media.audio_loopback_dev"

Depends on D132897

Differential Revision: https://phabricator.services.mozilla.com/D132898
This commit is contained in:
Karl Tomlinson 2021-12-26 01:38:59 +00:00
Родитель 0332d2ebf0
Коммит 829f90aa36
3 изменённых файлов: 62 добавлений и 155 удалений

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

@ -27,7 +27,6 @@
namespace mozilla::dom {
using EnumerationFlag = MediaManager::EnumerationFlag;
using DeviceEnumerationType = MediaManager::DeviceEnumerationType;
using LocalMediaDeviceSetRefCnt = MediaManager::LocalMediaDeviceSetRefCnt;
MediaDevices::MediaDevices(nsPIDOMWindowInner* aWindow)
@ -457,8 +456,6 @@ RefPtr<MediaDevices::SinkInfoPromise> MediaDevices::GetSinkDevice(
return MediaManager::Get()
->EnumerateDevicesImpl(GetOwner(), MediaSourceEnum::Other, audioInputType,
DeviceEnumerationType::Normal,
DeviceEnumerationType::Normal,
EnumerationFlag::EnumerateAudioOutputs)
->Then(
GetCurrentSerialEventTarget(), __func__,

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

@ -1766,36 +1766,15 @@ void MediaManager::GuessVideoDeviceGroupIDs(MediaDeviceSet& aDevices,
RefPtr<MediaManager::DeviceSetPromise> MediaManager::EnumerateRawDevices(
MediaSourceEnum aVideoInputType, MediaSourceEnum aAudioInputType,
DeviceEnumerationType aVideoInputEnumType,
DeviceEnumerationType aAudioInputEnumType, EnumerationFlags aFlags) {
EnumerationFlags aFlags) {
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aVideoInputType != MediaSourceEnum::Other ||
aAudioInputType != MediaSourceEnum::Other ||
aFlags.contains(EnumerationFlag::EnumerateAudioOutputs));
// Since the enums can take one of several values, the following asserts rely
// on short circuting behavior. E.g. aVideoInputEnumType != Fake will be true
// if the requested device is not fake and thus the assert will pass. However,
// if the device is fake, aVideoInputType == MediaSourceEnum::Camera will be
// checked as well, ensuring that fake devices are of the camera type.
MOZ_ASSERT(aVideoInputEnumType != DeviceEnumerationType::Fake ||
aVideoInputType == MediaSourceEnum::Camera,
"If fake cams are requested video type should be camera!");
MOZ_ASSERT(aVideoInputEnumType != DeviceEnumerationType::Loopback ||
aVideoInputType == MediaSourceEnum::Camera,
"If loopback video is requested video type should be camera!");
MOZ_ASSERT(aAudioInputEnumType != DeviceEnumerationType::Fake ||
aAudioInputType == MediaSourceEnum::Microphone,
"If fake mics are requested audio type should be microphone!");
MOZ_ASSERT(aAudioInputEnumType != DeviceEnumerationType::Loopback ||
aAudioInputType == MediaSourceEnum::Microphone,
"If loopback audio is requested audio type should be microphone!");
LOG("%s: aVideoInputType=%" PRIu8 ", aAudioInputType=%" PRIu8
", aVideoInputEnumType=%" PRIu8 ", aAudioInputEnumType=%" PRIu8,
__func__, static_cast<uint8_t>(aVideoInputType),
static_cast<uint8_t>(aAudioInputType),
static_cast<uint8_t>(aVideoInputEnumType),
static_cast<uint8_t>(aAudioInputEnumType));
LOG("%s: aVideoInputType=%" PRIu8 ", aAudioInputType=%" PRIu8, __func__,
static_cast<uint8_t>(aVideoInputType),
static_cast<uint8_t>(aAudioInputType));
MozPromiseHolder<DeviceSetPromise> holder;
RefPtr<DeviceSetPromise> promise = holder.Ensure(__func__);
@ -1804,34 +1783,42 @@ RefPtr<MediaManager::DeviceSetPromise> MediaManager::EnumerateRawDevices(
const bool hasAudio = aAudioInputType != MediaSourceEnum::Other;
const bool hasAudioOutput =
aFlags.contains(EnumerationFlag::EnumerateAudioOutputs);
// True of at least one of video input or audio input is a fake device
const bool fakeDeviceRequested =
(aVideoInputEnumType == DeviceEnumerationType::Fake && hasVideo) ||
(aAudioInputEnumType == DeviceEnumerationType::Fake && hasAudio);
const bool forceFakes = aFlags.contains(EnumerationFlag::ForceFakes);
const bool fakeByPref = Preferences::GetBool("media.navigator.streams.fake");
// Fake and loopback devices are supported for only Camera and Microphone.
nsAutoCString videoLoopDev, audioLoopDev;
bool hasFakeCams = false;
bool hasFakeMics = false;
if (aVideoInputType == MediaSourceEnum::Camera) {
if (forceFakes) {
hasFakeCams = true;
} else {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
// Loopback prefs take precedence over fake prefs
hasFakeCams = fakeByPref && videoLoopDev.IsEmpty();
}
}
if (aAudioInputType == MediaSourceEnum::Microphone) {
if (forceFakes) {
hasFakeMics = true;
} else {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
// Loopback prefs take precedence over fake prefs
hasFakeMics = fakeByPref && audioLoopDev.IsEmpty();
}
}
// True if at least one of video input or audio input is a real device
// or there is audio output.
const bool realDeviceRequested =
(aVideoInputEnumType != DeviceEnumerationType::Fake && hasVideo) ||
(aAudioInputEnumType != DeviceEnumerationType::Fake && hasAudio) ||
hasAudioOutput;
const bool realDeviceRequested = (!hasFakeCams && hasVideo) ||
(!hasFakeMics && hasAudio) || hasAudioOutput;
nsAutoCString videoLoopDev, audioLoopDev;
if (hasVideo && aVideoInputEnumType == DeviceEnumerationType::Loopback) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
}
if (hasAudio && aAudioInputEnumType == DeviceEnumerationType::Loopback) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
}
RefPtr<Runnable> task =
NewTaskFrom([holder = std::move(holder), aVideoInputType, aAudioInputType,
aVideoInputEnumType, aAudioInputEnumType, videoLoopDev,
audioLoopDev, hasVideo, hasAudio, hasAudioOutput,
fakeDeviceRequested, realDeviceRequested]() mutable {
RefPtr<Runnable> task = NewTaskFrom(
[holder = std::move(holder), aVideoInputType, aAudioInputType,
hasFakeCams, hasFakeMics, videoLoopDev, audioLoopDev, hasVideo, hasAudio,
hasAudioOutput, realDeviceRequested]() mutable {
// Only enumerate what's asked for, and only fake cams and mics.
RefPtr<MediaEngine> fakeBackend, realBackend;
if (fakeDeviceRequested) {
if (hasFakeCams || hasFakeMics) {
fakeBackend = new MediaEngineDefault();
}
if (realDeviceRequested) {
@ -1847,9 +1834,7 @@ RefPtr<MediaManager::DeviceSetPromise> MediaManager::EnumerateRawDevices(
RefPtr devices = new MediaDeviceSetRefCnt();
if (hasVideo) {
videoBackend = aVideoInputEnumType == DeviceEnumerationType::Fake
? fakeBackend
: realBackend;
videoBackend = hasFakeCams ? fakeBackend : realBackend;
MediaDeviceSet videos;
LOG("EnumerateRawDevices Task: Getting video sources with %s backend",
videoBackend == fakeBackend ? "fake" : "real");
@ -1858,9 +1843,7 @@ RefPtr<MediaManager::DeviceSetPromise> MediaManager::EnumerateRawDevices(
devices->AppendElements(videos);
}
if (hasAudio) {
audioBackend = aAudioInputEnumType == DeviceEnumerationType::Fake
? fakeBackend
: realBackend;
audioBackend = hasFakeMics ? fakeBackend : realBackend;
MediaDeviceSet audios;
LOG("EnumerateRawDevices Task: Getting audio sources with %s backend",
audioBackend == fakeBackend ? "fake" : "real");
@ -2240,8 +2223,6 @@ void MediaManager::DeviceListChanged() {
void MediaManager::HandleDeviceListChanged() {
EnumerateRawDevices(MediaSourceEnum::Camera, MediaSourceEnum::Microphone,
DeviceEnumerationType::Normal,
DeviceEnumerationType::Normal,
EnumerationFlag::EnumerateAudioOutputs)
->Then(
GetCurrentSerialEventTarget(), __func__,
@ -2656,35 +2637,10 @@ RefPtr<MediaManager::StreamPromise> MediaManager::GetUserMedia(
bool hasVideo = videoType != MediaSourceEnum::Other;
bool hasAudio = audioType != MediaSourceEnum::Other;
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
// Handle loopback and fake requests. For gUM we don't consider resist
// Handle fake requests from content. For gUM we don't consider resist
// fingerprinting as users should be prompted anyway.
bool forceFakes = c.mFake.WasPassed() && c.mFake.Value();
bool wantFakes =
forceFakes || Preferences::GetBool("media.navigator.streams.fake");
nsAutoCString videoLoopDev, audioLoopDev;
// Video
if (videoType == MediaSourceEnum::Camera) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
// Loopback prefs take precedence over fake prefs
if (!videoLoopDev.IsEmpty() && !forceFakes) {
videoEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
videoEnumerationType = DeviceEnumerationType::Fake;
}
}
// Audio
if (audioType == MediaSourceEnum::Microphone) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
// Loopback prefs take precedence over fake prefs
if (!audioLoopDev.IsEmpty() && !forceFakes) {
audioEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
audioEnumerationType = DeviceEnumerationType::Fake;
}
}
// fake:true is effective only for microphone and camera devices, so
// permission must be requested for screen capture even if fake:true is set.
bool hasOnlyForcedFakes =
@ -2698,18 +2654,17 @@ RefPtr<MediaManager::StreamPromise> MediaManager::GetUserMedia(
LOG("%s: Preparing to enumerate devices. windowId=%" PRIu64
", videoType=%" PRIu8 ", audioType=%" PRIu8
", videoEnumerationType=%" PRIu8 ", audioEnumerationType=%" PRIu8
", askPermission=%s",
", forceFakes=%s, askPermission=%s",
__func__, windowID, static_cast<uint8_t>(videoType),
static_cast<uint8_t>(audioType),
static_cast<uint8_t>(videoEnumerationType),
static_cast<uint8_t>(audioEnumerationType),
static_cast<uint8_t>(audioType), forceFakes ? "true" : "false",
askPermission ? "true" : "false");
EnumerationFlags flags = EnumerationFlag::AllowPermissionRequest;
if (forceFakes) {
flags += EnumerationFlag::ForceFakes;
}
RefPtr<MediaManager> self = this;
return EnumerateDevicesImpl(aWindow, videoType, audioType,
videoEnumerationType, audioEnumerationType,
EnumerationFlag::AllowPermissionRequest)
return EnumerateDevicesImpl(aWindow, videoType, audioType, flags)
->Then(
GetCurrentSerialEventTarget(), __func__,
[self, windowID, c, windowListener,
@ -2911,18 +2866,14 @@ nsresult MediaManager::AnonymizeId(nsAString& aId,
RefPtr<LocalDeviceSetPromise> MediaManager::EnumerateDevicesImpl(
nsPIDOMWindowInner* aWindow, MediaSourceEnum aVideoInputType,
MediaSourceEnum aAudioInputType, DeviceEnumerationType aVideoInputEnumType,
DeviceEnumerationType aAudioInputEnumType, EnumerationFlags aFlags) {
MediaSourceEnum aAudioInputType, EnumerationFlags aFlags) {
MOZ_ASSERT(NS_IsMainThread());
uint64_t windowId = aWindow->WindowID();
LOG("%s: windowId=%" PRIu64 ", aVideoInputType=%" PRIu8
", aAudioInputType=%" PRIu8 ", aVideoInputEnumType=%" PRIu8
", aAudioInputEnumType=%" PRIu8,
", aAudioInputType=%" PRIu8,
__func__, windowId, static_cast<uint8_t>(aVideoInputType),
static_cast<uint8_t>(aAudioInputType),
static_cast<uint8_t>(aVideoInputEnumType),
static_cast<uint8_t>(aAudioInputEnumType));
static_cast<uint8_t>(aAudioInputType));
// To get a device list anonymized for a particular origin, we must:
// 1. Get an origin-key (for either regular or private browsing)
@ -2961,8 +2912,7 @@ RefPtr<LocalDeviceSetPromise> MediaManager::EnumerateDevicesImpl(
return media::GetPrincipalKey(principalInfo, persist)
->Then(
GetMainThreadSerialEventTarget(), __func__,
[windowId, aVideoInputType, aAudioInputType, aVideoInputEnumType,
aAudioInputEnumType, aFlags,
[windowId, aVideoInputType, aAudioInputType, aFlags,
originKey](const nsCString& aOriginKey) {
MOZ_ASSERT(NS_IsMainThread());
originKey->Assign(aOriginKey);
@ -2974,8 +2924,7 @@ RefPtr<LocalDeviceSetPromise> MediaManager::EnumerateDevicesImpl(
__func__);
}
return mgr->EnumerateRawDevices(aVideoInputType, aAudioInputType,
aVideoInputEnumType,
aAudioInputEnumType, aFlags);
aFlags);
},
[](nsresult rs) {
NS_WARNING(
@ -3025,9 +2974,6 @@ RefPtr<LocalDeviceSetPromise> MediaManager::EnumerateDevices(
Document* doc = aWindow->GetExtantDoc();
MOZ_ASSERT(doc);
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
// Only expose devices which are allowed to use:
// https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices
MediaSourceEnum videoType =
@ -3051,40 +2997,11 @@ RefPtr<LocalDeviceSetPromise> MediaManager::EnumerateDevices(
}
bool resistFingerprinting = nsContentUtils::ShouldResistFingerprinting(doc);
// In order of precedence: resist fingerprinting > loopback > fake pref
if (resistFingerprinting) {
videoEnumerationType = DeviceEnumerationType::Fake;
audioEnumerationType = DeviceEnumerationType::Fake;
} else {
// Handle loopback and fake requests
nsAutoCString videoLoopDev, audioLoopDev;
bool wantFakes = Preferences::GetBool("media.navigator.streams.fake");
// Video
if (videoType == MediaSourceEnum::Camera) {
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
// Loopback prefs take precedence over fake prefs
if (!videoLoopDev.IsEmpty()) {
videoEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
videoEnumerationType = DeviceEnumerationType::Fake;
}
}
// Audio
if (audioType == MediaSourceEnum::Microphone) {
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
// Loopback prefs take precedence over fake prefs
if (!audioLoopDev.IsEmpty()) {
audioEnumerationType = DeviceEnumerationType::Loopback;
} else if (wantFakes) {
audioEnumerationType = DeviceEnumerationType::Fake;
}
}
flags += EnumerationFlag::ForceFakes;
}
return EnumerateDevicesImpl(aWindow, videoType, audioType,
videoEnumerationType, audioEnumerationType,
flags);
return EnumerateDevicesImpl(aWindow, videoType, audioType, flags);
}
RefPtr<LocalDevicePromise> MediaManager::SelectAudioOutput(
@ -3120,11 +3037,10 @@ RefPtr<LocalDevicePromise> MediaManager::SelectAudioOutput(
__func__);
}
uint64_t windowID = aWindow->WindowID();
return EnumerateDevicesImpl(
aWindow, MediaSourceEnum::Other, MediaSourceEnum::Other,
DeviceEnumerationType::Normal, DeviceEnumerationType::Normal,
{EnumerationFlag::EnumerateAudioOutputs,
EnumerationFlag::AllowPermissionRequest})
return EnumerateDevicesImpl(aWindow, MediaSourceEnum::Other,
MediaSourceEnum::Other,
{EnumerationFlag::EnumerateAudioOutputs,
EnumerationFlag::AllowPermissionRequest})
->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr<MediaManager>(this), windowID, aOptions, aCallerType,

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

@ -278,19 +278,15 @@ class MediaManager final : public nsIMediaManagerService,
RefPtr<LocalDeviceSetPromise> EnumerateDevices(nsPIDOMWindowInner* aWindow);
enum class DeviceEnumerationType : uint8_t {
Normal, // Enumeration should not return loopback or fake devices
Fake, // Enumeration should return fake device(s)
Loopback /* Enumeration should return loopback device(s) (possibly in
addition to normal devices) */
enum class EnumerationFlag {
AllowPermissionRequest,
EnumerateAudioOutputs,
ForceFakes,
};
enum class EnumerationFlag { AllowPermissionRequest, EnumerateAudioOutputs };
using EnumerationFlags = EnumSet<EnumerationFlag>;
RefPtr<LocalDeviceSetPromise> EnumerateDevicesImpl(
nsPIDOMWindowInner* aWindow, dom::MediaSourceEnum aVideoInputType,
dom::MediaSourceEnum aAudioInputType,
DeviceEnumerationType aVideoInputEnumType,
DeviceEnumerationType aAudioInputEnumType, EnumerationFlags aFlags);
dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
RefPtr<LocalDevicePromise> SelectAudioOutput(
nsPIDOMWindowInner* aWindow, const dom::AudioOutputOptions& aOptions,
@ -331,9 +327,7 @@ class MediaManager final : public nsIMediaManagerService,
private:
RefPtr<DeviceSetPromise> EnumerateRawDevices(
dom::MediaSourceEnum aVideoInputType,
dom::MediaSourceEnum aAudioInputType,
DeviceEnumerationType aVideoInputEnumType,
DeviceEnumerationType aAudioInputEnumType, EnumerationFlags aFlags);
dom::MediaSourceEnum aAudioInputType, EnumerationFlags aFlags);
RefPtr<LocalDeviceSetPromise> SelectSettings(
const dom::MediaStreamConstraints& aConstraints,