philnash/mediadevices-camera-selection

NotReadableError: Could not start video source

Closed this issue Β· 23 comments

when try to switch camera from front to rear on chrome 69.0.34 on android produce that error
NotReadableError: Could not start video source

it's working fine on iOS Safari

thanks

Is that when you're running the Video chat example? Does the simple HTML example still work?

yes the simple still work, but I used version 2beta

Ok, for a start this demo wasn't built with the version 2 beta in mind, so I can't promise it will work with that.

On the other hand, I can't make it work with v1 of Twilio Video at the moment either. Which is confusing as the simple demo is still fine. I assume something has changed in Chrome to break this, but I'll have to do some digging to find out what.

Thanks
I tested it with the older version already ,same problem

Ok, I’m getting that issue too. Not sure what’s going on. Perhaps you could try getting the video stream using getUserMedia and using the result to build a new LocalVideoTrack object?

Any solution on this? I am testing From Mac Opera/Firefox/Safari works fine expect Chrome. Though it worked fine on Chrome Android

I also am having a problem switching cameras on mobile chrome android. I've tried everything, and it still only works about 50% of the time.

I have not had the time to investigate this. If you have this issue, please let me know the error messages you are seeing and whether you are just running this project as is, or using the code elsewhere or with changes.

Thanks

I had a similar error in my project in Chrome Android. The solution for me was to stop all tracks in an active stream before acquiring a new one

if(this.lastStream) {
  this.lastStream.getTracks().forEach(track => track.stop()) 
}

after that the error has gone

There is a problem with the example on Chrome 71.0.3578.99 and on an app using Twilio I've built that's based on your example code.

I tried track.stop() but that didn't help.

The error I get is:

NotReadableError: 
Could not start video source

@altescape I just ran both the camera fun version and the quickstart video chat version in Chrome 71.0.3578.98 and both worked fine for me.

Can you share the code you are using that results in the error and a bit more detail about what you are doing with it? Is it a video chat application? What version of Twilio Video are you using?

Thanks

@philnash Thanks for the quick reply.

I can't share the repo but I'm getting same results when using your quickstart video chat... I'll include an example of our code also.

Running locally and with ngrok, your quickstart example isn't working on Android Chrome (or Samsung browser), however it is working on Apple Safari and desktop Chromes and this is the same result as the app we are building.

The culprit device:

Device: Samsung S5
OS: Android 6.0.1; SM-G901F Build MMB29M
Browser: Chrome
Version: 71.0.3578.99

Twilio library versions:

"twilio": "^3.27.1",
"twilio-video": "^1.15.1",

I will try and update to beta version to see if that helps and keep you posted.

Code from our Vue page:

<template>
  <div class="columns">
    <div class="column is-full">
      <div v-if="videoDevices" v-show="videoDevices.length > 1" class="field is-flex">
        <div class="column is-one-third">
          <label>{{ facingMode }} camera</label>
        </div>
        <div class="column is-two-thirds">
          <button class="button is-small is-primary" @click="switcher">Switch</button>

          <div class="control has-icons-left">
          <span class="select is-small">
            <select id="video-devices" v-model="currentVideoDevice">
              <option v-for="(device, index) in videoDevices"
                      :key="index"
                      :value="device.id"
              >
                {{ device.name }}
              </option>
            </select>
          </span>
            <span class="icon is-small is-left">
            <i class="fas fa-camera"></i>
          </span>
          </div>
        </div>

      </div>
    </div>

    <hr>

    <div class="column is-full">
      <ul>
        <li v-for="(device, index) in videoDevices" :key="index">
          {{ device.name }} - {{ device.id }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import { mapState } from 'vuex'
import $ from 'jquery';
import Video from 'twilio-video'
import { detachTracks, attachTracks } from './helper'

export default {
  name: 'CameraSelect',

  computed: {
    ...mapState([
      'activeRoom',
      'videoDevices'
    ]),
    currentVideoDevice: {
      get() {
        return this.$store.state.currentVideoDevice.id
      },
      set(value) {
        this.$store.commit('setCurrentVideoDevice', ...this.videoDevices.filter(device => device.id === value) )
      },
    }
  },

  data() {
    return {
      currentStream: undefined,
      facingMode: 'user',
      constraints: {},
    }
  },

  watch: {
    currentVideoDevice() {
      this.toggleFacingMode()
      this.setConstraints()
    }
  },

  mounted() {
    navigator.mediaDevices.ondevicechange = this.enumerateDevices
    this.enumerateDevices()
    this.setConstraints()
  },

  methods: {
    stopMediaTracks(stream) {
      stream.getTracks().forEach(track => {
        stream.removeTrack(track)
        track.stop();
      })
    },

    toggleFacingMode() {
      this.facingMode = this.facingMode === 'environment' ? 'user' : 'environment'
    },

    switcher() {
      this.$store.dispatch('toggleVideoDevice')
    },

    async setConstraints() {
      if (typeof this.currentStream !== 'undefined') {
        this.stopMediaTracks(await this.currentStream)
      }

      const videoConstraints = {}
      if (typeof await this.currentVideoDevice === 'undefined' || $.isEmptyObject(await this.currentVideoDevice)) {
        videoConstraints.facingMode = await this.facingMode
      } else {
        videoConstraints.deviceId = { exact: await this.currentVideoDevice }
      }

      this.constraints = {
        video: videoConstraints,
        audio: false,
      }
      
      const localParticipant = await this.activeRoom.localParticipant
      Video.createLocalVideoTrack(await this.constraints.video)
        .then((localVideoTrack) => {
          const tracks = Array.from(localParticipant.videoTracks.values())
          localParticipant.unpublishTracks(tracks)
          this.$store.dispatch('appendLog', `${localParticipant.identity} removed track: ${tracks[0].kind}`)
          detachTracks(tracks)

          localParticipant.publishTrack(localVideoTrack)
          this.$store.dispatch('appendLog', `${localParticipant.identity} added track: ${localVideoTrack.kind}`)
          const previewContainer = document.getElementById('local-media')
          attachTracks([localVideoTrack], previewContainer)

          this.$store.dispatch('appendLog', `${localParticipant.identity} swapped media successfully`)
        })
        .catch((error) => {
          this.$store.dispatch('setErrorMessage', { name: error.name, message: error.message })
        })
    },

    enumerateDevices() {
      navigator.mediaDevices.enumerateDevices()
        .then(mediaDevices => {
          this.$store.dispatch('clearVideoDevices')
          const videoDevices = []
          mediaDevices.forEach(mediaDevice => {
            if (mediaDevice.kind === 'videoinput') {
              videoDevices.push({
                name: mediaDevice.label,
                id: mediaDevice.deviceId,
              })
            }
          })
          return this.$store.dispatch('setVideoDevices', videoDevices)
        })
        .catch(error => {
          this.$store.dispatch('setErrorMessage', { name: error.name, message: error.message })
        })
    },
  }
}
</script>

AttachTracks and detachTracks imports:

export const attachTracks = (tracks, container) => {
  tracks.forEach(function (track) {
    container.appendChild(track.attach())
  })
}

export const detachTracks = (tracks) => {
  tracks.forEach((track) => {
    track.detach().forEach((detachedElement) => {
      detachedElement.remove()
    })
  })
}

And as stated earlier the error I get is:

NotReadableError: 
Could not start video source

Ah, it's Chrome on Android causing the issues? I was only looking on desktop, sorry.

I will take a look and see what I can find out.

Managed to fix by adding the following to just before the Video.createLocalVideoTrack() method call:

const localParticipant = await this.activeRoom.localParticipant
localParticipant.tracks.forEach(track => {
   track.stop()
})

Found this thread searching for the same issue in anothier context.
This seems to be a Chrome bug on Android, still an iissue with v 78. Reproducable on Galaxy Tab S3 and S10e.

I can switch to the back camera after repeated attempts. And then it seems to work OK until the page gets reloaded again.

Do you find this issue in Chrome for Android or desktop? And is this as part of the video chat or just the basic example?

hello
i have a problem in use Twilio example of react hook video chat :
my app work in all browser, but when i want to test remote participant and i open another browser in my system i get error in second browser .
my error is:
Call to getUserMedia failed: DOMException: Could not start video source
Uncaught Error: The error you provided does not contain a stack trace.
at B (index.js:1573)
at G (index.js:1890)
at index.js:1905
at index.js:1924
at index.js:1405
Uncaught (in promise) DOMException: Could not start video source

please help me.thanke you

There's a good explanation of what might cause this error here: twilio/twilio-video.js#325 (comment)

It normally boils down to no permission to use the video source or that you are trying to use more than one video source on Android, or another application is using the video source and is blocking the browser from access.

Make sure that if you are switching cameras to stop any existing tracks. I will check through my code to add examples of that if it needs it.

There's a good explanation of what might cause this error here: twilio/twilio-video.js#325 (comment)

It normally boils down to no permission to use the video source or that you are trying to use more than one video source on Android, or another application is using the video source and is blocking the browser from access.

Make sure that if you are switching cameras to stop any existing tracks. I will check through my code to add examples of that if it needs it.

im sorry for my question.i was Beginner in react hook .i did not install hoo.so after that the program run right.

No problem, glad you are sorted now

if the camera is used by other app like firefox this may be occured

Problem persists and occurs if camera is switch too fast / too quickly.

@AntonioCaroppos I would suggest adding a delay before you re-enable the button to switch cameras. That way users can't switch too fast.