WebRTC с использованием VueJS: почему удаленное видео не воспроизводится? - PullRequest
0 голосов
/ 29 января 2019

Я делаю пример приложения, в котором будет два видеоэлемента и кнопка «Позвонить».Первый видеоэлемент (#localVideo) покажет выходные данные локального медиапотока.Когда я нажимаю кнопку вызова, удаленный элемент видео будет воспроизводить удаленный поток мультимедиа.Я сделал то же самое приложение на необработанном JavaScript, который работает нормально.

В VueJS я делаю компонент WebRTC для получения пользовательских мультимедийных данных и установки потока для локального элемента видео.Когда пользователи нажимают кнопку вызова, я создаю оба объекта RTCPeerConnection, отправляю предложение, устанавливаю локальное описание, отправляю ответ и все.

вот шаблон компонента -

<template>
  <div class="webRTC">
    <video id = "localVideo" playsinline autoplay muted></video>
    <button id = "call" v-on:click='call'> Call </button>
    <video id = "remoteVideo" playsinline autoplay controls></video>
  </div>
</template>

<script src="./webRTC.js"></script>

А вот и скрипт для компонента -

export default {
  name: 'webRTC',
  sockets: {
    connect: function () {
      console.log('Socket IO connected!')
    },

    TestConnection: function () {
      console.log('Test connection successful!')
    }
  },

  data: function () {
    return {
      localStream: null,
      remoteStream: null,
      pc1: null,
      pc2: null
    }
  },

  methods: {
    call: function () {
      this.pc1 = new RTCPeerConnection()
      this.pc1.addEventListener('icecandidate', e => this.addIceCandidate(this.pc1, e))

      this.pc2 = new RTCPeerConnection()
      this.pc2.addEventListener('icecandidate', e => this.addIceCandidate(this.pc2, e))
      this.pc2.addEventListener('track', this.gotRemoteStrem)

      this.localStream.getTracks().forEach(track => {
        console.log('Adding local stream')
        this.pc1.addTrack(track, this.localStream)
      })

      this.pc1.createOffer({ offerToReceiveAudio: 1, offerToReceiveVideo: 1 }).then(this.gotDescription)
    },

    gotRemoteStrem: function (event) {
      console.log('Got Remote stream')
      let remoteVideo = document.querySelector('#remoteVideo')
      this.remoteStream = event.streams[0]
      remoteVideo.srcObject = event.streams[0]
    },

    gotDescription: function (description) {
      console.log('Got description 1')
      this.pc1.setLocalDescription(description)
      this.pc2.setRemoteDescription(description)

      this.pc2.createAnswer().then(this.gotDescription2)
    },

    gotDescription2: function (description) {
      console.log('Got description 2')
      this.pc2.setLocalDescription(description)
      this.pc1.setRemoteDescription(description)
    },

    addIceCandidate: function (pc, event) {
      this.getOtherPC(pc).addIceCandidate(event.candidate).then(this.addIceCandicateSuccess).catch(this.addIceCandicateFailure)
    },

    addIceCandicateSuccess: function () {
      console.log('Ice candidate added successfully')
    },

    addIceCandicateFailure: function () {
      console.log('Ice candidate failure')
    },

    getOtherPC: function (pc) {
      if (pc === this.pc1) {
        return this.pc2
      }

      return this.pc1
    },

    gotDevices: function (stream) {
      let localVideo = document.querySelector('#localVideo')
      this.localStream = stream
      localVideo.srcObject = stream
    },

    handleMediaError: function (error) {
      console.error('Error:' + error.name)
    }
  },

  created: function () {
    console.log('webRTC is created!')
    let prom = navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(this.gotDevices).catch(this.handleMediaError)
  }
}

Локальное видео показывается правильно.Проблема, с которой я сталкиваюсь, заключается в том, что, когда я нажимаю кнопку Call, на удаленном видео ничего не отображается, скорее я вижу круг загрузки, как на скриншоте.Также нет ошибки консоли.

enter image description here

Я отладил и увидел srcObject как локального, так и удаленного видео, и они выглядят одинаково- enter image description here Может кто-нибудь сказать мне, если я делаю что-то не так?Также есть ли другой способ отладки этого?

Примечание:

Проект / исходный код можно скачать здесь, если вы хотите, вы можете загрузить и проверитькод.Я постараюсь приготовить кодовую ручку - https://drive.google.com/open?id=1e7C0ojZ0jT7EXFNtCKcWpJBpKd_mWi_s

1 Ответ

0 голосов
/ 29 января 2019

Для использования обещаний без async / await требуется распространение ошибок вручную и их проверка.

Добавьте сюда catch, например, чтобы увидеть ошибки:

this.pc1.createOffer({offerToReceiveAudio: 1, offerToReceiveVideo: 1})
  .then(this.gotDescription)
  .catch(e => console.log(e)); // <-- here

... и вы должны увидеть, что this это undefined внутри gotDescription().Это потому, что вы передаете функцию-член в качестве обратного вызова функции then, которая в итоге вызывает ее без this.Либо используйте this.gotDescription.bind(this), либо (приятнее) функции стрелок.Например:

this.pc1.createOffer({offerToReceiveAudio: 1, offerToReceiveVideo: 1})
  .then(offer => this.gotDescription(offer)) // arrow function invoking on this
  .catch(e => console.log(e));

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

Все эти вызовы возвращают обещания, который вы игнорируете:

/* const unusedPromise1 = */ this.pc1.setLocalDescription(description)
/* const unusedPromise2 = */ this.pc2.setRemoteDescription(description)
/* const unusedPromise3 = */ this.pc2.createAnswer().then(this.gotDescription2)

К счастью (и, возможно, сбивает с толку), RTCPeerConnection автоматически ставит в очередь операции, выполняемые на нем, так что это может фактически работать, если нет ошибок, которыеможет зависнуть в зависимости от браузера.

Вместо этого, чтобы перехватывать ошибки, либо сделайте следующее:

this.pc1.setLocalDescription(description)
.then(() => this.pc2.setRemoteDescription(description))
.then(() => this.pc2.createAnswer())
.then(answer => this.gotDescription2(answer))
.catch(e => console.log(e))

, либо используйте более приятный синтаксис async / await, который правильно распространяет ошибки:

gotDescription: async function (description) {
  console.log('Got description 1')
  await this.pc1.setLocalDescription(description)
  await this.pc2.setRemoteDescription(description)
  await this.gotDescription2(await this.pc2.createAnswer());
}
...