简体   繁体   中英

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

In VueJS, i am making a WebRTC component to get the user media and set the stream to the local video element. When users press the call button, i am creating both of the RTCPeerConnection objects, sending the offer, setting local description, sending answer and all.

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. 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 - 在此处输入图片说明 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

Using promises without async / await requires propagating errors manually and checking them.

Add a catch eg here to see errors:

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() . That's because you're passing a member function as a callback to the then function, which ends up invoking it without a this . Either use this.gotDescription.bind(this) or (nicer) arrow functions. 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.

All these calls return promises, which you're ignoring:

/* 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.

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:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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