@ -157,19 +157,14 @@ protocol CallServiceObserver: class {
}
}
/* *
* In the process of establishing a connection between the clients ( ICE process ) we must exchange ICE updates .
* Because this happens via Signal Service it ' s possible the callee user has not accepted any change in the caller ' s
* identity . In which case * each * ICE update would cause an " identity change " warning on the callee ' s device . Since
* this could be several messages , the caller stores all ICE updates until receiving positive confirmation that the
* callee has received a message from us . This positive confirmation comes in the form of the callees ` CallAnswer `
* message .
*/
var sendIceUpdatesImmediately = true
var pendingIceUpdateMessages = [ OWSCallIceUpdateMessage ] ( )
// U s e d t o c o o r d i n a t e p r o m i s e s a c r o s s d e l e g a t e m e t h o d s
var fulfillCallConnectedPromise : ( ( ) -> Void ) ?
private var fulfillCallConnectedPromise : ( ( ) -> Void ) ?
// U s e d b y w a i t F o r P e e r C o n n e c t i o n C l i e n t t o m a k e s u r e a n y r e c e i v e d
// I C E m e s s a g e s w a i t u n t i l t h e p e e r c o n n e c t i o n c l i e n t i s s e t u p .
private var fulfillPeerConnectionClientPromise : ( ( ) -> Void ) ?
private var rejectPeerConnectionClientPromise : ( ( Error ) -> Void ) ?
private var peerConnectionClientPromise : Promise < Void > ?
weak var localVideoTrack : RTCVideoTrack ? {
didSet {
@ -265,9 +260,6 @@ protocol CallServiceObserver: class {
self . call = call
sendIceUpdatesImmediately = false
pendingIceUpdateMessages = [ ]
let callRecord = TSCall ( timestamp : NSDate . ows_millisecondTimeStamp ( ) , withCallNumber : call . remotePhoneNumber , callType : RPRecentCallTypeOutgoingIncomplete , in : call . thread )
callRecord . save ( )
call . callRecord = callRecord
@ -290,6 +282,7 @@ protocol CallServiceObserver: class {
let peerConnectionClient = PeerConnectionClient ( iceServers : iceServers , delegate : self , callDirection : . outgoing , useTurnOnly : useTurnOnly )
Logger . debug ( " \( self . TAG ) setting peerConnectionClient in \( #function ) for call: \( call . identifiersForLogs ) " )
self . peerConnectionClient = peerConnectionClient
self . fulfillPeerConnectionClientPromise ? ( )
return peerConnectionClient . createOffer ( )
} . then { ( sessionDescription : HardenedRTCSessionDescription ) -> Promise < Void > in
@ -356,19 +349,6 @@ protocol CallServiceObserver: class {
return
}
// N o w t h a t w e k n o w t h e r e c i p i e n t t r u s t s o u r i d e n t i t y , w e n o l o n g e r n e e d t o e n q u e u e I C E u p d a t e s .
self . sendIceUpdatesImmediately = true
if pendingIceUpdateMessages . count > 0 {
Logger . error ( " \( self . TAG ) Sending \( pendingIceUpdateMessages . count ) pendingIceUpdateMessages " )
let callMessage = OWSOutgoingCallMessage ( thread : thread , iceUpdateMessages : pendingIceUpdateMessages )
let sendPromise = messageSender . sendCallMessage ( callMessage ) . catch { error in
Logger . error ( " \( self . TAG ) failed to send ice updates in \( #function ) with error: \( error ) " )
}
sendPromise . retainUntilComplete ( )
}
guard let peerConnectionClient = self . peerConnectionClient else {
handleFailedCall ( failedCall : call , error : CallError . assertionError ( description : " peerConnectionClient was unexpectedly nil in \( #function ) " ) )
return
@ -556,6 +536,7 @@ protocol CallServiceObserver: class {
Logger . debug ( " \( self . TAG ) setting peerConnectionClient in \( #function ) for: \( newCall . identifiersForLogs ) " )
let peerConnectionClient = PeerConnectionClient ( iceServers : iceServers , delegate : self , callDirection : . incoming , useTurnOnly : useTurnOnly )
self . peerConnectionClient = peerConnectionClient
self . fulfillPeerConnectionClientPromise ? ( )
let offerSessionDescription = RTCSessionDescription ( type : . offer , sdp : callerSessionDescription )
let constraints = RTCMediaConstraints ( mandatoryConstraints : nil , optionalConstraints : nil )
@ -616,30 +597,33 @@ protocol CallServiceObserver: class {
* Remote client ( could be caller or callee ) sent us a connectivity update
*/
public func handleRemoteAddedIceCandidate ( thread : TSContactThread , callId : UInt64 , sdp : String , lineIndex : Int32 , mid : String ) {
AssertIsOnMainThread( )
Logger . info ( " \( TAG ) called \( #function ) " )
waitForPeerConnectionClient( ) . then { ( ) -> Void in
AssertIsOnMainThread ( )
guard let call = self . call else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) since there is no current call. Call already ended? " )
return
}
guard let call = self . call else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) since there is no current call. Call already ended? " )
return
}
guard call . signalingId = = callId else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) due to callId mismatch. Call already ended? " )
return
}
guard call . signalingId = = callId else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) due to callId mismatch. Call already ended? " )
return
}
guard thread . contactIdentifier ( ) = = call . thread . contactIdentifier ( ) else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) due to thread mismatch. Call already ended? " )
return
}
guard thread . contactIdentifier ( ) = = call . thread . contactIdentifier ( ) else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) due to thread mismatch. Call already ended? " )
return
}
guard let peerConnectionClient = self . peerConnectionClient else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) since there is no current peerConnectionClient. Call already ended? " )
return
}
guard let peerConnectionClient = self . peerConnectionClient else {
Logger . warn ( " ignoring remote ice update for thread: \( thread . uniqueId ) since there is no current peerConnectionClient. Call already ended? " )
return
}
peerConnectionClient . addRemoteIceCandidate ( RTCIceCandidate ( sdp : sdp , sdpMLineIndex : lineIndex , sdpMid : mid ) )
peerConnectionClient . addRemoteIceCandidate ( RTCIceCandidate ( sdp : sdp , sdpMLineIndex : lineIndex , sdpMid : mid ) )
} . catch { error in
Logger . error ( " \( self . TAG ) in \( #function ) failed with error: \( error ) " )
} . retainUntilComplete ( )
}
/* *
@ -665,19 +649,8 @@ protocol CallServiceObserver: class {
let iceUpdateMessage = OWSCallIceUpdateMessage ( callId : call . signalingId , sdp : iceCandidate . sdp , sdpMLineIndex : iceCandidate . sdpMLineIndex , sdpMid : iceCandidate . sdpMid )
if self . sendIceUpdatesImmediately {
Logger . info ( " \( TAG ) in \( #function ) . Sending immediately. " )
let callMessage = OWSOutgoingCallMessage ( thread : call . thread , iceUpdateMessage : iceUpdateMessage )
let sendPromise = self . messageSender . sendCallMessage ( callMessage )
sendPromise . retainUntilComplete ( )
} else {
// F o r o u t g o i n g m e s s a g e s , w e w a i t t o s e n d i c e u p d a t e s u n t i l w e ' r e s u r e c l i e n t r e c e i v e d o u r c a l l m e s s a g e .
// e . g . i f t h e c l i e n t h a s b l o c k e d o u r m e s s a g e d u e t o a n i d e n t i t y c h a n g e , w e ' d o t h e r w i s e
// b o m b a r d t h e m w i t h a b u n c h * m o r e * u n d e c i p h e r a b l e m e s s a g e s .
Logger . info ( " \( TAG ) in \( #function ) . Enqueing for later. " )
self . pendingIceUpdateMessages . append ( iceUpdateMessage )
return
}
let callMessage = OWSOutgoingCallMessage ( thread : call . thread , iceUpdateMessage : iceUpdateMessage )
self . messageSender . sendCallMessage ( callMessage ) . retainUntilComplete ( )
}
/* *
@ -1165,6 +1138,49 @@ protocol CallServiceObserver: class {
// MARK: H e l p e r s
private func waitForPeerConnectionClient ( ) -> Promise < Void > {
AssertIsOnMainThread ( )
guard self . peerConnectionClient = = nil else {
// p e e r C o n n e c t i o n C l i e n t a l r e a d y s e t
return Promise ( value : ( ) )
}
if self . peerConnectionClientPromise = = nil {
createPeerConnectionClientPromise ( )
}
guard let peerConnectionClientPromise = self . peerConnectionClientPromise else {
return Promise ( error : CallError . assertionError ( description : " failed to create peerConnectionClientPromise " ) )
}
return peerConnectionClientPromise
}
private func createPeerConnectionClientPromise ( ) {
AssertIsOnMainThread ( )
guard self . peerConnectionClientPromise = = nil else {
Logger . error ( " expected peerConnectionClientPromise to be nil " )
return
}
guard self . fulfillPeerConnectionClientPromise = = nil else {
Logger . error ( " expected fulfillPeerConnectionClientPromise to be nil " )
return
}
guard self . rejectPeerConnectionClientPromise = = nil else {
Logger . error ( " expected rejectPeerConnectionClientPromise to be nil " )
return
}
let ( promise , fulfill , reject ) = Promise < Void > . pending ( )
self . fulfillPeerConnectionClientPromise = fulfill
self . rejectPeerConnectionClientPromise = reject
self . peerConnectionClientPromise = promise
}
/* *
* RTCIceServers are used when attempting to establish an optimal connection to the other party . SignalService supplies
* a list of servers , plus we have fallback servers hardcoded in the app .
@ -1247,21 +1263,27 @@ protocol CallServiceObserver: class {
Logger . debug ( " \( TAG ) in \( #function ) " )
localVideoTrack = nil
remoteVideoTrack = nil
isRemoteVideoEnabled = false
self . localVideoTrack = nil
self . remoteVideoTrack = nil
self . isRemoteVideoEnabled = false
PeerConnectionClient . stopAudioSession ( )
peerConnectionClient ? . terminate ( )
self . peerConnectionClient ? . terminate ( )
Logger . debug ( " \( TAG ) setting peerConnectionClient in \( #function ) " )
peerConnectionClient = nil
call ? . removeAllObservers ( )
call = nil
sendIceUpdatesImmediately = true
Logger . info ( " \( TAG ) clearing pendingIceUpdateMessages " )
pendingIceUpdateMessages = [ ]
fulfillCallConnectedPromise = nil
self . peerConnectionClient = nil
self . call ? . removeAllObservers ( )
self . call = nil
self . fulfillCallConnectedPromise = nil
// I n c a s e w e ' r e s t i l l w a i t i n g o n t h e p e e r c o n n e c t i o n s e t u p s o m e w h e r e , w e n e e d t o r e j e c t i t t o a v o i d a m e m o r y l e a k .
// T h e r e i s n o h a r m i n r e j e c t i n g a p r e v i o u s l y f u l f i l l e d p r o m i s e .
if let rejectPeerConnectionClientPromise = self . rejectPeerConnectionClientPromise {
rejectPeerConnectionClientPromise ( CallError . obsoleteCall ( description : " Terminating call " ) )
}
self . rejectPeerConnectionClientPromise = nil
self . fulfillPeerConnectionClientPromise = nil
self . peerConnectionClientPromise = nil
}
// MARK: - C a l l O b s e r v e r