Skip to content

Commit

Permalink
New way to handle Streams
Browse files Browse the repository at this point in the history
- Commit for SIPit
  • Loading branch information
jmillan committed Feb 19, 2013
1 parent 8aff36f commit 88fa9b6
Show file tree
Hide file tree
Showing 2 changed files with 359 additions and 299 deletions.
235 changes: 103 additions & 132 deletions src/MediaSession.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,107 +7,90 @@
* @augments JsSIP
* @class PeerConnection helper Class.
* @param {JsSIP.Session} session
* @param {HTMLVideoElement} selfView
* @param {HTMLVideoElement} remoteView
*/
JsSIP.MediaSession = function(session, selfView, remoteView) {
JsSIP.MediaSession = function(session, RTCConstraints) {
RTCConstraints = RTCConstraints || {};

this.session = session;
this.selfView = selfView || null;
this.remoteView = remoteView || null;
this.localMedia = null;
this.peerConnection = null;

this.init(RTCConstraints);
};

JsSIP.MediaSession.prototype = {
/**
* Establish peerConnection for Caller.
* <br> - Prompt the user for permission to use the Web cam or other video or audio input.
* <br> -- If the user consents, create a peerConnection.
* <br> -- If the user doesn't consent, fire onFailure callback.
*
* @param {Object} mediaTypes {audio:true/false, video:true/false}
* @param {Function} onSuccess
* @param {Function} onFailure
*/
startCaller: function(mediaTypes, onSuccess, onFailure) {
var self = this;

/** @private */
function onGetUserMediaSuccess(stream) {
// Start peerConnection
self.start(onSuccess);
createOffer: function(onSuccess, onFailure, constraints) {
var
self = this,
sent = false;

// add stream to peerConnection
self.peerConnection.addStream(stream);
this.onIceCompleted = function() {
if (!sent) {
sent = true;
onSuccess(self.peerConnection.localDescription.sdp);
}
};

// Set local description and start Ice.
self.peerConnection.createOffer(function(sessionDescription){
self.peerConnection.setLocalDescription(sessionDescription);
});
}
this.peerConnection.createOffer(
function(sessionDescription){
self.peerConnection.setLocalDescription(
sessionDescription,
null,
onFailure
);
},
onFailure,
constraints.offerConstraints
);
},

/** @private */
function onGetUserMediaFailure(e) {
onFailure(e);
}
createAnswer: function(onSuccess, onFailure, constraints) {
var
self = this,
sent = false;

this.getUserMedia(mediaTypes, onGetUserMediaSuccess, onGetUserMediaFailure);
this.onIceCompleted = function() {
if (!sent) {
sent = true;
onSuccess(self.peerConnection.localDescription.sdp);
}
};

this.peerConnection.createAnswer(
function(sessionDescription){
self.peerConnection.setLocalDescription(
sessionDescription,
null,
onFailure
);
},
onFailure,
constraints.answerConstraints
);
},

/**
* Establish peerConnection for Callee.
* <br> - Prompt the user for permission to use the Web cam or other video or audio input.
* <br> -- If the user consents, create a peerConnection.
* <br> -- If the user doesn't consent, fire onMediaFailure callback.
* <br>
* <br> - Set the received SDP offer to the just created peerConnection.
* <br> -- If the SDP offer is not valid, fire onSdpFailure callback.
* <br> -- If the SDP offer is valid, fire onSuccess callback
*
* @param {Function} onSuccess
* @param {Function} onMediaFailure
* @param {Function} onSdpFailure
* @param {String} sdp
*/
startCallee: function(onSuccess, onMediaFailure, onSdpFailure, sdp) {
addStream: function(onSuccess, onFailure, constraints) {
var self = this;

function onGetUserMediaSuccess(stream) {
// Start peerConnection
self.start(onSuccess);

// add stream to peerConnection
self.peerConnection.addStream(stream);

self.peerConnection.setRemoteDescription(
new JsSIP.WebRTC.RTCSessionDescription({type:'offer', sdp:sdp}),
function() {
self.peerConnection.createAnswer(
function(sessionDescription){
self.peerConnection.setLocalDescription(sessionDescription);
},
onSdpFailure
);
},
onSdpFailure
);
}

function onGetUserMediaFailure(e) {
onMediaFailure(e);
}

self.getUserMedia({'audio':true, 'video':true}, onGetUserMediaSuccess, onGetUserMediaFailure);
},
this.getUserMedia(constraints.userMediaConstraints,
function(stream) {
self.peerConnection.addStream(stream, constraints.streamConstraints);
onSuccess();
},
function(e) {
onFailure(e);
}
);
},

/**
* peerConnection creation.
* @param {Function} onSuccess Fired when there are no more ICE candidates
*/
start: function(onSuccess) {
init: function(RTCConstraints) {
var idx, server, scheme, url,
session = this,
sent = false,
self = this,
servers = [];

for (idx in this.session.ua.configuration.stun_servers) {
Expand All @@ -125,41 +108,40 @@ JsSIP.MediaSession.prototype = {
});
}

this.peerConnection = new JsSIP.WebRTC.RTCPeerConnection({'iceServers': servers});

this.peerConnection.onicecandidate = function(event) {
if (event.candidate) {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'ICE candidate received: '+ event.candidate.candidate);
} else {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'no more ICE candidates');
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'PeerConnection state: '+ this.readyState);
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'ICE state: '+ this.iceState);
if (!sent) { // Execute onSuccess just once.
sent = true;
onSuccess();
}
}
};
this.peerConnection = new JsSIP.WebRTC.RTCPeerConnection({'iceServers': servers}, RTCConstraints);

this.peerConnection.mediaSession = self;

this.peerConnection.onopen = function() {
console.log(JsSIP.C.LOG_MEDIA_SESSION +'media session opened');
};

this.peerConnection.onaddstream = function(mediaStreamEvent) {
console.log(JsSIP.C.LOG_MEDIA_SESSION +'stream added');
this.peerConnection.onaddstream = function(e) {
console.log(JsSIP.C.LOG_MEDIA_SESSION +'stream added: '+ e.stream.id);
};

this.peerConnection.onremovestream = function(e) {
console.log(JsSIP.C.LOG_MEDIA_SESSION +'stream removed: '+ e.stream.id);
};

this.peerConnection.onicecandidate = function(e) {
if (e.candidate) {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'ICE candidate received: '+ e.candidate.candidate);
}
};

if (session.remoteView && this.getRemoteStreams().length > 0) {
session.remoteView.src = window.URL.createObjectURL(mediaStreamEvent.stream);
this.peerConnection.ongatheringchange = function(e) {
if (e.currentTarget.iceGatheringState === 'complete' && this.iceConnectionState !== 'closed') {
this.mediaSession.onIceCompleted();
}
};

this.peerConnection.onremovestream = function(stream) {
console.log(JsSIP.C.LOG_MEDIA_SESSION +'stream removed: '+ stream);
this.peerConnection.onicechange = function() {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'ICE connection state changed to "'+ this.iceConnectionState +'"');
};

this.peerConnection.onstatechange = function() {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'PeerConnection state changed to '+ this.readyState);
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'ICE state: '+ this.iceState);
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'PeerConnection state changed to "'+ this.readyState +'"');
};
},

Expand All @@ -175,50 +157,39 @@ JsSIP.MediaSession.prototype = {
},

/**
* @param {Object} mediaTypes
* @param {Object} mediaConstraints
* @param {Function} onSuccess
* @param {Function} onFailure
*/
getUserMedia: function(mediaTypes, onSuccess, onFailure) {
getUserMedia: function(mediaConstraints, onSuccess, onFailure) {
var self = this;

function getSuccess(stream) {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'got stream: ' + stream);

//Save the localMedia in order to revoke access to devices later.
self.localMedia = stream;

// Attach the stream to the view if it exists.
if (self.selfView){
self.selfView.src = window.URL.createObjectURL(stream);
}

onSuccess(stream);
}

function getFailure(e) {
onFailure(e);
}

// Get User Media
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'requesting access to local media');
JsSIP.WebRTC.getUserMedia(mediaTypes, getSuccess, getFailure);

JsSIP.WebRTC.getUserMedia(mediaConstraints,
function(stream) {
console.log(JsSIP.C.LOG_MEDIA_SESSION + 'got stream');
self.localMedia = stream;
onSuccess(stream);
},
function(e) {
onFailure(e);
}
);
},

/**
* Message reception once PeerConnection is active.
* Message reception.
* @param {String} type
* @param {String} sdp
* @param {Function} onSuccess
* @param {Function} onFailure
*/
onMessage: function(type, sdp, onSuccess, onFailure) {
if (type === 'offer') {
console.log(JsSIP.C.LOG_MEDIA_SESSION +'new SDP offer received');
} else if (type === 'answer') {
this.peerConnection.setRemoteDescription(
new JsSIP.WebRTC.RTCSessionDescription({type:'answer', sdp:sdp}), onSuccess, onFailure);
}
onMessage: function(type, body, onSuccess, onFailure) {
this.peerConnection.setRemoteDescription(
new JsSIP.WebRTC.RTCSessionDescription({type: type, sdp:body}),
onSuccess,
onFailure
);
}
};
Loading

3 comments on commit 88fa9b6

@saghul
Copy link
Contributor

@saghul saghul commented on 88fa9b6 Feb 19, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What. The. Fuck.

@rvulpescu
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A much better rewrite, great job!

@saghul
Copy link
Contributor

@saghul saghul commented on 88fa9b6 Feb 19, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get too attached to it, this was prematurely committed and API will change a bit.

Please sign in to comment.