Bug 1800580 preselect AudioOutputOptions.deviceId if present for webRTC-selectSpeaker-menulist r=jib

The selectAudioOutput() prompt will be presented even when speaker permissions
are implemented, if permissions have expired or been revoked.

Differential Revision: https://phabricator.services.mozilla.com/D162078
This commit is contained in:
Karl Tomlinson 2022-12-06 05:01:19 +00:00
parent 352eecc756
commit 7791a9abac
5 changed files with 64 additions and 25 deletions

View File

@ -274,6 +274,7 @@ function handleGUMRequest(aSubject, aTopic, aData) {
aSubject.windowID,
aSubject.callID,
constraints,
aSubject.getAudioOutputOptions(),
aSubject.devices,
aSubject.isSecure,
aSubject.isHandlingUserInput
@ -286,6 +287,7 @@ function prompt(
aWindowID,
aCallID,
aConstraints,
aAudioOutputOptions,
aDevices,
aSecure,
aIsHandlingUserInput
@ -322,6 +324,7 @@ function prompt(
name: device.rawName, // unfiltered device name to show to the user
deviceIndex: devices.length,
rawId: device.rawId,
id: device.id,
mediaSource: device.mediaSource,
};
switch (device.type) {
@ -423,6 +426,7 @@ function prompt(
audioOutputDevices,
hasInherentAudioConstraints,
hasInherentVideoConstraints,
audioOutputId: aAudioOutputOptions.deviceId,
};
let actor = getActorForWindow(aContentWindow);

View File

@ -784,7 +784,14 @@ function prompt(aActor, aBrowser, aRequest) {
menulist.selectedItem = null;
for (let device of devices) {
addDeviceToList(menupopup, device.name, device.deviceIndex);
let item = addDeviceToList(
menupopup,
device.name,
device.deviceIndex
);
if (device.id == aRequest.audioOutputId) {
menulist.selectedItem = item;
}
}
let label = doc.getElementById(labelID);

View File

@ -24,29 +24,34 @@ async function requestAudioOutputExpectingPrompt() {
checkDeviceSelectors(["speaker"]);
}
async function simulateAudioOutputRequest() {
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function simPrompt() {
const req = {
type: "selectaudiooutput",
windowID: content.windowGlobalChild.outerWindowId,
devices: [
{
type: "audiooutput",
rawName: "name 1",
deviceIndex: 1,
rawId: "id 1",
QueryInterface: ChromeUtils.generateQI([Ci.nsIMediaDevice]),
},
],
getConstraints: () => ({}),
isSecure: true,
isHandlingUserInput: true,
};
const { WebRTCChild } = SpecialPowers.ChromeUtils.import(
"resource:///actors/WebRTCChild.jsm"
);
WebRTCChild.observe(req, "getUserMedia:request");
});
async function simulateAudioOutputRequest(options) {
await SpecialPowers.spawn(
gBrowser.selectedBrowser,
[options],
function simPrompt({ deviceCount, deviceId }) {
const devices = [...Array(deviceCount).keys()].map(i => ({
type: "audiooutput",
rawName: `name ${i}`,
deviceIndex: i,
rawId: `rawId ${i}`,
id: `id ${i}`,
QueryInterface: ChromeUtils.generateQI([Ci.nsIMediaDevice]),
}));
const req = {
type: "selectaudiooutput",
windowID: content.windowGlobalChild.outerWindowId,
devices,
getConstraints: () => ({}),
getAudioOutputOptions: () => ({ deviceId }),
isSecure: true,
isHandlingUserInput: true,
};
const { WebRTCChild } = SpecialPowers.ChromeUtils.import(
"resource:///actors/WebRTCChild.jsm"
);
WebRTCChild.observe(req, "getUserMedia:request");
}
);
}
async function allow() {
@ -108,12 +113,27 @@ var gTests = [
run: async function checkSingle() {
await Promise.all([
promisePopupNotificationShown("webRTC-shareDevices"),
simulateAudioOutputRequest(),
simulateAudioOutputRequest({ deviceCount: 1 }),
]);
checkDeviceSelectors(["speaker"]);
await escapePrompt();
},
},
{
desc: "Multi Device with deviceId",
run: async function checkMulti() {
await Promise.all([
promisePopupNotificationShown("webRTC-shareDevices"),
simulateAudioOutputRequest({ deviceCount: 4, deviceId: "id 2" }),
]);
const selectorList = document.getElementById(
`webRTC-selectSpeaker-menulist`
);
is(selectorList.selectedIndex, 2, "pre-selected index");
checkDeviceSelectors(["speaker"]);
await escapePrompt();
},
},
];
add_task(async function test() {

View File

@ -1016,6 +1016,13 @@ LocalMediaDevice::GetRawId(nsAString& aID) {
return NS_OK;
}
NS_IMETHODIMP
LocalMediaDevice::GetId(nsAString& aID) {
MOZ_ASSERT(NS_IsMainThread());
aID.Assign(mID);
return NS_OK;
}
NS_IMETHODIMP
LocalMediaDevice::GetScary(bool* aScary) {
*aScary = mRawDevice->mScary;

View File

@ -11,6 +11,7 @@ interface nsIMediaDevice : nsISupports
readonly attribute AString type;
readonly attribute AString mediaSource;
readonly attribute AString rawId;
readonly attribute AString id; // anonymized and localized to the origin
readonly attribute boolean scary;
readonly attribute AString rawName; // unfiltered device name, from 1616661
};