javascriptvideohtml5-videogetusermediamediadevices

Event triggered when the video stream is started, with getUserMedia


I'm using the ZXing JS barcode scanner library https://github.com/zxing-js/library/ with a video stream input (webcam or phone camera), as detailed in the following code.

In general, how to add an event listener to a <video> to do an action when a video stream has just started? (a video using the MediaDevices.getUserMedia video stream API, started from ZXing's decodeFromInputVideoDevice)?

const codeReader = new ZXing.BrowserQRCodeReader();

codeReader
  .decodeFromInputVideoDevice(undefined, 'video')  // uses the default input
  .then(result => console.log(result.text))  // this happens when the barcode is found / recognized
  .catch(err => console.error(err));
<script src="https://unpkg.com/@zxing/library@0.15.2/umd/index.min.js"></script>
<video id="video"></video>

Note: for now I'm using setTimeout(..., 2000) when the user has clicked on the button to start the video, but obviously this fails in the case there is a dialog box "Do you want to allow this website to use the camera device?", then 2 seconds is not enough. A listener on event "VideoHasJustStarted" would be better.

Edit:
Here is a jsFiddle showing the issue: not working with various events: started, devicechange.


Solution

  • There are a few ways to detect if a video is playing, or can be played, using event listeners:

    let video = document.querySelector('video');
    
    // Video has been started/unpaused
    video.addEventListener('play', function() {
        ...
    })
    
    // Video has resumed play/started/unpaused/finished buffering/finished seeking, etc
    video.addEventListener('playing', function() {
        ...
    })
    
    // Video can start playing (but might not be playing)
    video.addEventListener('canplay', function() {
        ...
    })
    
    // Video can be played without buffering (but might not be playing)
    video.addEventListener('canplaythrough', function() {
        ...
    })
    

    Most similar to VideoHasJustStarted is probably playing. But depending on how you want to execute your function, one of the above methods should fit your needs.

    More info on video events: https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events

    Example

    // Get video
    var video = document.querySelector('video');
    
    // Add event listener to monitor events
    video.addEventListener('playing', () => {
      console.log('Video is now streaming!')
    });
    
    // Add stream
    navigator.mediaDevices.getUserMedia({
        video: true
      })
      .then(function(stream) {
        var videoTracks = stream.getVideoTracks();
    
        stream.onremovetrack = function() {
          console.log('Stream ended');
        };
        window.stream = stream;
        video.srcObject = stream;
      })
      .catch(function(error) {
    
        console.log(error);
      });
    <video id="video" autoplay muted></video>

    Tested on Firefox on laptop - permission is requested to use webcam and the console.log fires when the video starts. As StackOverflow blocks the above from running inline, link to working fiddle