Auswählen von Kameras in JavaScript mit der mediaDevices-API

April 19, 2018
Autor:in:
Phil Nash
Twilion

Auswählen von Kameras in JavaScript mit der mediaDevices-API


Hallo und Danke fürs Lesen! Dieser Blogpost ist eine Übersetzung von Choosing cameras in JavaScript with the mediaDevices API. Während wir unsere Übersetzungsprozesse verbessern, würden wir uns über Dein Feedback an help@twilio.com freuen, solltest Du etwas bemerken, was falsch übersetzt wurde. Wir bedanken uns für hilfreiche Beiträge mit Twilio Swag :)

Die meisten Smartphones sind mit einer Vorder- und Rückkamera ausgestattet. Wenn du eine Videoanwendung für Mobilgeräte erstellst, möchtest du möglicherweise zwischen ihnen wählen oder zwischen ihnen wechseln.

Wenn du eine Chat-App erstellst, möchtest du wahrscheinlich die Frontkamera, aber wenn du eine Kamera-App erstellst, interessierst du dich mehr für die Rückkamera. In diesem Beitrag erfährst du, wie du mit der mediaDevices-API und Medieneinschränkungen die Kamera wählst oder zwischen Kameras wechseln kannst.

Das brauchen wir

Um diesem Beitrag folgen zu können, benötigst du:

  • ein iOS- oder Android-Gerät mit zwei Kameras zum Testen. Wenn du zwei Webcams hast, funktioniert dies auch auf deinem Laptop
  • ngrok, damit du einfach von deinem mobilen Gerät aus auf das Projekt zugreifen kannst (und weil ich denke, dass ngrok großartig ist)
  • den Code von diesem GitHub-Repo, um dir den Einstieg zu erleichtern

Um den Code zu erhalten, klonst du das Projekt und checkst den Starter-Projekt-Tag aus.

git clone https://github.com/philnash/mediadevices-camera-selection.git -b initial-project
cd mediadevices-camera-selection

Dieses Starterprojekt bietet dir HTML und CSS, damit wir uns auf das JavaScript konzentrieren können. Du kannst die Datei index.html direkt öffnen, aber ich empfehle dir, diese Dateien mit einem Webserver bereitzustellen. Ich benutze gern npm module serve. Ich habe auch Serve in das Repo aufgenommen, um es zu verwenden, installiere zuerst die Abhängigkeit mit npm und starte dann den Server.

npm install
npm start

Öffne nach dem Ausführen des Servers mit ngrok einen Tunnel dazu. serve hostet die Dateien auf Port 5000, um mit ngrok zu diesem Port zu tunneln, gib Folgendes in der Befehlszeile in ein neues Fenster ein:

ngrok http 5000

Jetzt hast du eine öffentlich verfügbare Version der Site, die du auf deinem mobilen Gerät öffnen kannst, um sie später zu testen. Stelle sicher, dass du die HTTPS-URL öffnest, da die von uns verwendeten APIs nur in einem sicheren Kontext ausgeführt werden.

Das ngrok Fenster zeigt zwei URLs, die du verwenden kannst. Wähle die Option mit HTTPS.

Die App sollte folgendermaßen aussehen:

Die App sollte eine Überschrift 'Camera fun' zeigen, mit einer Schaltfläche und einer leeren Dropdown-Box.

Abrufen des Medienstreams

Unsere erste Herausforderung besteht darin, den Videostream von jeder Kamera auf den Bildschirm zu bringen. Sobald dies abgeschlossen ist, werden wir die Optionen für die Auswahl der spezifischen Kamera untersuchen. Öffne app.js und wähle zunächst die Schaltfläche und die Videoelemente aus dem DOM aus:

// app.js
const video = document.getElementById('video');
const button = document.getElementById('button');

Wir werden den Zugriff auf die Kamera über die mediaDevices API anfordern, wenn der Benutzer auf die Schaltfläche klickt oder tippt. Dazu rufen wir navigator.mediaDevices.getUserMedia auf, zum Übergeben eines Objekts mit Medienbeschränkungen. Wir beginnen mit einer Reihe einfacher Einschränkungen. Wir möchten nur Video, also setzen wir Video auf true und Audio zu false.

getUserMedia gibt ein Promise zurück, wenn dies behoben ist, haben wir Zugriff auf einen Medienstream von der Kamera. Stelle das srcObj des Videos auf den Stream ein und wir werden es auf dem Bildschirm sehen.

button.addEventListener('click', event => {
  const constraints = {
    video: true,
    audio: false
  };
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(stream => {
      video.srcObject = stream;
    })
    .catch(error => {
      console.error(error);
    });
});

Speichere die Datei, lade die Seite neu und klicke auf die Schaltfläche. Du solltest ein Berechtigungsdialogfeld sehen, das den Zugriff auf deine Kamera anfordert. Sobald die Berechtigungen erteilt wurden, wird dein Video auf dem Bildschirm angezeigt. Probiere dies auf deinem Computer und deinem Telefon. Als ich es mit meinem iPhone versuchte, war die ausgewählte Kamera die nach vorne gerichtete Kamera.

Die Kamera-App, jetzt mit meinem Gesicht in dem Feld, das zuvor leer war!

Wenn du ein iPhone verwendest, stelle sicher, dass du in Safari eincheckst, da dies mit anderen Browsern anscheinend nicht funktioniert.

Welche Kameras sind verfügbar?

Die mediaDevices-API gibt uns die Möglichkeit, alle verfügbaren Geräte für die Audio- und Videoeingabe aufzulisten. Wir werden die enumerateDevices Funktion zum Aufbau einer Reihe von Optionen für eine Box verwenden, damit wir damit die Kamera auswählen können, die wir sehen möchten. Öffne app.js erneut und wähle zunächst die <select> aus dem DOM aus:

const video = document.getElementById('video');
const button = document.getElementById('button');
const select = document.getElementById('select');

enumerateDevices gibt ein Promise zurück. Schreiben wir also eine Funktion, mit der wir das Ergebnis des Promise erhalten können. Die Funktion verwendet eine Liste von Mediengeräten als Argument.

Das erste, was zu tun ist, ist <select> von vorhandenen Optionen zu leeren und eine leere <option> einzufügen. Dann durchlaufen wir die Geräte und filtern alle heraus, die nicht von der Art „videoinput“ sind. Wir erstellen dann eine <option> mit der Geräte-ID als Wert und der Gerätebezeichnung für den Text. Wir behandeln auch den Fall, dass ein Gerät keine Bezeichnung meldet, indem wir eine einfache „Camera n“-Bezeichnung generieren.

const video = document.getElementById('video');
const button = document.getElementById('button');
const select = document.getElementById('select');

function gotDevices(mediaDevices) {
  select.innerHTML = '';
  select.appendChild(document.createElement('option'));
  let count = 1;
  mediaDevices.forEach(mediaDevice => {
    if (mediaDevice.kind === 'videoinput') {
      const option = document.createElement('option');
      option.value = mediaDevice.deviceId;
      const label = mediaDevice.label || `Camera ${count++}`;
      const textNode = document.createTextNode(label);
      option.appendChild(textNode);
      select.appendChild(option);
    }
  });
}

Am Ende von app.js rufst du enumerateDevices auf.

navigator.mediaDevices.enumerateDevices().then(gotDevices);

Aktualisiere die Seite und sieh dir die Dropdown-Auswahl neben der Schaltfläche an. Wenn du mit Android arbeitest oder Chrome oder Firefox verwendest, wird der Name der verfügbaren Kameras angezeigt.

Auf einem iPhone siehst du jedoch die generischen Namen „Camera 1“ und „Camera 2“ aus unserer Funktion. Unter iOS erhältst du die Bezeichnungen der Kameras erst, wenn du der Site die Berechtigung erteilt hast, mindestens eine der Kameras zu verwenden. Dies macht unsere Benutzeroberfläche für die Auswahl einer Kamera weniger nützlich, da du, obwohl du die ID der Geräte erhältst, nicht erkennen kannst, welche Kamera welche ist.

Auf dem iPhone kannst du nur die Bezeichnungen sehen, die wir erstellt haben, &#x27;Camera 1&#x27; und &#x27;Camera 2&#x27;.

Wir haben die Dropdown-Auswahl zum Wechseln der Kamera noch nicht verbunden. Bevor wir dies tun, schauen wir uns einen anderen Weg an, wie wir beeinflussen können, welche Kamera wir auswählen möchten.

Facing-Modus

Ein alternativer Ansatz, mit dem wir eine Kamera auswählen können, ist die facingMode-Beschränkung. Dies ist eine weniger genaue Methode, um eine Kamera auszuwählen, als ihre ID von der enumerateDevices-Funktion zu erhalten, funktioniert aber sehr gut für mobile Geräte. Es gibt vier Optionen, die du für die Einschränkung verwenden kannst: userenvironmentleft und right. Das Einschränkungen werden in der MDN-Dokumentation erläutert, für die Zwecke dieses Beitrags werden wir user und environment verwenden, da sie sich gut auf nach vorne und hinten gerichtete Kameras auf einem mobilen Gerät abbilden lassen.

Um die facingMode Einschränkung zu verwenden, müssen wir die Einschränkungen ändern, die wir in unserem Aufruf an getUserMedia verwenden. Anstatt nur true in Bezug auf video zu sagen, brauchen wir ein Objekt dieser Einschränkungen. Aktualisiere den Code, um die nach vorne gerichtete Kamera wie folgt auszuwählen:

button.addEventListener('click', event => {
  const videoConstraints = {
    facingMode: 'user'
  };
  const constraints = {
    video: videoConstraints,
    audio: false
  };

Teste jetzt von deinem mobilen Gerät aus. Du solltest feststellen, dass die nach vorne gerichtete Kamera ausgewählt ist. Aktualisiere den facingMode auf environment und versuche es erneut. Nun sollte die nach hinten gerichtete Kamera ausgewählt sein.

Lass uns diesen Code mit den Ergebnissen zusammenfügen, die wir von enumerateDevices oben erhalten haben, um einen Kameraumschalter zu erstellen, sobald wir die Erlaubnis zum Lesen der Kameradaten haben.

Kameras wechseln

Wir haben den Code, um bei der ersten Auswahl eine Benutzer- oder eine Umgebungskamera auszuwählen, aber wenn wir die Kamera wechseln möchten, müssen wir noch etwas mehr tun.

Zunächst sollten wir einen Verweis auf den aktuellen Stream beibehalten, damit wir ihn stoppen können, wenn wir zu einem anderen wechseln. Füge eine weitere Variable und eine Utility-Funktion oben in app.js hinzu, um die Tracks in einem Stream zu stoppen.

const video = document.getElementById('video');
const button = document.getElementById('button');
const select = document.getElementById('select');
let currentStream;

function stopMediaTracks(stream) {
  stream.getTracks().forEach(track => {
    track.stop();
  });
}

Die Funktion stopMediaTracks nimmt einen Stream und durchläuft jeden Medientrack im Stream, wobei jeder von ihnen gestoppt wird.

Wir werden die Kameras wechseln, wenn wir dieselbe Taste drücken, daher müssen wir den Ereignis-Listener aktualisieren. Zunächst sollten wir, wenn wir einen currentStream haben, diesen stoppen. Dann werden wir <select>, überprüfen um zu sehen, ob wir ein bestimmtes Gerät auswählen und die darauf basierenden Videoeinschränkungen aufbauen.

Aktualisiere den Click-Handler der Schaltfläche und die Videoeinschränkungen wie folgt:

button.addEventListener('click', event => {
  if (typeof currentStream !== 'undefined') {
    stopMediaTracks(currentStream);
  }
  const videoConstraints = {};
  if (select.value === '') {
    videoConstraints.facingMode = 'environment';
  } else {
    videoConstraints.deviceId = { exact: select.value };
  }
  const constraints = {
    video: videoConstraints,
    audio: false
  };

Wenn wir ein Gerät anhand seiner Geräte-ID auswählen möchten, verwenden wir die Einschränkung exact. Wir vermeiden das jedoch für die Einschränkung facingMode, da dies auf einem Gerät fehlschlagen kann, das nicht erkennt, dass ein „Benutzer“- oder „Umgebungs“-Modus vorliegt, so dass wir dann überhaupt keine Medien mehr haben.

Wenn wir im Click-Handler die Erlaubnis zur Verwendung des Videos erhalten, werden wir noch einige Dinge ändern. Stelle die currentStream an den neuen Stream, der an die Funktion übergeben wurde, damit wir ihn später stoppen und einen weiteren Aufruf an enumerateDevices auslösen können.

enumerateDevices gibt ein Promise zurück, damit wir es von unserer then-Funktion zurückgeben können und ein neues then für das Ergebnis verketten, das dann von unserer gotDevices-Funktion verarbeitet wird.

Ersetze deinen bestehenden Aufruf an getUserMedia mit dem folgenden:

button.addEventListener('click', event => {
  if (typeof currentStream !== 'undefined') {
    stopMediaTracks(currentStream);
  }
  const videoConstraints = {};
  if (select.value === '') {
    videoConstraints.facingMode = 'environment';
  } else {
    videoConstraints.deviceId = { exact: select.value };
  }
  const constraints = {
    video: videoConstraints,
    audio: false
  };

  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(stream => {
      currentStream = stream;
      video.srcObject = stream;
      return navigator.mediaDevices.enumerateDevices();
    })
    .then(gotDevices)
    .catch(error => {
      console.error(error);
    });
});

Wenn du den gesamten Code hinzugefügt hast, sollte deine app.js so aussehen, wie diese vervollständigte. Aktualisiere die Seite und du kannst Kameras auswählen und ändern. Dies funktioniert sowohl auf Mobilgeräten als auch auf Desktops.

Das fertige Ergebnis. Dies ist eine Animation, die zeigt, dass du eine Kamera wählen kannst und dann auch von der Anzeige der hinteren Kamera auf die vordere Kamera wechseln kannst.

Nächste Schritte

Wir haben gesehen, wie man die Kamera eines Benutzers mit der facingMode- oder deviceID-Einschränkung auswählt. Denk daran, facingMode ist zuverlässiger, bevor du die Berechtigung zur Verwendung der Kamera hast, aber das Auswählen einer deviceID ist genauer. Du kannst den gesamte Code aus diesem Blog-Beitrag im GitHub-Repo bekommen und die Anwendung hier live ausprobieren.

Wenn du Twilio Video verwendest, um eine Videoanwendung zu erstellen, kannst du diese Einschränkungen beim Aufrufen von connect oder createLocalVideoTrack verwenden.

Das Auswählen oder Wechseln von Kameras ist eine nützliche Funktion für den Video-Chat, mit der Benutzer genau die Kamera auswählen können, die sie in der Benutzeroberfläche deiner Anwendung verwenden möchten. Dies kann Hand in Hand gehen mit dem Teilen deines Bildschirms, auch während eines Videoanrufs.

Gibt es andere Videofunktionen, die du gerne sehen würdest und die in Video-Chats nützlich wären? Oder Fragen zu dieser Funktion? Lass es mich in den Kommentaren oder auf Twitter unter @philnash wissen.