Как переключить камеру Front и Back WebRT C с Firebase / Firestore? - PullRequest
0 голосов
/ 05 августа 2020

Я разработал веб-приложение, в котором звонящий и получатель имеют элементы управления видео и аудио. В моем случае должна быть возможность переключить камеру для мобильных пользователей и изменить голос с динамика на внутриканальный динамик.

Я загрузил его на хостинг Firebase, и у меня возникла проблема с подключением двух пользователей в один комнату и во время потока, как я могу переключить камеру и микрофон. ?

Спасибо

Приложение. js

   mdc.ripple.MDCRipple.attachTo(document.querySelector('.mdc-button'));

// DEfault configuration - Change these if you have a different STUN or TURN server.
const configuration = {
  iceServers: [
    {
      urls: [
        'stun:stun1.l.google.com:19302',
        'stun:stun2.l.google.com:19302',
      ],
    },
  ],
  iceCandidatePoolSize: 10,
};

let peerConnection = null;
let localStream = null;
let remoteStream = null;
let roomDialog = null;
let roomId = null;

function init() {
  document.querySelector('#cameraBtn').addEventListener('click', openUserMedia);
  document.querySelector('#hangupBtn').addEventListener('click', hangUp);
  document.querySelector('#createBtn').addEventListener('click', createRoom);
  document.querySelector('#joinBtn').addEventListener('click', joinRoom);
  roomDialog = new mdc.dialog.MDCDialog(document.querySelector('#room-dialog'));
}

async function createRoom() {
  document.querySelector('#createBtn').disabled = true;
  document.querySelector('#joinBtn').disabled = true;
  const db = firebase.firestore();

  console.log('Create PeerConnection with configuration: ', configuration);
  peerConnection = new RTCPeerConnection(configuration);

  registerPeerConnectionListeners();

  // Add code for creating a room here
  
  // Code for creating room above
  
  localStream.getTracks().forEach(track => {
    peerConnection.addTrack(track, localStream);
  });

  // Code for creating a room below

  // Code for creating a room above

  // Code for collecting ICE candidates below

  // Code for collecting ICE candidates above

  peerConnection.addEventListener('track', event => {
    console.log('Got remote track:', event.streams[0]);
    event.streams[0].getTracks().forEach(track => {
      console.log('Add a track to the remoteStream:', track);
      remoteStream.addTrack(track);
    });
  });

  // Listening for remote session description below

  // Listening for remote session description above

  // Listen for remote ICE candidates below

  // Listen for remote ICE candidates above
}

function joinRoom() {
  document.querySelector('#createBtn').disabled = true;
  document.querySelector('#joinBtn').disabled = true;

  document.querySelector('#confirmJoinBtn').
      addEventListener('click', async () => {
        roomId = document.querySelector('#room-id').value;
        console.log('Join room: ', roomId);
        document.querySelector(
            '#currentRoom').innerText = `Current room is ${roomId} - You are the callee!`;
        await joinRoomById(roomId);
      }, {once: true});
  roomDialog.open();
}

async function joinRoomById(roomId) {
  const db = firebase.firestore();
  const roomRef = db.collection('rooms').doc(`${roomId}`);
  const roomSnapshot = await roomRef.get();
  console.log('Got room:', roomSnapshot.exists);

  if (roomSnapshot.exists) {
    console.log('Create PeerConnection with configuration: ', configuration);
    peerConnection = new RTCPeerConnection(configuration);
    registerPeerConnectionListeners();
    localStream.getTracks().forEach(track => {
      peerConnection.addTrack(track, localStream);
    });

    // Code for collecting ICE candidates below

    // Code for collecting ICE candidates above

    peerConnection.addEventListener('track', event => {
      console.log('Got remote track:', event.streams[0]);
      event.streams[0].getTracks().forEach(track => {
        console.log('Add a track to the remoteStream:', track);
        remoteStream.addTrack(track);
      });
    });

    // Code for creating SDP answer below

    // Code for creating SDP answer above

    // Listening for remote ICE candidates below

    // Listening for remote ICE candidates above
  }
}

async function openUserMedia(e) {
  const stream = await navigator.mediaDevices.getUserMedia(
      {video: true, audio: true});
  document.querySelector('#localVideo').srcObject = stream;
  localStream = stream;
  remoteStream = new MediaStream();
  document.querySelector('#remoteVideo').srcObject = remoteStream;

  console.log('Stream:', document.querySelector('#localVideo').srcObject);
  document.querySelector('#cameraBtn').disabled = true;
  document.querySelector('#joinBtn').disabled = false;
  document.querySelector('#createBtn').disabled = false;
  document.querySelector('#hangupBtn').disabled = false;
}

async function hangUp(e) {
  const tracks = document.querySelector('#localVideo').srcObject.getTracks();
  tracks.forEach(track => {
    track.stop();
  });

  if (remoteStream) {
    remoteStream.getTracks().forEach(track => track.stop());
  }

  if (peerConnection) {
    peerConnection.close();
  }

  document.querySelector('#localVideo').srcObject = null;
  document.querySelector('#remoteVideo').srcObject = null;
  document.querySelector('#cameraBtn').disabled = false;
  document.querySelector('#joinBtn').disabled = true;
  document.querySelector('#createBtn').disabled = true;
  document.querySelector('#hangupBtn').disabled = true;
  document.querySelector('#currentRoom').innerText = '';

  // Delete room on hangup
  if (roomId) {
    const db = firebase.firestore();
    const roomRef = db.collection('rooms').doc(roomId);
    const calleeCandidates = await roomRef.collection('calleeCandidates').get();
    calleeCandidates.forEach(async candidate => {
      await candidate.delete();
    });
    const callerCandidates = await roomRef.collection('callerCandidates').get();
    callerCandidates.forEach(async candidate => {
      await candidate.delete();
    });
    await roomRef.delete();
  }

  document.location.reload(true);
}

function registerPeerConnectionListeners() {
  peerConnection.addEventListener('icegatheringstatechange', () => {
    console.log(
        `ICE gathering state changed: ${peerConnection.iceGatheringState}`);
  });

  peerConnection.addEventListener('connectionstatechange', () => {
    console.log(`Connection state change: ${peerConnection.connectionState}`);
  });

  peerConnection.addEventListener('signalingstatechange', () => {
    console.log(`Signaling state change: ${peerConnection.signalingState}`);
  });

  peerConnection.addEventListener('iceconnectionstatechange ', () => {
    console.log(
        `ICE connection state change: ${peerConnection.iceConnectionState}`);
  });
}

init();

Приложение. html

   <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Welcome to FirebaseRTC</title>
    <link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
    <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

    <!-- update the version number as needed -->
    <script defer src="/__/firebase/7.13.1/firebase-app.js"></script>
    <!-- include only the Firebase features as you need -->
    <script defer src="/__/firebase/7.13.1/firebase-firestore.js"></script>
    <!-- initialize the SDK after all desired features are loaded -->
    <script defer src="/__/firebase/init.js"></script>

    <link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<h1>Welcome to FirebaseRTC!</h1>
<div id="buttons">
    <button class="mdc-button mdc-button--raised" id="cameraBtn">
        <i class="material-icons mdc-button__icon" aria-hidden="true">perm_camera_mic</i>
        <span class="mdc-button__label">Open camera & microphone</span>
    </button>
    <button class="mdc-button mdc-button--raised" disabled id="createBtn">
        <i class="material-icons mdc-button__icon" aria-hidden="true">group_add</i>
        <span class="mdc-button__label">Create room</span>
    </button>
    <button class="mdc-button mdc-button--raised" disabled id="joinBtn">
        <i class="material-icons mdc-button__icon" aria-hidden="true">group</i>
        <span class="mdc-button__label">Join room</span>
    </button>
    <button class="mdc-button mdc-button--raised" disabled id="hangupBtn">
        <i class="material-icons mdc-button__icon" aria-hidden="true">close</i>
        <span class="mdc-button__label">Hangup</span>
    </button>
</div>
<div>
    <span id="currentRoom"></span>
</div>
<div id="videos">
    <video id="localVideo" muted autoplay playsinline></video>
    <video id="remoteVideo" autoplay playsinline></video>
</div>
<div class="mdc-dialog"
     id="room-dialog"
     role="alertdialog"
     aria-modal="true"
     aria-labelledby="my-dialog-title"
     aria-describedby="my-dialog-content">
    <div class="mdc-dialog__container">
        <div class="mdc-dialog__surface">
            <h2 class="mdc-dialog__title" id="my-dialog-title">Join room</h2>
            <div class="mdc-dialog__content" id="my-dialog-content">
                Enter ID for room to join:
                <div class="mdc-text-field">
                    <input type="text" id="room-id" class="mdc-text-field__input">
                    <label class="mdc-floating-label" for="my-text-field">Room ID</label>
                    <div class="mdc-line-ripple"></div>
                </div>
            </div>
            <footer class="mdc-dialog__actions">
                <button type="button" class="mdc-button mdc-dialog__button" data-mdc-dialog-action="no">
                    <span class="mdc-button__label">Cancel</span>
                </button>
                <button id="confirmJoinBtn" type="button" class="mdc-button mdc-dialog__button"
                        data-mdc-dialog-action="yes">
                    <span class="mdc-button__label">Join</span>
                </button>
            </footer>
        </div>
    </div>
    <div class="mdc-dialog__scrim"></div>
</div>
<script src="app.js"></script>
</body>
</html>

Прил. CSS

body {
    background: #ECEFF1;
    color: rgba(0, 0, 0, 0.87);
    font-family: Roboto, Helvetica, Arial, sans-serif;
    margin: 0;
    padding: 0;
}

#message {
    background: white;
    max-width: 360px;
    margin: 100px auto 16px;
    padding: 32px 24px;
    border-radius: 3px;
}

#message h2 {
    color: #ffa100;
    font-weight: bold;
    font-size: 16px;
    margin: 0 0 8px;
}

#message h1 {
    font-size: 22px;
    font-weight: 300;
    color: rgba(0, 0, 0, 0.6);
    margin: 0 0 16px;
}

#message p {
    line-height: 140%;
    margin: 16px 0 24px;
    font-size: 14px;
}

#message a {
    display: block;
    text-align: center;
    background: #039be5;
    text-transform: uppercase;
    text-decoration: none;
    color: white;
    padding: 16px;
    border-radius: 4px;
}

#message, #message a {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}

#load {
    color: rgba(0, 0, 0, 0.4);
    text-align: center;
    font-size: 13px;
}

@media (max-width: 600px) {
    body, #message {
        margin-top: 0;
        background: white;
        box-shadow: none;
    }

    body {
        border-top: 16px solid #ffa100;
    }
}

body {
    margin: 1em;
}

button {
    margin: 0.2em 0.1em;
}

div#videos {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
}

div#videos > video {
    background: black;
    width: 640px;
    height: 100%;
    display: block;
    margin: 1em;
}
...