WebRTCの動作と実装(.socket.ioを介して)


Introduction



Peer A:元のユーザー(新しいユーザーが部屋に入ったら通知を受け取る)
Peer B:新規ユーザ
文書:https://developer.mozilla.org/ko/docs/Web/API/WebRTC_API/Signaling_and_video_calling

1. Offers (Peer A)


1)ビデオ取得-getUserMedia()

const myFace = document.getElementById("myFace")

// 방 입장하기 클릭 시 startMedia 함수 호출
function handleWelcomeSubmit(event) {
  event.preventDefault();
  const input = welcomeForm.querySelector("input");
  socket.emit("join_room", input.value, startMedia);
  input.value = "";
}

// 방 입자 화면 hidden, 화상화면 display
await function initCall() {
  welcome.hidden = true;
  call.hidden = false;
  await getMedia();
};

// 화상화면 가져오기
let constraints = {
  audio: true,
  video: {
    width: { min: 1024, ideal: 1280, max: 1920 },
    height: { min: 776, ideal: 720, max: 1080 }
  }
}

let myStream;

async function getMedia() {
  let constraints = {
    audio: true,
    video: {
      width: { min: 1024, ideal: 1280, max: 1920 },
      height: { min: 776, ideal: 720, max: 1080 }
    }
  }
  try {
    myStream = await navigator.mediaDevices.getUserMedia(constraints);
    myFace.srcObject = stream
  } catch(err) {
    console.log(err);
  }
}

2)ピア接続の作成+ストリームの追加-addStream()


新しく部屋に入ったすべてのユーザー(最初のユーザーとその後のすべてのユーザーを含む)
  • PeerConnectionを作成し、独自のビデオとオーディオ
  • を含む
    // 어디서든 PeerConnection을 가져오기 위해 선언
    let myPeerConnection;
    
    // 서버에 연결되었을 때 RTC 연결을 만들어 주기 위해 startMedia 함수 안에서 호출
    async function initCall() {
      welcome.hidden = true;
      call.hidden = false;
      await getMedia();
      // 연결 설정 함수 호출
      makeConnection();
    }
    
    // 새로 방에 연결되는 모든 사용자
    function makeConnection() {
      myPeerConnection = new RTCPeerConnection();
      myStream
        .getTracks()
        .forEach((track) => myPeerConnection.addTrack(track, myStream));
    }

    3)Offer-createOffer()の作成


    既存のユーザ(Peer A)に独自のフローを含むPeerConnectionによって見積書を作成します.
    生成された見積書を記述形式に変換します.
    変更された見積書をサーバに送信
    // Only Peer A
    socket.on("welcome", async () => {
      const offer = await myPeerConnection.createOffer();
      myPeerConnection.setLocalDescription(offer);
      socket.emit("offer", offer, roomName);
    })
    見積情報を受信したサーバは、見積要求をユーザーに送信します.
    // To Peer B
    socket.on("offer", (offer, roomName) => {
      socket.to(roomName).emit("offer", offer);
    })

    2. Answers (Peer B)


    1) setRemoteDescription()


    Peer Bで自分のPeerConnectionにPeer Aを設定する説明
    // Only Peer B
    socket.on("offer", (offer) => {
      myPeerConnection.setRemoteDescription(offer);
    })
    上のコードは論理的に正しいが、エラーが発生した.
    =Webソケットの速度は、メディアのインポートやPerConnectionの作成よりも速い==
    これにより、実行順序がメディアのインポートに変更され、接続が作成され、次のサーバに通知されます.

  • 既存のコード
    function handleWelcomeSubmit(event) {
      event.preventDefault();
      const input = welcomeForm.querySelector("input");
      // 서버에 startMedia 함수 보내고 서버에서 실행
      socket.emit("join_room", input.value, startMedia);
      input.value = "";
    }

  • 置換コード
    async function handleWelcomeSubmit(event) {
      event.preventDefault();
      const input = welcomeForm.querySelector("input");
      // 1. Media를 가져온다 (Conncetion 함수 포함되어 있음)
      await startMedia();
      // 2. 서버에 참가 알림
      socket.emit("join_room", input.value);
      input.value = "";
    }
  • 2) createAnswer()


    Peer Bによって答えが作成され、サーバに送信されます.
    // Only Peer B
    socket.on("offer", async (offer) => {
      myPeerConnection.setRemoteDescription(offer);
      const answer = await myPeerConnection.createAnswer();
      myPeerConnection.setLocalDescription(answer);
      socket.emit("answer", answer, roomName);
    });
    socket.on("answer", (answer, roomName) => {  socket.to(roomName).emit("answer", answer);});
    文書:https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Build_a_phone_with_peerjs/Connect_peers/Answer_a_call

    3. IceCandidate


    ICE Candidateは、RTCPEER接続を作成する際に使用できるICE候補です.
    ICE候補者は、WebRTCがリモートデバイスと通信するために必要なプロトコルおよびルーティングを記述する.WebRTCピア接続を開始すると、通常、決定された接続が一致するまで、接続の各エンドポイントによって推奨される候補接続が多くなります.その後、WebRTCは候補者の詳細を使用して接続を開始する.

    1)Ice Candidateイベントの傍受

    // 연결을 만들 때 event listenfunction makeConnection() {  myPeerConnection = new RTCPeerConnection();  // Ice candidate event listen  myPeerConnection.addEventListener("icecandidate", handleIce);  myStream    .getTracks()    .forEach((track) => myPeerConnection.addTrack(track, myStream));}function handleIce(data) {  socket.emit("ice", data.candidate, roomName);}
    socket.on("ice", (ice, roomName) => {  socket.to(roomName).emit("ice", ice);});

    2) addICECandidate()

    socket.on("ice", (ice) => {  console.log("received candidate");  myPeerConnection.addIceCandidate(ice);});

    3)addStreamイベントの傍受

    // 연결을 만들 때 event listenfunction makeConnection() {  myPeerConnection = new RTCPeerConnection();  myPeerConnection.addEventListener("icecandidate", handleIce);  // addStream event event listen  myPeerConnection.addEventListener("addstream", handleAddStream);  myStream    .getTracks()    .forEach((track) => myPeerConnection.addTrack(track, myStream));}function handleAddStream(data) {  const peerFace = document.getElementById("peerFace");  peerFace.srcObject = data.stream;}
    文書:https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate