Merge branch 'charlesmchen/callThreadSafety3'

pull/1/head
Matthew Chen 9 years ago
commit 2d6851743d

@ -271,7 +271,7 @@ protocol CallServiceObserver: class {
return Promise(error: CallError.assertionError(description: errorDescription)) return Promise(error: CallError.assertionError(description: errorDescription))
} }
return getIceServers().then() { iceServers -> Promise<HardenedRTCSessionDescription> in return getIceServers().then { iceServers -> Promise<HardenedRTCSessionDescription> in
Logger.debug("\(self.TAG) got ice servers:\(iceServers)") Logger.debug("\(self.TAG) got ice servers:\(iceServers)")
let peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self) let peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self)
@ -281,16 +281,17 @@ protocol CallServiceObserver: class {
peerConnectionClient.createSignalingDataChannel() peerConnectionClient.createSignalingDataChannel()
assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance") assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance")
Logger.debug("\(self.TAG) setting peerConnectionClient in \(#function)")
self.peerConnectionClient = peerConnectionClient self.peerConnectionClient = peerConnectionClient
return self.peerConnectionClient!.createOffer() return self.peerConnectionClient!.createOffer()
}.then() { (sessionDescription: HardenedRTCSessionDescription) -> Promise<Void> in }.then { (sessionDescription: HardenedRTCSessionDescription) -> Promise<Void> in
return self.peerConnectionClient!.setLocalSessionDescription(sessionDescription).then() { return self.peerConnectionClient!.setLocalSessionDescription(sessionDescription).then {
let offerMessage = OWSCallOfferMessage(callId: call.signalingId, sessionDescription: sessionDescription.sdp) let offerMessage = OWSCallOfferMessage(callId: call.signalingId, sessionDescription: sessionDescription.sdp)
let callMessage = OWSOutgoingCallMessage(thread: thread, offerMessage: offerMessage) let callMessage = OWSOutgoingCallMessage(thread: thread, offerMessage: offerMessage)
return self.messageSender.sendCallMessage(callMessage) return self.messageSender.sendCallMessage(callMessage)
} }
}.catch() { error in }.catch { error in
Logger.error("\(self.TAG) placing call failed with error: \(error)") Logger.error("\(self.TAG) placing call failed with error: \(error)")
if let callError = error as? CallError { if let callError = error as? CallError {
@ -338,7 +339,7 @@ protocol CallServiceObserver: class {
let sessionDescription = RTCSessionDescription(type: .answer, sdp: sessionDescription) let sessionDescription = RTCSessionDescription(type: .answer, sdp: sessionDescription)
_ = peerConnectionClient.setRemoteSessionDescription(sessionDescription).then { _ = peerConnectionClient.setRemoteSessionDescription(sessionDescription).then {
Logger.debug("\(self.TAG) successfully set remote description") Logger.debug("\(self.TAG) successfully set remote description")
}.catch() { error in }.catch { error in
if let callError = error as? CallError { if let callError = error as? CallError {
self.handleFailedCall(error: callError) self.handleFailedCall(error: callError)
} else { } else {
@ -424,10 +425,11 @@ protocol CallServiceObserver: class {
incomingCallPromise = firstly { incomingCallPromise = firstly {
return getIceServers() return getIceServers()
}.then() { (iceServers: [RTCIceServer]) -> Promise<HardenedRTCSessionDescription> in }.then { (iceServers: [RTCIceServer]) -> Promise<HardenedRTCSessionDescription> in
// FIXME for first time call recipients I think we'll see mic/camera permission requests here, // FIXME for first time call recipients I think we'll see mic/camera permission requests here,
// even though, from the users perspective, no incoming call is yet visible. // even though, from the users perspective, no incoming call is yet visible.
assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance") assert(self.peerConnectionClient == nil, "Unexpected PeerConnectionClient instance")
Logger.debug("\(self.self.TAG) setting peerConnectionClient in \(#function)")
self.peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self) self.peerConnectionClient = PeerConnectionClient(iceServers: iceServers, delegate: self)
let offerSessionDescription = RTCSessionDescription(type: .offer, sdp: callerSessionDescription) let offerSessionDescription = RTCSessionDescription(type: .offer, sdp: callerSessionDescription)
@ -435,14 +437,14 @@ protocol CallServiceObserver: class {
// Find a sessionDescription compatible with my constraints and the remote sessionDescription // Find a sessionDescription compatible with my constraints and the remote sessionDescription
return self.peerConnectionClient!.negotiateSessionDescription(remoteDescription: offerSessionDescription, constraints: constraints) return self.peerConnectionClient!.negotiateSessionDescription(remoteDescription: offerSessionDescription, constraints: constraints)
}.then() { (negotiatedSessionDescription: HardenedRTCSessionDescription) in }.then { (negotiatedSessionDescription: HardenedRTCSessionDescription) in
Logger.debug("\(self.TAG) set the remote description") Logger.debug("\(self.TAG) set the remote description")
let answerMessage = OWSCallAnswerMessage(callId: newCall.signalingId, sessionDescription: negotiatedSessionDescription.sdp) let answerMessage = OWSCallAnswerMessage(callId: newCall.signalingId, sessionDescription: negotiatedSessionDescription.sdp)
let callAnswerMessage = OWSOutgoingCallMessage(thread: thread, answerMessage: answerMessage) let callAnswerMessage = OWSOutgoingCallMessage(thread: thread, answerMessage: answerMessage)
return self.messageSender.sendCallMessage(callAnswerMessage) return self.messageSender.sendCallMessage(callAnswerMessage)
}.then() { }.then {
Logger.debug("\(self.TAG) successfully sent callAnswerMessage") Logger.debug("\(self.TAG) successfully sent callAnswerMessage")
let (promise, fulfill, _) = Promise<Void>.pending() let (promise, fulfill, _) = Promise<Void>.pending()
@ -456,7 +458,7 @@ protocol CallServiceObserver: class {
self.fulfillCallConnectedPromise = fulfill self.fulfillCallConnectedPromise = fulfill
return race(promise, timeout) return race(promise, timeout)
}.catch() { error in }.catch { error in
if let callError = error as? CallError { if let callError = error as? CallError {
self.handleFailedCall(error: callError) self.handleFailedCall(error: callError)
} else { } else {
@ -771,9 +773,9 @@ protocol CallServiceObserver: class {
// If the call hasn't started yet, we don't have a data channel to communicate the hang up. Use Signal Service Message. // If the call hasn't started yet, we don't have a data channel to communicate the hang up. Use Signal Service Message.
let hangupMessage = OWSCallHangupMessage(callId: call.signalingId) let hangupMessage = OWSCallHangupMessage(callId: call.signalingId)
let callMessage = OWSOutgoingCallMessage(thread: thread, hangupMessage: hangupMessage) let callMessage = OWSOutgoingCallMessage(thread: thread, hangupMessage: hangupMessage)
_ = self.messageSender.sendCallMessage(callMessage).then() { _ = self.messageSender.sendCallMessage(callMessage).then {
Logger.debug("\(self.TAG) successfully sent hangup call message to \(thread)") Logger.debug("\(self.TAG) successfully sent hangup call message to \(thread)")
}.catch() { error in }.catch { error in
Logger.error("\(self.TAG) failed to send hangup call message to \(thread) with error: \(error)") Logger.error("\(self.TAG) failed to send hangup call message to \(thread) with error: \(error)")
} }
@ -921,18 +923,28 @@ protocol CallServiceObserver: class {
/** /**
* The connection has been established. The clients can now communicate. * The connection has been established. The clients can now communicate.
*/ */
internal func peerConnectionClientIceConnected(_ peerconnectionClient: PeerConnectionClient) { internal func peerConnectionClientIceConnected(_ peerConnectionClient: PeerConnectionClient) {
AssertIsOnMainThread() AssertIsOnMainThread()
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.TAG) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.handleIceConnected() self.handleIceConnected()
} }
/** /**
* The connection failed to establish. The clients will not be able to communicate. * The connection failed to establish. The clients will not be able to communicate.
*/ */
internal func peerConnectionClientIceFailed(_ peerconnectionClient: PeerConnectionClient) { internal func peerConnectionClientIceFailed(_ peerConnectionClient: PeerConnectionClient) {
AssertIsOnMainThread() AssertIsOnMainThread()
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.TAG) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.handleFailedCall(error: CallError.disconnected) self.handleFailedCall(error: CallError.disconnected)
} }
@ -941,31 +953,51 @@ protocol CallServiceObserver: class {
* reach the local client via the internet. The delegate must shuttle these IceCandates to the other (remote) client * reach the local client via the internet. The delegate must shuttle these IceCandates to the other (remote) client
* out of band, as part of establishing a connection over WebRTC. * out of band, as part of establishing a connection over WebRTC.
*/ */
internal func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, addedLocalIceCandidate iceCandidate: RTCIceCandidate) { internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, addedLocalIceCandidate iceCandidate: RTCIceCandidate) {
AssertIsOnMainThread() AssertIsOnMainThread()
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.TAG) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.handleLocalAddedIceCandidate(iceCandidate) self.handleLocalAddedIceCandidate(iceCandidate)
} }
/** /**
* Once the peerconnection is established, we can receive messages via the data channel, and notify the delegate. * Once the peerconnection is established, we can receive messages via the data channel, and notify the delegate.
*/ */
internal func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, received dataChannelMessage: OWSWebRTCProtosData) { internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, received dataChannelMessage: OWSWebRTCProtosData) {
AssertIsOnMainThread() AssertIsOnMainThread()
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.TAG) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.handleDataChannelMessage(dataChannelMessage) self.handleDataChannelMessage(dataChannelMessage)
} }
internal func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, didUpdateLocal videoTrack: RTCVideoTrack?) { internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, didUpdateLocal videoTrack: RTCVideoTrack?) {
AssertIsOnMainThread() AssertIsOnMainThread()
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.TAG) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.localVideoTrack = videoTrack self.localVideoTrack = videoTrack
self.fireDidUpdateVideoTracks() self.fireDidUpdateVideoTracks()
} }
internal func peerConnectionClient(_ peerconnectionClient: PeerConnectionClient, didUpdateRemote videoTrack: RTCVideoTrack?) { internal func peerConnectionClient(_ peerConnectionClient: PeerConnectionClient, didUpdateRemote videoTrack: RTCVideoTrack?) {
AssertIsOnMainThread() AssertIsOnMainThread()
guard peerConnectionClient == self.peerConnectionClient else {
Logger.debug("\(self.TAG) \(#function) Ignoring event from obsolete peerConnectionClient")
return
}
self.remoteVideoTrack = videoTrack self.remoteVideoTrack = videoTrack
self.fireDidUpdateVideoTracks() self.fireDidUpdateVideoTracks()
} }
@ -981,7 +1013,7 @@ protocol CallServiceObserver: class {
return firstly { return firstly {
return accountManager.getTurnServerInfo() return accountManager.getTurnServerInfo()
}.then() { turnServerInfo -> [RTCIceServer] in }.then { turnServerInfo -> [RTCIceServer] in
Logger.debug("\(self.TAG) got turn server urls: \(turnServerInfo.urls)") Logger.debug("\(self.TAG) got turn server urls: \(turnServerInfo.urls)")
return turnServerInfo.urls.map { url in return turnServerInfo.urls.map { url in
@ -1028,21 +1060,21 @@ protocol CallServiceObserver: class {
Logger.debug("\(TAG) in \(#function)") Logger.debug("\(TAG) in \(#function)")
PeerConnectionClient.stopAudioSession()
peerConnectionClient?.terminate()
peerConnectionClient = nil
localVideoTrack = nil localVideoTrack = nil
remoteVideoTrack = nil remoteVideoTrack = nil
isRemoteVideoEnabled = false isRemoteVideoEnabled = false
PeerConnectionClient.stopAudioSession()
peerConnectionClient?.terminate()
Logger.debug("\(TAG) setting peerConnectionClient in \(#function)")
peerConnectionClient = nil
call?.removeAllObservers() call?.removeAllObservers()
call = nil call = nil
thread = nil thread = nil
incomingCallPromise = nil incomingCallPromise = nil
sendIceUpdatesImmediately = true sendIceUpdatesImmediately = true
pendingIceUpdateMessages = [] pendingIceUpdateMessages = []
fireDidUpdateVideoTracks()
} }
// MARK: - CallObserver // MARK: - CallObserver

@ -423,10 +423,7 @@ class PeerConnectionClient: NSObject, RTCPeerConnectionDelegate, RTCDataChannelD
AssertIsOnMainThread() AssertIsOnMainThread()
Logger.debug("\(TAG) in \(#function)") Logger.debug("\(TAG) in \(#function)")
delegate.peerConnectionClient(self, didUpdateLocal: nil) PeerConnectionClient.signalingQueue.sync {
delegate.peerConnectionClient(self, didUpdateRemote: nil)
PeerConnectionClient.signalingQueue.async {
assert(self.peerConnection != nil) assert(self.peerConnection != nil)
self.terminateInternal() self.terminateInternal()
} }

Loading…
Cancel
Save