Demander l’accès à la caméra et au microphone à l’aide de Azure Communication Services bibliothèque d’interface utilisateur
Important
Cette fonctionnalité d’Azure Communication Services est actuellement en préversion.
Ces interfaces de programmation d’applications et kits de développement logiciel (SDK) en préversion sont fournis sans contrat au niveau du service. Nous vous recommandons de ne pas les utiliser pour les charges de travail de production. Certaines fonctionnalités peuvent être limitées ou non prises en charge.
Pour plus d’informations, consultez Conditions d’utilisation supplémentaires relatives aux préversions de Microsoft Azure.
Ce didacticiel est la suite d’une série de trois didacticiels sur la préparation des appels et suit la précédente : Vérifier que l’utilisateur est sur un navigateur pris en charge.
Télécharger le code
Accédez au code complet de ce tutoriel sur GitHub.
Demande d’accès à la caméra et au microphone
Pour les applications appelantes, il est souvent essentiel qu’un utilisateur ait donné l’autorisation d’utiliser le microphone et la caméra. Dans cette section, nous créons une série de composants qui encouragent l’utilisateur à accorder l’accès à la caméra et au microphone. Nous affichons des invites à l’utilisateur pour le guider dans l’octroi de l’accès. Nous informons l’utilisateur à l’aide d’une invite si l’accès n’est pas accordé.
Création d’invites pour l’accès à la caméra et au microphone
Nous créons d’abord une série d’invites d’autorisations d’appareil pour amener les utilisateurs dans un état où ils ont accepté les autorisations de microphone et de caméra. Ces invites utilisent le composant CameraAndMicrophoneSitePermissions
de la bibliothèque d’interface utilisateur. À l’instar de l’invite Navigateur non pris en charge, nous hébergeons ces invites à l’intérieur d’un FluentUI modal
.
src/DevicePermissionPrompts.tsx
import { CameraAndMicrophoneSitePermissions } from '@azure/communication-react';
import { Modal } from '@fluentui/react';
/** Modal dialog that prompt the user to accept the Browser's device permission request. */
export const AcceptDevicePermissionRequestPrompt = (props: { isOpen: boolean }): JSX.Element => (
<PermissionsModal isOpen={props.isOpen} kind="request" />
);
/** Modal dialog that informs the user we are checking for device access. */
export const CheckingDeviceAccessPrompt = (props: { isOpen: boolean }): JSX.Element => (
<PermissionsModal isOpen={props.isOpen} kind="check" />
)
/** Modal dialog that informs the user they denied permission to the camera or microphone with corrective steps. */
export const PermissionsDeniedPrompt = (props: { isOpen: boolean }): JSX.Element => (
<PermissionsModal isOpen={props.isOpen} kind="denied" />
);
/** Base component utilized by the above prompts for better code separation. */
const PermissionsModal = (props: { isOpen: boolean, kind: "denied" | "request" | "check" }): JSX.Element => (
<Modal isOpen={props.isOpen}>
<CameraAndMicrophoneSitePermissions
appName={'this site'}
kind={props.kind}
onTroubleshootingClick={() => alert('This callback should be used to take the user to further troubleshooting')}
/>
</Modal>
);
Vérification de l’accès à la caméra et au microphone
Ici, nous ajoutons deux nouvelles fonctions utilitaires pour vérifier et demander l’accès à la caméra et au microphone. Créez un fichier appelé devicePermissionUtils.ts
avec deux fonctions checkDevicePermissionsState
et requestCameraAndMicrophonePermissions
.
checkDevicePermissionsState
utilise PermissionAPI. Toutefois, l’interrogation de la caméra et du microphone n’est pas prise en charge sur Firefox et nous nous assurons donc que cette méthode retourne unknown
dans ce cas. Plus tard, nous nous assurons de gérer le unknown
cas lorsque l’utilisateur demande des autorisations.
src/DevicePermissionUtils.ts
import { DeviceAccess } from "@azure/communication-calling";
import { StatefulCallClient } from "@azure/communication-react";
/**
* Check if the user needs to be prompted for camera and microphone permissions.
*
* @remarks
* The Permissions API we are using is not supported in Firefox, Android WebView or Safari < 16.
* In those cases this returns 'unknown'.
*/
export const checkDevicePermissionsState = async (): Promise<{camera: PermissionState, microphone: PermissionState} | 'unknown'> => {
try {
const [micPermissions, cameraPermissions] = await Promise.all([
navigator.permissions.query({ name: "microphone" as PermissionName }),
navigator.permissions.query({ name: "camera" as PermissionName })
]);
console.info('PermissionAPI results', [micPermissions, cameraPermissions]); // view console logs in the browser to see what the PermissionsAPI info is returned
return { camera: cameraPermissions.state, microphone: micPermissions.state };
} catch (e) {
console.warn("Permissions API unsupported", e);
return 'unknown';
}
}
/** Use the DeviceManager to request for permissions to access the camera and microphone. */
export const requestCameraAndMicrophonePermissions = async (callClient: StatefulCallClient): Promise<DeviceAccess> => {
const response = await (await callClient.getDeviceManager()).askDevicePermission({ audio: true, video: true });
console.info('AskDevicePermission response', response); // view console logs in the browser to see what device access info is returned
return response
}
Inviter l’utilisateur à accorder l’accès à la caméra et au microphone
Maintenant que nous disposons des invites et de la logique de vérification et de requête, nous créons un DeviceAccessComponent
pour inviter l’utilisateur à connaître les autorisations d’appareil.
Dans ce composant, nous affichons différentes invites à l’utilisateur en fonction de l’état d’autorisation de l’appareil :
- Si l’état de l’autorisation de l’appareil est inconnu, nous affichons une invite à l’utilisateur pour l’informer que nous vérifions les autorisations d’appareil.
- Si nous demandons des autorisations, nous affichons une invite à l’utilisateur pour l’encourager à accepter la requête d’autorisations.
- Si les autorisations sont refusées, nous affichons une invite à l’utilisateur pour l’informer qu’il a refusé les autorisations et qu’il doit accorder des autorisations pour continuer.
src/DeviceAccessChecksComponent.tsx
import { useEffect, useState } from 'react';
import { CheckingDeviceAccessPrompt, PermissionsDeniedPrompt, AcceptDevicePermissionRequestPrompt } from './DevicePermissionPrompts';
import { useCallClient } from '@azure/communication-react';
import { checkDevicePermissionsState, requestCameraAndMicrophonePermissions } from './DevicePermissionUtils';
export type DevicesAccessChecksState = 'runningDeviceAccessChecks' |
'checkingDeviceAccess' |
'promptingForDeviceAccess' |
'deniedDeviceAccess';
/**
* This component is a demo of how to use the StatefulCallClient with CallReadiness Components to get a user
* ready to join a call.
* This component checks the browser support and if camera and microphone permissions have been granted.
*/
export const DeviceAccessChecksComponent = (props: {
/**
* Callback triggered when the tests are complete and successful
*/
onTestsSuccessful: () => void
}): JSX.Element => {
const [currentCheckState, setCurrentCheckState] = useState<DevicesAccessChecksState>('runningDeviceAccessChecks');
// Run call readiness checks when component mounts
const callClient = useCallClient();
useEffect(() => {
const runDeviceAccessChecks = async (): Promise<void> => {
// First we check if we need to prompt the user for camera and microphone permissions.
// The prompt check only works if the browser supports the PermissionAPI for querying camera and microphone.
// In the event that is not supported, we show a more generic prompt to the user.
const devicePermissionState = await checkDevicePermissionsState();
if (devicePermissionState === 'unknown') {
// We don't know if we need to request camera and microphone permissions, so we'll show a generic prompt.
setCurrentCheckState('checkingDeviceAccess');
} else if (devicePermissionState.camera === 'prompt' || devicePermissionState.microphone === 'prompt') {
// We know we need to request camera and microphone permissions, so we'll show the prompt.
setCurrentCheckState('promptingForDeviceAccess');
}
// Now the user has an appropriate prompt, we can request camera and microphone permissions.
const devicePermissionsState = await requestCameraAndMicrophonePermissions(callClient);
if (!devicePermissionsState.audio || !devicePermissionsState.video) {
// If the user denied camera and microphone permissions, we prompt the user to take corrective action.
setCurrentCheckState('deniedDeviceAccess');
} else {
// Test finished successfully, trigger callback to parent component to take user to the next stage of the app.
props.onTestsSuccessful();
}
};
runDeviceAccessChecks();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<>
{/* We show this when we are prompting the user to accept device permissions */}
<AcceptDevicePermissionRequestPrompt isOpen={currentCheckState === 'promptingForDeviceAccess'} />
{/* We show this when the PermissionsAPI is not supported and we are checking what permissions the user has granted or denied */}
<CheckingDeviceAccessPrompt isOpen={currentCheckState === 'checkingDeviceAccess'} />
{/* We show this when the user has failed to grant camera and microphone access */}
<PermissionsDeniedPrompt isOpen={currentCheckState === 'deniedDeviceAccess'} />
</>
);
}
Une fois que nous avons terminé de créer ce composant, nous l’ajoutons à App.tsx
. Commencez par ajouter l’importation :
import { DeviceAccessChecksComponent } from './DeviceAccessChecksComponent';
Ensuite, mettez à jour le type TestingState
pour qu’il soit la valeur suivante :
type TestingState = 'runningEnvironmentChecks' | 'runningDeviceAccessChecks' | 'finished';
Enfin, mettez à jour le composant App
:
/**
* Entry point of a React app.
*
* This shows a PreparingYourSession component while the CallReadinessChecks are running.
* Once the CallReadinessChecks are finished, the TestComplete component is shown.
*/
const App = (): JSX.Element => {
const [testState, setTestState] = useState<TestingState>('runningEnvironmentChecks');
return (
<FluentThemeProvider>
<CallClientProvider callClient={callClient}>
{/* Show a Preparing your session screen while running the environment checks */}
{testState === 'runningEnvironmentChecks' && (
<>
<PreparingYourSession />
<EnvironmentChecksComponent onTestsSuccessful={() => setTestState('runningDeviceAccessChecks')} />
</>
)}
{/* Show a Preparing your session screen while running the device access checks */}
{testState === 'runningDeviceAccessChecks' && (
<>
<PreparingYourSession />
<DeviceAccessChecksComponent onTestsSuccessful={() => setTestState('finished')} />
</>
)}
{/* After the device setup is complete, take the user to the call. For this sample we show a test complete page. */}
{testState === 'finished' && <TestComplete />}
</CallClientProvider>
</FluentThemeProvider>
);
}
L’application présente à l’utilisateur des invites pour le guider dans l’accès à l’appareil :
Notes
Pour les tests, nous vous recommandons de visiter votre application en mode InPrivate/Incognito afin que les autorisations de caméra et de microphone n’aient pas été précédemment accordées pour localhost:3000
.