简体   繁体   English

使用VueJS的WebRTC:为什么不播放远程视频?

[英]WebRTC using VueJS: Why the remote video is not playing?

I am making a sample application where there will be two video elements and a button "Call". 我正在制作一个示例应用程序,其中将有两个视频元素和一个“呼叫”按钮。 The first video element ( #localVideo ) will show the output of the local media stream. 第一个视频元素( #localVideo )将显示本地媒体流的输出。 When i press the call button the remote video element will play the remote media stream. 当我按下通话按钮时,远程视频元素将播放远程媒体流。 I have made the same application in raw JavaScript, which is working fine. 我已经在原始JavaScript中制作了相同的应用程序,效果很好。

In VueJS, i am making a WebRTC component to get the user media and set the stream to the local video element. 在VueJS中,我正在制作一个WebRTC组件来获取用户媒体并将流设置为本地视频元素。 When users press the call button, i am creating both of the RTCPeerConnection objects, sending the offer, setting local description, sending answer and all. 当用户按下呼叫按钮时,我将创建两个RTCPeerConnection对象,发送报价,设置本地描述,发送答案以及全部。

here is the template of the component - 这是组件的模板-

<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>

And here is the script for the component - 这是该组件的脚本-

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)
  }
}

The local video is showing properly. 本地视频显示正常。 The problem i am facing is that, when i am pressing the Call button, the remote video is not showing anything, rather i see a loading circle like in the screenshot. 我面临的问题是,当我按下“ Call按钮时,远程视频没有显示任何内容,而是在屏幕截图中看到了一个加载圆圈。 There is no console error as well. 也没有控制台错误。

在此处输入图片说明

I have debugged and saw the srcObject of both local and remote video and they appears to be same - 我已经调试并看到了本地和远程视频的srcObject ,它们似乎是相同的- 在此处输入图片说明 Can anyone please tell me if i am doing something wrong? 谁能告诉我我做错了什么吗? Also is there any other way to debug this? 还有其他方法可以调试吗?

Note: 注意:

The project/source code can be downloaded from here, if you want you can download and check the code. 可以从此处下载项目/源代码,如果需要,可以下载并检查代码。 I will try to prepare a codepen - https://drive.google.com/open?id=1e7C0ojZ0jT7EXFNtCKcWpJBpKd_mWi_s 我将尝试准备一个代码笔-https://drive.google.com/open ? id = 1e7C0ojZ0jT7EXFNtCKcWpJBpKd_mWi_s

Using promises without async / await requires propagating errors manually and checking them. 使用没有async / await promise需要手动传播错误并进行检查。

Add a catch eg here to see errors: 添加一个catch例如在这里查看错误:

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

...and you should see that this is undefined inside gotDescription() . ...并且您应该看到在gotDescription()thisundefined That's because you're passing a member function as a callback to the then function, which ends up invoking it without a this . 那是因为您要将成员函数作为回调传递给then函数,而最终没有使用this调用它。 Either use this.gotDescription.bind(this) or (nicer) arrow functions. 使用this.gotDescription.bind(this)或(nicer)箭头功能。 Eg: 例如:

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

Furthermore, unless you return all the promises , they won't form a single chain to catch all errors. 此外,除非您返回所有的Promise ,否则它们不会形成捕获所有错误的单一链。

All these calls return promises, which you're ignoring: 所有这些调用都会返回promise,您将忽略它们:

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

Luckily (and perhaps confusingly), RTCPeerConnection automatically queues operations done on it, so this may actually work, provided there are no errors, which may get swallowed, depending on browser. 幸运的是(可能令人困惑), RTCPeerConnection自动将在其上进行的操作排队,因此,如果没有错误(可能会被浏览器吞没),这可以实际起作用。

Instead, to catch errors, either do this: 相反,要捕获错误,请执行以下操作:

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

or use the nicer async / await syntax which propagates errors correctly: 或使用更好的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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM