Fire an optional JitsiMediaDevices.PERMISSION_PROMPT_IS_SHOWN event when browser shows user media permission prompt when calling createLocalTracks

pull/701/head
tsareg 9 years ago
parent 8ca282079a
commit d149ba6fc5
  1. 132
      conference.js
  2. 1
      lang/main.json
  3. 6
      modules/UI/UI.js
  4. 15
      modules/UI/gum_overlay/UserMediaPermissionsGuidanceOverlay.js
  5. 19
      modules/devices/mediaDeviceHelper.js

@ -27,8 +27,6 @@ let room, connection, localAudio, localVideo, roomLocker;
import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo"; import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo";
const USER_MEDIA_PERMISSIONS_GUIDANCE_OVERLAY_TIMEOUT = 500;
/** /**
* Known custom conference commands. * Known custom conference commands.
*/ */
@ -68,32 +66,26 @@ function connect(roomName) {
*/ */
function createInitialLocalTracksAndConnect(roomName) { function createInitialLocalTracksAndConnect(roomName) {
let audioAndVideoError, let audioAndVideoError,
audioOnlyError, audioOnlyError;
tracksCreated;
JitsiMeetJS.mediaDevices.addEventListener(
JitsiMeetJS.events.mediaDevices.PERMISSION_PROMPT_IS_SHOWN,
browser => APP.UI.showUserMediaPermissionsGuidanceOverlay(browser));
// First try to retrieve both audio and video. // First try to retrieve both audio and video.
let tryCreateLocalTracks = createLocalTracks(['audio', 'video']) let tryCreateLocalTracks = createLocalTracks(
{ devices: ['audio', 'video'] }, true)
.catch(err => { .catch(err => {
// If failed then try to retrieve only audio. // If failed then try to retrieve only audio.
audioAndVideoError = err; audioAndVideoError = err;
return createLocalTracks(['audio']); return createLocalTracks({ devices: ['audio'] }, true);
}) })
.catch(err => { .catch(err => {
// If audio failed too then just return empty array for tracks. // If audio failed too then just return empty array for tracks.
audioOnlyError = err; audioOnlyError = err;
return []; return [];
})
.then(tracks => {
tracksCreated = true;
return tracks;
}); });
window.setTimeout(() => {
if (!audioAndVideoError && !audioOnlyError && !tracksCreated) {
APP.UI.showUserMediaPermissionsGuidanceOverlay();
}
}, USER_MEDIA_PERMISSIONS_GUIDANCE_OVERLAY_TIMEOUT);
return Promise.all([ tryCreateLocalTracks, connect(roomName) ]) return Promise.all([ tryCreateLocalTracks, connect(roomName) ])
.then(([tracks, con]) => { .then(([tracks, con]) => {
APP.UI.hideUserMediaPermissionsGuidanceOverlay(); APP.UI.hideUserMediaPermissionsGuidanceOverlay();
@ -245,32 +237,42 @@ function hangup (requestFeedback = false) {
/** /**
* Create local tracks of specified types. * Create local tracks of specified types.
* @param {string[]} devices - required track types ('audio', 'video' etc.) * @param {Object} options
* @param {string|null} [cameraDeviceId] - camera device id, if undefined - one * @param {string[]} options.devices - required track types
* from settings will be used * ('audio', 'video' etc.)
* @param {string|null} [micDeviceId] - microphone device id, if undefined - one * @param {string|null} (options.cameraDeviceId) - camera device id, if
* from settings will be used * undefined - one from settings will be used
* @param {string|null} (options.micDeviceId) - microphone device id, if
* undefined - one from settings will be used
* @param {boolean} (checkForPermissionPrompt) - if lib-jitsi-meet should check
* for gUM permission prompt
* @returns {Promise<JitsiLocalTrack[]>} * @returns {Promise<JitsiLocalTrack[]>}
*/ */
function createLocalTracks (devices, cameraDeviceId, micDeviceId) { function createLocalTracks (options, checkForPermissionPrompt) {
return JitsiMeetJS.createLocalTracks({ options || (options = {});
// copy array to avoid mutations inside library
devices: devices.slice(0), return JitsiMeetJS
resolution: config.resolution, .createLocalTracks({
cameraDeviceId: typeof cameraDeviceId === 'undefined' // copy array to avoid mutations inside library
|| cameraDeviceId === null devices: options.devices.slice(0),
resolution: config.resolution,
cameraDeviceId: typeof options.cameraDeviceId === 'undefined' ||
options.cameraDeviceId === null
? APP.settings.getCameraDeviceId() ? APP.settings.getCameraDeviceId()
: cameraDeviceId, : options.cameraDeviceId,
micDeviceId: typeof micDeviceId === 'undefined' || micDeviceId === null micDeviceId: typeof options.micDeviceId === 'undefined' ||
? APP.settings.getMicDeviceId() options.micDeviceId === null
: micDeviceId, ? APP.settings.getMicDeviceId()
// adds any ff fake device settings if any : options.micDeviceId,
firefox_fake_device: config.firefox_fake_device // adds any ff fake device settings if any
}).catch(function (err) { firefox_fake_device: config.firefox_fake_device
console.error('failed to create local tracks', ...devices, err); }, checkForPermissionPrompt)
return Promise.reject(err); .catch(function (err) {
}); console.error(
} 'failed to create local tracks', options.devices, err);
return Promise.reject(err);
});
}
/** /**
* Changes the email for the local user * Changes the email for the local user
@ -861,7 +863,7 @@ export default {
this.videoSwitchInProgress = true; this.videoSwitchInProgress = true;
if (shareScreen) { if (shareScreen) {
createLocalTracks(['desktop']).then(([stream]) => { createLocalTracks({ devices: ['desktop'] }).then(([stream]) => {
stream.on( stream.on(
TrackEvents.LOCAL_TRACK_STOPPED, TrackEvents.LOCAL_TRACK_STOPPED,
() => { () => {
@ -918,7 +920,7 @@ export default {
APP.UI.messageHandler.openDialog(dialogTitle, dialogTxt, false); APP.UI.messageHandler.openDialog(dialogTitle, dialogTxt, false);
}); });
} else { } else {
createLocalTracks(['video']).then( createLocalTracks({ devices: ['video'] }).then(
([stream]) => this.useVideoStream(stream) ([stream]) => this.useVideoStream(stream)
).then(() => { ).then(() => {
this.videoSwitchInProgress = false; this.videoSwitchInProgress = false;
@ -1260,32 +1262,40 @@ export default {
APP.UI.addListener( APP.UI.addListener(
UIEvents.VIDEO_DEVICE_CHANGED, UIEvents.VIDEO_DEVICE_CHANGED,
(cameraDeviceId) => { (cameraDeviceId) => {
createLocalTracks(['video'], cameraDeviceId, null) createLocalTracks({
.then(([stream]) => { devices: ['video'],
this.useVideoStream(stream); cameraDeviceId: cameraDeviceId,
console.log('switched local video device'); micDeviceId: null
APP.settings.setCameraDeviceId(cameraDeviceId); })
}) .then(([stream]) => {
.catch((err) => { this.useVideoStream(stream);
APP.UI.showDeviceErrorDialog(null, err); console.log('switched local video device');
APP.UI.setSelectedCameraFromSettings(); APP.settings.setCameraDeviceId(cameraDeviceId);
}); })
.catch((err) => {
APP.UI.showDeviceErrorDialog(null, err);
APP.UI.setSelectedCameraFromSettings();
});
} }
); );
APP.UI.addListener( APP.UI.addListener(
UIEvents.AUDIO_DEVICE_CHANGED, UIEvents.AUDIO_DEVICE_CHANGED,
(micDeviceId) => { (micDeviceId) => {
createLocalTracks(['audio'], null, micDeviceId) createLocalTracks({
.then(([stream]) => { devices: ['audio'],
this.useAudioStream(stream); cameraDeviceId: null,
console.log('switched local audio device'); micDeviceId: micDeviceId
APP.settings.setMicDeviceId(micDeviceId); })
}) .then(([stream]) => {
.catch((err) => { this.useAudioStream(stream);
APP.UI.showDeviceErrorDialog(err, null); console.log('switched local audio device');
APP.UI.setSelectedMicFromSettings(); APP.settings.setMicDeviceId(micDeviceId);
}); })
.catch((err) => {
APP.UI.showDeviceErrorDialog(err, null);
APP.UI.setSelectedMicFromSettings();
});
} }
); );

@ -14,6 +14,7 @@
"userMedia": { "userMedia": {
"react-nativeGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button", "react-nativeGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button",
"chromeGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button", "chromeGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button",
"androidGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button",
"firefoxGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Share Selected Device</i> button", "firefoxGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Share Selected Device</i> button",
"operaGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button", "operaGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>Allow</i> button",
"iexplorerGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>OK</i> button", "iexplorerGrantPermissions": "Please grant permissions to use your camera and microphone by pressing <i>OK</i> button",

@ -1388,9 +1388,11 @@ UI.hideRingOverLay = function () {
/** /**
* Shows browser-specific overlay with guidance how to proceed with gUM prompt. * Shows browser-specific overlay with guidance how to proceed with gUM prompt.
* @param {string} browser - name of browser for which to show the guidance
* overlay.
*/ */
UI.showUserMediaPermissionsGuidanceOverlay = function () { UI.showUserMediaPermissionsGuidanceOverlay = function (browser) {
GumPermissionsOverlay.show(); GumPermissionsOverlay.show(browser);
}; };
/** /**

@ -5,11 +5,10 @@ let $overlay;
/** /**
* Internal function that constructs overlay with guidance how to proceed with * Internal function that constructs overlay with guidance how to proceed with
* gUM prompt. * gUM prompt.
* @param {string} browser - name of browser for which to construct the
* guidance overlay.
*/ */
function buildOverlayHtml() { function buildOverlayHtml(browser) {
let browser = JitsiMeetJS.environment.getBrowserType()
.split('rtc_browser.')[1] || 'chrome';
$overlay = $(` $overlay = $(`
<div class='overlay_container'> <div class='overlay_container'>
<div class='overlay overlay_transparent' /> <div class='overlay overlay_transparent' />
@ -28,11 +27,13 @@ export default {
/** /**
* Shows browser-specific overlay with guidance how to proceed with * Shows browser-specific overlay with guidance how to proceed with
* gUM prompt. * gUM prompt.
* @param {string} browser - name of browser for which to show the
* guidance overlay.
*/ */
show() { show(browser) {
!$overlay && buildOverlayHtml(); !$overlay && buildOverlayHtml(browser);
$overlay && $overlay.appendTo('body'); !$overlay.parents('body').length && $overlay.appendTo('body');
}, },
/** /**

@ -191,8 +191,11 @@ export default {
if (audioRequested && videoRequested) { if (audioRequested && videoRequested) {
// First we try to create both audio and video tracks together. // First we try to create both audio and video tracks together.
return createLocalTracks( return createLocalTracks({
['audio', 'video'], cameraDeviceId, micDeviceId) devices: ['audio', 'video'],
cameraDeviceId: cameraDeviceId,
micDeviceId: micDeviceId
})
// If we fail to do this, try to create them separately. // If we fail to do this, try to create them separately.
.catch(() => Promise.all( .catch(() => Promise.all(
[createAudioTrack(false), createVideoTrack(false)])) [createAudioTrack(false), createVideoTrack(false)]))
@ -213,7 +216,11 @@ export default {
} }
function createAudioTrack(showError) { function createAudioTrack(showError) {
return createLocalTracks(['audio'], null, micDeviceId) return createLocalTracks({
devices: ['audio'],
cameraDeviceId: null,
micDeviceId: micDeviceId
})
.catch(err => { .catch(err => {
audioTrackError = err; audioTrackError = err;
showError && APP.UI.showDeviceErrorDialog(err, null); showError && APP.UI.showDeviceErrorDialog(err, null);
@ -222,7 +229,11 @@ export default {
} }
function createVideoTrack(showError) { function createVideoTrack(showError) {
return createLocalTracks(['video'], cameraDeviceId, null) return createLocalTracks({
devices: ['video'],
cameraDeviceId: cameraDeviceId,
micDeviceId: null
})
.catch(err => { .catch(err => {
videoTrackError = err; videoTrackError = err;
showError && APP.UI.showDeviceErrorDialog(null, err); showError && APP.UI.showDeviceErrorDialog(null, err);

Loading…
Cancel
Save