Как добавить видеопоток с подключением WebRT C от другого партнера? - PullRequest
0 голосов
/ 22 января 2020

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

Кажется, что соединение установлено успешно, и сообщения успешно передаются через сокеты, и в консоли не отображаются ошибки. Чего мне не хватает?

лог c - это: - Пользователь1 входит в комнату

  • Пользователь2 входит в комнату

  • Пользователь1 отправляет сообщение Пользователю2 через сокеты

  • Пользователь1 нажимает «вызов» для вызова Пользователя2, получает локальный носитель и запускает WebRT C соединение

  • Пользователь2 нажимает «ответить», чтобы принять вызов от Пользователя2, принимает предложение и отвечает своим локальным носителем

Редактировать 1: Кажется, работает, если шаги выполняются в следующем порядке:

  • Пользователь1 входит в комнату

  • Пользователь1 нажимает «вызов» для вызова Пользователя2, получает локальный носитель и запускает WebRT C соединение

  • Пользователь2 входит в комнату

  • Пользователь2 нажимает «ответить», чтобы принять вызов от Пользователя2, принимает предложение и отвечает с его локальным носителем

  • Пользователь1 нажимает «ответить»

Я не совсем понимаю, почему это работает. «p c .ontrack» запускается только в указанном порядке c, и почему я могу установить соединение WebRT C до того, как второй узел войдет в комнату?

комната. html:

<!-- chat/templates/chat/room.html -->
<!DOCTYPE html>
{% load static %}
{% extends 'main/header.html' %}

{% block content %}

<body>

<div class="container">
    <a class="waves-effect waves-light btn prefix" id='call'>call</a>
    <a class="waves-effect waves-light btn prefix" id='respond'>respond</a>
  <div class="copy">Send your URL to a friend to start a video call</div>
  <video id="localVideo" autoplay muted></video>
  <video id="remoteVideo" autoplay></video>
    <textarea id="chat-log"  class="materialize-textarea" ></textarea><br/>

<div class="input-field col s12 ">
    <input id="chat-message-input" type="text" />
    <a class="waves-effect waves-light btn prefix" id="chat-message-submit"><i class="material-icons right">send</i></a>

</div>

</div>

</body>
<script>src = "{% static 'main/js/client.js' %}"></script>
{% endblock  %}

клиент. js:

// Generate random room name if needed

var roomName = "{{ room_name|escapejs }}";
var drone = new WebSocket(
        'ws://' + window.location.host +
        '/ws/chat/' + roomName + '/');


const configuration = {
  iceServers: [{
    urls: 'stun:stun.l.google.com:19302'
  }]
};

pc = new RTCPeerConnection(configuration);


function onSuccess() {};
function onError(error) {
  console.error(error);
};



document.getElementById('call').onclick = function() {startWebRTC(true);};
document.getElementById('respond').onclick = function() {startWebRTC(false);};



// Send signaling data via Scaledrone
function sendMessage(message) {
  var user = "{{user.username}}"
  drone.send(JSON.stringify({
            'message': message,
            'user': user

        }));
  console.log("Message sent")
};


function startWebRTC(isOfferer) {


  // 'onicecandidate' notifies us whenever an ICE agent needs to deliver a
  // message to the other peer through the signaling server
    pc.onicecandidate = event => {
        if (event.candidate) {
            sendMessage({'candidate': event.candidate});
    }
  };

  // If user is offerer let the 'negotiationneeded' event create the offer
  if (isOfferer) {

    pc.onnegotiationneeded = () => {
      pc.createOffer().then(localDescCreated).catch(onError);
      console.log("Offer created")
    }
  }

   // This part does not seem to be working
  // When a remote stream arrives display it in the #remoteVideo element
  pc.ontrack = event => {
    const stream = event.streams[0];
    if (!remoteVideo.srcObject || remoteVideo.srcObject.id !== stream.id) {
      remoteVideo.srcObject = stream;
      console.log("Remote stream added")
    }
  };

  navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  }).then(stream => {
    // Display your local video in #localVideo element
    localVideo.srcObject = stream;
    console.log("Local stream added")
    // Add your stream to be sent to the conneting peer
    stream.getTracks().forEach(track => pc.addTrack(track, stream));
    console.log("Added local stream to track")
  }, onError);



}




function localDescCreated(desc) {
    pc.setLocalDescription(
    desc,
    () => sendMessage({'sdp': pc.localDescription}),
    onError
  );
};

    document.querySelector('#chat-message-input').focus();
    document.querySelector('#chat-message-input').onkeyup = function(e) {
        if (e.keyCode === 13) {  // enter, return
            document.querySelector('#chat-message-submit').click();
        }
    };

    document.querySelector('#chat-message-submit').onclick = function(e) {
        var messageInputDom = document.querySelector('#chat-message-input');
        var message = messageInputDom.value;
        sendMessage(message);

        messageInputDom.value = '';
    };

// Listen to signaling data
drone.onmessage = function(e) {
        var data = JSON.parse(e.data);
        console.info(e)
        var message = data['message'];
        var user = data['user'];
    // Message was sent by us
    if (user === '{{user.username}}') {
        document.querySelector('#chat-log').value += (user +": " + message + '\n');
        elem = document.getElementById("chat-log")
        M.textareaAutoResize(elem);
        console.log("Echo")
      return;
    }
    if (message[0]){
    sdp = message[0]['sdp']
    candidate = message[0]['candidate']
    };

    console.log("Message recieved")
    if (sdp) {


pc.setRemoteDescription(new RTCSessionDescription(sdp),  () => {
        // When receiving an offer lets answer it
    if (pc.remoteDescription.type === 'offer') {
            pc.createAnswer().then(localDescCreated).catch(onError);
            console.log("Offer answerd")
        }
      }, onError);

      // This is called after receiving an offer or answer from another peer

    } else if (candidate) {
      // Add the new ICE candidate to our connections remote description
        pc.addIceCandidate(
        new RTCIceCandidate(candidate), onSuccess, onError);
        console.log("Ice candidate added")
    } else {
        document.querySelector('#chat-log').value += (user +": " + message + '\n');
        elem = document.getElementById("chat-log")
        M.textareaAutoResize(elem);
    }
  };

вывод на консоль после отправки сообщения «привет» и последующего нажатия «вызов» от пользователя1: enter image description here

вывод на консоль после получения сообщения «привет» с последующим нажатием «ответить» от user2: enter image description here

1 Ответ

1 голос
/ 23 января 2020

На стороне, которая отвечает, вы отвечаете немедленно, не дожидаясь getUserMedia и результирующего addTracks. Эти операции являются асинхронными, и они должны выполняться перед вызовом createAnswer. Следовательно, ответ не содержит промежуточного потока, и ontrack не будет вызываться на конце, который вызывает.

Использование синтаксиса обещания облегчает это, как

pc.setRemoteDescription(offer)
.then(() => {
  return navigator.mediaDevices.getUserMedia({audio: true, video: true});
})
.then(stream => {
  stream.getTracks().forEach(track => pc.addTrack(track, stream));
  return pc.createAnswer();
})
... then continue with setLocalDescription and signal to the offerer
...