Search code examples
javascriptandroidangularjsgoogle-chromewebcam

Webcam getUserMedia API - AngularJS bugs?


I've done a webcam directive that uses a service in AngularJS. I've used this example:

https://simpl.info/getusermedia/sources/

When I try the example in my tablet it works fine, but when I start my code in the tablet (Google Chrome), it gives me a couple of bugs.

Bug #1: I can't get the rear camera to work.

Bug #2: When I start the camera directive, it only shows me the first frame of the stream and then it halts. Although, when I flip to the rear camera (that doesn't work) and then flip back, it gives me the stream.

Anyone got any ideas about what I might be doing wrong? I've tried a lot of stuff.

Webcam directive:

link: function postLink($scope, element) {

    var videoSources = [];

    MediaStreamTrack.getSources(function(mediaSources) {

      for (var i = 0; i < mediaSources.length; i++)
      {
        if (mediaSources[i].kind == 'video')
        {
          videoSources.push(mediaSources[i].id);
        }
      }

      if (videoSources.length > 1){ $scope.$emit('multipleVideoSources'); }

      initCamera(0);

    });

    // Elements
    var videoElement = element.find('video')[0];

    // Stream
    function streaming(stream) {
      $scope.$apply(function(){
        videoElement.src = stream;
        videoElement.play();
      });
    }

    // Check ready state
    function checkReadyState(){
      if (videoElement.readyState == 4)
      {
        $interval.cancel(interval);
        $scope.$emit('videoStreaming');
      }
    }
    var interval = $interval(checkReadyState, 1000);

    // Init
    $scope.$on('init', function(event, stream){
      streaming(stream);
    });

    // Switch camera
    $scope.$on('switchCamera', function(event, cameraIndex){
      initCamera(cameraIndex);
    });

    // Init via Service
    function initCamera(cameraIndex)
    {
      var constraints = {
        audio: false,
        video: {
          optional: [{ sourceId: videoSources[cameraIndex] }]
        }
      };

      camera.setup(constraints, camera.onSuccess, camera.onError);
    }

  }

Camera service:

.service('camera', function($rootScope) {

    // Setup of stream
    this.init = false;

    this.onError = function(error){
        console.log(error);
        alert('Camera error');
    };

    this.onSuccess = function(stream){
        window.stream = stream;
        stream = window.URL.createObjectURL(stream);

        $rootScope.$broadcast('init', stream); 
    };

    this.setup = function(constraint){
        navigator.getMedia(constraint, this.onSuccess, this.onError);
        this.init = true;
    };

On my laptop this works fine, although I can only test with one video source (as it only has one).


Solution

  • Bug #2 solved by not do videoStream.play() until it has a readyState of 4.

    Bug #1 solved by moving window in to the directive and not using the service. Then calling the following code within initCamera function:

    if (!!window.stream) {
       videoElement.src = null;
       window.stream.stop();
    }