2

I'm trying to make a simple AngularJS WebRTC video chat app based on this tutorial.

I'm able to connect to connect clients, add streams and play my own stream, but somehow I can't play the remote stream.

When I check the elements I can see that the videoplayer does in fact have a blob source, but it won't play it.

Can anyone tell me why it won't show?

HTML element: Blob src

Room controller:

angular.module('publicApp').controller('RoomCtrl', function ($sce, VideoStream, $location, $routeParams, $scope, Room)
{
    if (!window.RTCPeerConnection || !navigator.getUserMedia) {
  $scope.error = 'WebRTC is not supported by your browser. You can try the app with Chrome and Firefox.';
  return;
}

var stream;

VideoStream.get()
.then(function (s) {
  stream = s;
  Room.init(stream);
  stream = URL.createObjectURL(stream);
  if (!$routeParams.roomId) {
    Room.createRoom()
    .then(function (roomId) {
      $location.path('/room/' + roomId);
    });
  } else {
    Room.joinRoom($routeParams.roomId);
  }
}, function () {
  $scope.error = 'No audio/video permissions. Please refresh your browser and allow the audio/video capturing.';
});

$scope.peers = [];

Room.on('peer.stream', function (peer) {
  console.log('Client connected, adding new stream');
  $scope.peers.push({
    id: peer.id,
    stream: URL.createObjectURL(peer.stream)
  });
  console.log($scope.peers);
});

Room.on('peer.disconnected', function (peer) {
  console.log('Client disconnected, removing stream');
  $scope.peers = $scope.peers.filter(function (p) {
    return p.id !== peer.id;
  });
});

$scope.getLocalVideo = function () {
  return $sce.trustAsResourceUrl(stream);
};
});

Room factory:

angular.module('publicApp').factory('Room', function ($rootScope, $q, Io, config)
{
var iceConfig = { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }]},
    peerConnections = {},
    currentId, roomId,
    stream;

function getPeerConnection(id)
{
  if (peerConnections[id]) {
    return peerConnections[id];
  }
  var pc = new RTCPeerConnection(iceConfig);
  peerConnections[id] = pc;
  pc.addStream(stream);
  pc.onicecandidate = function (evnt) {
    socket.emit('msg', { by: currentId, to: id, ice: evnt.candidate, type: 'ice' });
  };
  pc.onaddstream = function (evnt) {
    console.log('Received new stream');
    api.trigger('peer.stream', [{
      id: id,
      stream: evnt.stream
    }]);
    if (!$rootScope.$$digest) {
      $rootScope.$apply();
    }
  };
  return pc;
}

function makeOffer(id)
{
  var pc = getPeerConnection(id);
  pc.createOffer(function (sdp) {
    pc.setLocalDescription(sdp);
    console.log('Creating an offer for', id);
    socket.emit('msg', { by: currentId, to: id, sdp: sdp, type: 'sdp-offer' });
  }, function (e) {
    console.log(e);
  },
  { mandatory: { OfferToReceiveVideo: true, OfferToReceiveAudio: true }});
}

function handleMessage(data)
{
  var pc = getPeerConnection(data.by);
  switch (data.type) {
    case 'sdp-offer':
      pc.setRemoteDescription(new RTCSessionDescription(data.sdp), function () {
        console.log('Setting remote description by offer');
        pc.createAnswer(function (sdp) {
          pc.setLocalDescription(sdp);
          socket.emit('msg', { by: currentId, to: data.by, sdp: sdp, type: 'sdp-answer' });
        });
      });
      break;
    case 'sdp-answer':
      pc.setRemoteDescription(new RTCSessionDescription(data.sdp), function () {
        console.log('Setting remote description by answer');
      }, function (e) {
        console.error(e);
      });
      break;
    case 'ice':
      if (data.ice) {
        console.log('Adding ice candidates');
        pc.addIceCandidate(new RTCIceCandidate(data.ice));
      }
      break;
  }
}

var socket = Io.connect(config.SIGNALIG_SERVER_URL),
    connected = false;

function addHandlers(socket)
{
  socket.on('peer.connected', function (params) {
    makeOffer(params.id);
  });

  socket.on('peer.disconnected', function (data) {
    api.trigger('peer.disconnected', [data]);
    if (!$rootScope.$$digest) {
      $rootScope.$apply();
    }
  });

  socket.on('msg', function (data) {
    handleMessage(data);
  });
}

var api = {
  joinRoom: function (r) {
    if (!connected) {
      socket.emit('init', { room: r }, function (roomid, id) {
        currentId = id;
        roomId = roomid;
      });
      connected = true;
    }
  },
  createRoom: function () {
    var d = $q.defer();
    socket.emit('init', null, function (roomid, id) {
      d.resolve(roomid);
      roomId = roomid;
      currentId = id;
      connected = true;
    });
    return d.promise;
  },
  init: function (s) {
    stream = s;
  }
};
EventEmitter.call(api);
Object.setPrototypeOf(api, EventEmitter.prototype);

addHandlers(socket);
return api;
});

Directive:

angular.module('publicApp').directive('videoPlayer', function ($sce) {
return {
  template: '<div><video ng-src="{{trustSrc()}}" autoplay></video></div>',
  restrict: 'E',
  replace: true,
  scope: {
    vidSrc: '@'
  },
  link: function (scope) {
    console.log('Initializing video-player');
    scope.trustSrc = function () {
      if (!scope.vidSrc) {
        console.log('No vidSrc found');
        return undefined;
      }
      return $sce.trustAsResourceUrl(scope.vidSrc);
    };
  }
};
});

Room.html:

<div class="video-wrapper">
  <video-player class="col-md-4" ng-repeat="peer in peers" vid-src="{{peer.stream}}"></video-player>
</div>

<div class="video-wrapper">
  <div class="col-md-2">
    <video ng-src="{{getLocalVideo()}}" autoplay muted></video>
  </div>
</div>
Berry
  • 128
  • 1
  • 15
  • Can you try to play it manually with javascript command .play() ? https://www.w3schools.com/tags/av_met_play.asp – Guillaume Apr 06 '17 at 15:37
  • 1
    The line `stream = URL.createObjectURL(stream)` seems suspect. That function returns a url, not a `MediaStream`. In fact, [please stop](http://stackoverflow.com/a/40210033/918910) using `createObjectURL` altogether as it has been [deprecated](https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL), and use `video.srcObject = stream` where `stream` is the original MediaStream instead. – jib Apr 06 '17 at 16:56
  • @jib Thanks, I now understand why `createObjectURL` won't work. What I don't yet understand is exactly where/how to use `video.srcObject = stream`. Do I need to adjust my directive? – Berry Apr 07 '17 at 09:08
  • 1
    `element.srcObject` is the new sibling of `element.src`. Check out working fiddle [here](http://stackoverflow.com/a/34034763/918910). Sorry I don't know where that corresponds to in angular. – jib Apr 07 '17 at 12:46

0 Answers0