Anfordern des Kamera- und Mikrofonzugriffs mithilfe der Azure Communication Services UI Library

Wichtig

Dieses Feature von Azure Communication Services befindet sich derzeit in der Vorschau. Features in der Vorschau sind öffentlich verfügbar und können von allen neuen und vorhandenen Microsoft-Kunden verwendet werden.

Vorschau-APIs und -SDKs werden ohne Vereinbarung zum Servicelevel bereitgestellt. Es wird empfohlen, diese nicht für Produktionsworkloads zu verwenden. Bestimmte Features werden möglicherweise nicht unterstützt oder Funktionen sind eingeschränkt.

Weitere Informationen finden Sie unter Zusätzliche Nutzungsbestimmungen für Microsoft Azure-Vorschauen.

Dieses Lernprogramm ist eine Fortsetzung einer dreiteiligen Reihe von Lernprogrammen zur Anrufbereitschaft und folgt aus dem vorherigen: Stellen Sie sicher, dass sich der Benutzer in einem unterstützten Browser befindet.

Code herunterladen

Greifen Sie auf den vollständigen Quellcode für dieses Tutorial auf GitHub zu.

Anfordern des Zugriffs auf die Kamera und das Mikrofon

Bei Anrufanwendungen ist es häufig unbedingt erforderlich, dass Benutzende die Verwendung von Mikrofon und Kamera zulassen. In diesem Abschnitt erstellen wir eine Reihe von Komponenten, die den Benutzer auffordern, Zugriff auf die Kamera und das Mikrofon zu gewähren. Wir zeigen Benutzenden Aufforderungen an, um sie durch das Gewähren des Zugriffs zu leiten. Wir informieren den Benutzer mit einer Eingabeaufforderung, wenn der Zugriff nicht gewährt wird.

Erstellen von Eingabeaufforderungen für den Kamera- und Mikrofonzugriff

Wir erstellen zunächst eine Reihe von Geräteberechtigungsaufforderungen, um Benutzer in einen Zustand zu versetzen, in dem sie die Mikrofon- und Kameraberechtigungen akzeptiert haben. Diese Eingabeaufforderungen verwenden die CameraAndMicrophoneSitePermissions Komponente aus der Ui-Bibliothek. Genauso wie bei der Aufforderung wegen eines nicht unterstützten Browsers hosten wir diese Aufforderungen in einem FluentUI-modal-Element.

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>
);

Überprüfen des Kamera- und Mikrofonzugriffs

Hier fügen wir zwei neue Hilfsfunktionen hinzu, um den Kamera- und Mikrofonzugriff zu überprüfen und anzufordern. Erstellen Sie eine Datei namens devicePermissionUtils.ts mit den beiden Funktionen checkDevicePermissionsState und requestCameraAndMicrophonePermissions. checkDevicePermissionsState verwendet die PermissionAPI. Die Abfrage nach Kamera und Mikrofon wird jedoch in Firefox nicht unterstützt, daher stellen wir sicher, dass diese Methode in diesem Fall zurückgegeben wird unknown . Später stellen wir sicher, dass der unknown-Fall verarbeitet wird, wenn die Benutzenden zur Eingabe von Berechtigungen aufgefordert werden.

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
}

Auffordern des Benutzers, Zugriff auf die Kamera und das Mikrofon zu gewähren

Jetzt verfügen wir über die Aufforderungen und die Überprüfungs- und Anforderungslogik. Als Nächstes erstellen wir ein DeviceAccessComponent-Element, um Benutzende bezüglich der Geräteberechtigungen aufzufordern. In dieser Komponente zeigen wir dem Benutzer unterschiedliche Eingabeaufforderungen basierend auf dem Geräteberechtigungsstatus an:

  • Wenn der Geräteberechtigungsstatus unbekannt ist, wird dem Benutzer eine Eingabeaufforderung angezeigt, die sie darüber informiert, dass wir auf Geräteberechtigungen überprüfen.
  • Wenn wir Berechtigungen anfordern, wird dem Benutzer eine Eingabeaufforderung angezeigt, die den Benutzer ermutigt, die Berechtigungsanforderung zu akzeptieren.
  • Wenn die Berechtigungen abgelehnt werden, wird den Benutzenden eine Aufforderung angezeigt, in der sie darüber informiert werden, dass sie Berechtigungen verweigert haben, diese aber erteilen müssen, um fortzufahren.

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'} />
    </>
  );
}

Nachdem wir die Erstellung dieser Komponente abgeschlossen haben, fügen wir sie der App.tsxDatei hinzu. Fügen Sie zuerst den Import hinzu:

import { DeviceAccessChecksComponent } from './DeviceAccessChecksComponent';

Aktualisieren Sie dann den TestingState Typ so, dass er der folgende Wert ist:

type TestingState = 'runningEnvironmentChecks' | 'runningDeviceAccessChecks' | 'finished';

Aktualisieren Sie schließlich die App Komponente:

/**
 * 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>
  );
}

Die App zeigt Benutzenden Aufforderungen an, um sie durch den Gerätezugriff zu leiten:

GIF, in dem der Benutzer zur Eingabe des Kamera- und Mikrofonzugriffs aufgefordert wird

Hinweis

Zum Testen empfehlen wir, Ihre App im InPrivate-/Inkognito-Modus zu öffnen, um sicherzustellen, dass localhost:3000 vorher keine Kamera- und Mikrofonberechtigungen erteilt wurden.

Nächste Schritte