2018-06-27 16:43:44 +02:00
"use strict" ;
/ *
* ( C ) Copyright 2017 - 2018 OpenVidu ( https : //openvidu.io/)
*
* Licensed under the Apache License , Version 2.0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an "AS IS" BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*
* /
var _ _extends = ( this && this . _ _extends ) || ( function ( ) {
2018-10-01 11:17:05 +02:00
var extendStatics = function ( d , b ) {
extendStatics = Object . setPrototypeOf ||
( { _ _proto _ _ : [ ] } instanceof Array && function ( d , b ) { d . _ _proto _ _ = b ; } ) ||
function ( d , b ) { for ( var p in b ) if ( b . hasOwnProperty ( p ) ) d [ p ] = b [ p ] ; } ;
return extendStatics ( d , b ) ;
2018-12-14 14:01:16 +01:00
} ;
2018-06-27 16:43:44 +02:00
return function ( d , b ) {
extendStatics ( d , b ) ;
function _ _ ( ) { this . constructor = d ; }
d . prototype = b === null ? Object . create ( b ) : ( _ _ . prototype = b . prototype , new _ _ ( ) ) ;
} ;
} ) ( ) ;
exports . _ _esModule = true ;
var freeice = require ( "freeice" ) ;
var uuid = require ( "uuid" ) ;
2018-12-14 14:01:16 +01:00
var platform = require ( "platform" ) ;
platform [ 'isIonicIos' ] = ( platform . product === 'iPhone' || platform . product === 'iPad' ) && platform . ua . indexOf ( 'Safari' ) === - 1 ;
2018-06-27 16:43:44 +02:00
var WebRtcPeer = /** @class */ ( function ( ) {
function WebRtcPeer ( configuration ) {
var _this = this ;
this . configuration = configuration ;
this . remoteCandidatesQueue = [ ] ;
this . localCandidatesQueue = [ ] ;
this . iceCandidateList = [ ] ;
this . candidategatheringdone = false ;
this . configuration . iceServers = ( ! ! this . configuration . iceServers && this . configuration . iceServers . length > 0 ) ? this . configuration . iceServers : freeice ( ) ;
this . pc = new RTCPeerConnection ( { iceServers : this . configuration . iceServers } ) ;
this . id = ! ! configuration . id ? configuration . id : uuid . v4 ( ) ;
this . pc . onicecandidate = function ( event ) {
2018-10-01 11:17:05 +02:00
if ( ! ! event . candidate ) {
var candidate = event . candidate ;
if ( candidate ) {
_this . localCandidatesQueue . push ( { candidate : candidate . candidate } ) ;
_this . candidategatheringdone = false ;
_this . configuration . onicecandidate ( event . candidate ) ;
}
else if ( ! _this . candidategatheringdone ) {
_this . candidategatheringdone = true ;
}
2018-06-27 16:43:44 +02:00
}
} ;
this . pc . onsignalingstatechange = function ( ) {
if ( _this . pc . signalingState === 'stable' ) {
while ( _this . iceCandidateList . length > 0 ) {
_this . pc . addIceCandidate ( _this . iceCandidateList . shift ( ) ) ;
}
}
} ;
this . start ( ) ;
}
/ * *
* This function creates the RTCPeerConnection object taking into account the
* properties received in the constructor . It starts the SDP negotiation
* process : generates the SDP offer and invokes the onsdpoffer callback . This
* callback is expected to send the SDP offer , in order to obtain an SDP
* answer from another peer .
* /
WebRtcPeer . prototype . start = function ( ) {
var _this = this ;
return new Promise ( function ( resolve , reject ) {
if ( _this . pc . signalingState === 'closed' ) {
reject ( 'The peer connection object is in "closed" state. This is most likely due to an invocation of the dispose method before accepting in the dialogue' ) ;
}
if ( ! ! _this . configuration . mediaStream ) {
2018-12-14 14:01:16 +01:00
if ( platform [ 'isIonicIos' ] ) {
// iOS Ionic. LIMITATION: must use deprecated WebRTC API
2018-11-26 10:30:49 +01:00
var pc2 = _this . pc ;
pc2 . addStream ( _this . configuration . mediaStream ) ;
2018-10-01 11:17:05 +02:00
}
2018-12-14 14:01:16 +01:00
else {
for ( var _i = 0 , _a = _this . configuration . mediaStream . getTracks ( ) ; _i < _a . length ; _i ++ ) {
var track = _a [ _i ] ;
_this . pc . addTrack ( track , _this . configuration . mediaStream ) ;
}
}
2018-10-01 11:17:05 +02:00
resolve ( ) ;
2018-06-27 16:43:44 +02:00
}
} ) ;
} ;
/ * *
* This method frees the resources used by WebRtcPeer
* /
2018-10-01 11:17:05 +02:00
WebRtcPeer . prototype . dispose = function ( videoSourceIsMediaStreamTrack ) {
2018-06-27 16:43:44 +02:00
console . debug ( 'Disposing WebRtcPeer' ) ;
try {
if ( this . pc ) {
if ( this . pc . signalingState === 'closed' ) {
return ;
}
this . remoteCandidatesQueue = [ ] ;
this . localCandidatesQueue = [ ] ;
2018-12-14 14:01:16 +01:00
if ( platform [ 'isIonicIos' ] ) {
// iOS Ionic. LIMITATION: must use deprecated WebRTC API
// Stop senders deprecated
var pc1 = this . pc ;
for ( var _i = 0 , _a = pc1 . getLocalStreams ( ) ; _i < _a . length ; _i ++ ) {
var sender = _a [ _i ] ;
if ( ! videoSourceIsMediaStreamTrack ) {
sender . stop ( ) ;
}
pc1 . removeStream ( sender ) ;
}
// Stop receivers deprecated
for ( var _b = 0 , _c = pc1 . getRemoteStreams ( ) ; _b < _c . length ; _b ++ ) {
var receiver = _c [ _b ] ;
if ( ! ! receiver . track ) {
receiver . stop ( ) ;
}
2018-10-01 11:17:05 +02:00
}
}
2018-12-14 14:01:16 +01:00
else {
// Stop senders
for ( var _d = 0 , _e = this . pc . getSenders ( ) ; _d < _e . length ; _d ++ ) {
var sender = _e [ _d ] ;
if ( ! videoSourceIsMediaStreamTrack ) {
if ( ! ! sender . track ) {
sender . track . stop ( ) ;
}
}
this . pc . removeTrack ( sender ) ;
}
// Stop receivers
for ( var _f = 0 , _g = this . pc . getReceivers ( ) ; _f < _g . length ; _f ++ ) {
var receiver = _g [ _f ] ;
if ( ! ! receiver . track ) {
receiver . track . stop ( ) ;
}
2018-10-01 11:17:05 +02:00
}
}
2018-06-27 16:43:44 +02:00
this . pc . close ( ) ;
}
}
catch ( err ) {
console . warn ( 'Exception disposing webrtc peer ' + err ) ;
}
} ;
/ * *
* 1 ) Function that creates an offer , sets it as local description and returns the offer param
* to send to OpenVidu Server ( will be the remote description of other peer )
* /
WebRtcPeer . prototype . generateOffer = function ( ) {
var _this = this ;
return new Promise ( function ( resolve , reject ) {
var offerAudio , offerVideo = true ;
// Constraints must have both blocks
if ( ! ! _this . configuration . mediaConstraints ) {
offerAudio = ( typeof _this . configuration . mediaConstraints . audio === 'boolean' ) ?
_this . configuration . mediaConstraints . audio : true ;
offerVideo = ( typeof _this . configuration . mediaConstraints . video === 'boolean' ) ?
_this . configuration . mediaConstraints . video : true ;
}
var constraints = {
2018-10-01 11:17:05 +02:00
offerToReceiveAudio : ( _this . configuration . mode !== 'sendonly' && offerAudio ) ,
offerToReceiveVideo : ( _this . configuration . mode !== 'sendonly' && offerVideo )
2018-06-27 16:43:44 +02:00
} ;
console . debug ( 'RTCPeerConnection constraints: ' + JSON . stringify ( constraints ) ) ;
2018-12-14 14:01:16 +01:00
if ( platform . name === 'Safari' && platform . ua . indexOf ( 'Safari' ) !== - 1 ) {
// Safari (excluding Ionic), at least on iOS just seems to support unified plan, whereas in other browsers is not yet ready and considered experimental
if ( offerAudio ) {
_this . pc . addTransceiver ( 'audio' , {
direction : _this . configuration . mode
} ) ;
2018-06-27 16:43:44 +02:00
}
2018-12-14 14:01:16 +01:00
if ( offerVideo ) {
_this . pc . addTransceiver ( 'video' , {
direction : _this . configuration . mode
} ) ;
2018-06-27 16:43:44 +02:00
}
2018-12-14 14:01:16 +01:00
_this . pc
. createOffer ( )
. then ( function ( offer ) {
console . debug ( 'Created SDP offer' ) ;
return _this . pc . setLocalDescription ( offer ) ;
} )
. then ( function ( ) {
var localDescription = _this . pc . localDescription ;
if ( ! ! localDescription ) {
console . debug ( 'Local description set' , localDescription . sdp ) ;
resolve ( localDescription . sdp ) ;
}
else {
reject ( 'Local description is not defined' ) ;
}
} ) [ "catch" ] ( function ( error ) { return reject ( error ) ; } ) ;
}
else {
_this . pc . createOffer ( constraints ) . then ( function ( offer ) {
console . debug ( 'Created SDP offer' ) ;
return _this . pc . setLocalDescription ( offer ) ;
} ) . then ( function ( ) {
var localDescription = _this . pc . localDescription ;
if ( ! ! localDescription ) {
console . debug ( 'Local description set' , localDescription . sdp ) ;
resolve ( localDescription . sdp ) ;
}
else {
reject ( 'Local description is not defined' ) ;
}
} ) [ "catch" ] ( function ( error ) { return reject ( error ) ; } ) ;
}
2018-06-27 16:43:44 +02:00
} ) ;
} ;
/ * *
* 2 ) Function to invoke when a SDP offer is received . Sets it as remote description ,
* generates and answer and returns it to send it to OpenVidu Server
* /
WebRtcPeer . prototype . processOffer = function ( sdpOffer ) {
var _this = this ;
return new Promise ( function ( resolve , reject ) {
var offer = {
type : 'offer' ,
sdp : sdpOffer
} ;
console . debug ( 'SDP offer received, setting remote description' ) ;
if ( _this . pc . signalingState === 'closed' ) {
reject ( 'PeerConnection is closed' ) ;
}
_this . pc . setRemoteDescription ( offer )
. then ( function ( ) {
return _this . pc . createAnswer ( ) ;
} ) . then ( function ( answer ) {
console . debug ( 'Created SDP answer' ) ;
return _this . pc . setLocalDescription ( answer ) ;
} ) . then ( function ( ) {
var localDescription = _this . pc . localDescription ;
if ( ! ! localDescription ) {
console . debug ( 'Local description set' , localDescription . sdp ) ;
resolve ( localDescription . sdp ) ;
}
else {
reject ( 'Local description is not defined' ) ;
}
} ) [ "catch" ] ( function ( error ) { return reject ( error ) ; } ) ;
} ) ;
} ;
/ * *
* 3 ) Function invoked when a SDP answer is received . Final step in SDP negotiation , the peer
* just needs to set the answer as its remote description
* /
2018-12-14 14:01:16 +01:00
WebRtcPeer . prototype . processAnswer = function ( sdpAnswer , needsTimeoutOnProcessAswer ) {
2018-06-27 16:43:44 +02:00
var _this = this ;
return new Promise ( function ( resolve , reject ) {
var answer = {
type : 'answer' ,
sdp : sdpAnswer
} ;
console . debug ( 'SDP answer received, setting remote description' ) ;
if ( _this . pc . signalingState === 'closed' ) {
reject ( 'RTCPeerConnection is closed' ) ;
}
2018-12-14 14:01:16 +01:00
if ( needsTimeoutOnProcessAswer && platform [ 'isIonicIos' ] ) {
setTimeout ( function ( ) {
console . info ( 'setRemoteDescription run after timout for iOS device' ) ;
_this . pc . setRemoteDescription ( answer ) . then ( function ( ) { return resolve ( ) ; } ) [ "catch" ] ( function ( error ) { return reject ( error ) ; } ) ;
} , 250 ) ;
}
else {
_this . pc . setRemoteDescription ( answer ) . then ( function ( ) { return resolve ( ) ; } ) [ "catch" ] ( function ( error ) { return reject ( error ) ; } ) ;
}
2018-06-27 16:43:44 +02:00
} ) ;
} ;
/ * *
* Callback function invoked when an ICE candidate is received
* /
WebRtcPeer . prototype . addIceCandidate = function ( iceCandidate ) {
var _this = this ;
return new Promise ( function ( resolve , reject ) {
console . debug ( 'Remote ICE candidate received' , iceCandidate ) ;
_this . remoteCandidatesQueue . push ( iceCandidate ) ;
switch ( _this . pc . signalingState ) {
case 'closed' :
reject ( new Error ( 'PeerConnection object is closed' ) ) ;
break ;
case 'stable' :
if ( ! ! _this . pc . remoteDescription ) {
_this . pc . addIceCandidate ( iceCandidate ) . then ( function ( ) { return resolve ( ) ; } ) [ "catch" ] ( function ( error ) { return reject ( error ) ; } ) ;
}
break ;
default :
_this . iceCandidateList . push ( iceCandidate ) ;
resolve ( ) ;
}
} ) ;
} ;
return WebRtcPeer ;
} ( ) ) ;
exports . WebRtcPeer = WebRtcPeer ;
var WebRtcPeerRecvonly = /** @class */ ( function ( _super ) {
_ _extends ( WebRtcPeerRecvonly , _super ) ;
function WebRtcPeerRecvonly ( configuration ) {
var _this = this ;
configuration . mode = 'recvonly' ;
_this = _super . call ( this , configuration ) || this ;
return _this ;
}
return WebRtcPeerRecvonly ;
} ( WebRtcPeer ) ) ;
exports . WebRtcPeerRecvonly = WebRtcPeerRecvonly ;
var WebRtcPeerSendonly = /** @class */ ( function ( _super ) {
_ _extends ( WebRtcPeerSendonly , _super ) ;
function WebRtcPeerSendonly ( configuration ) {
var _this = this ;
configuration . mode = 'sendonly' ;
_this = _super . call ( this , configuration ) || this ;
return _this ;
}
return WebRtcPeerSendonly ;
} ( WebRtcPeer ) ) ;
exports . WebRtcPeerSendonly = WebRtcPeerSendonly ;
var WebRtcPeerSendrecv = /** @class */ ( function ( _super ) {
_ _extends ( WebRtcPeerSendrecv , _super ) ;
function WebRtcPeerSendrecv ( configuration ) {
var _this = this ;
configuration . mode = 'sendrecv' ;
_this = _super . call ( this , configuration ) || this ;
return _this ;
}
return WebRtcPeerSendrecv ;
} ( WebRtcPeer ) ) ;
exports . WebRtcPeerSendrecv = WebRtcPeerSendrecv ;
//# sourceMappingURL=WebRtcPeer.js.map