Screen sharing in 1-to-1 calls

This commit is contained in:
Ali
2021-07-23 18:02:47 +02:00
parent 37c6de33ff
commit ee7116ff15
25 changed files with 395 additions and 275 deletions

View File

@@ -186,7 +186,7 @@ final class PresentationCallToneRenderer {
}
public final class PresentationCallImpl: PresentationCall {
public let account: Account
public let context: AccountContext
private let audioSession: ManagedAudioSession
private let callSessionManager: CallSessionManager
private let callKitIntegration: CallKitIntegration?
@@ -286,11 +286,19 @@ public final class PresentationCallImpl: PresentationCall {
private var useFrontCamera: Bool = true
private var videoCapturer: OngoingCallVideoCapturer?
private var screencastBufferServerContext: IpcGroupCallBufferAppContext?
private var screencastCapturer: OngoingCallVideoCapturer?
private var isScreencastActive: Bool = false
private var proximityManagerIndex: Int?
private let screencastFramesDisposable = MetaDisposable()
private let screencastAudioDataDisposable = MetaDisposable()
private let screencastStateDisposable = MetaDisposable()
init(
account: Account,
context: AccountContext,
audioSession: ManagedAudioSession,
callSessionManager: CallSessionManager,
callKitIntegration: CallKitIntegration?,
@@ -313,7 +321,7 @@ public final class PresentationCallImpl: PresentationCall {
enableTCP: Bool,
preferredVideoCodec: String?
) {
self.account = account
self.context = context
self.audioSession = audioSession
self.callSessionManager = callSessionManager
self.callKitIntegration = callKitIntegration
@@ -345,7 +353,7 @@ public final class PresentationCallImpl: PresentationCall {
self.isVideo = startWithVideo
if self.isVideo {
self.videoCapturer = OngoingCallVideoCapturer()
self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: .active, remoteVideoState: .inactive, remoteAudioState: .active, remoteBatteryLevel: .normal))
self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: .active(isScreencast: self.isScreencastActive), remoteVideoState: .inactive, remoteAudioState: .active, remoteBatteryLevel: .normal))
} else {
self.statePromise.set(PresentationCallState(state: isOutgoing ? .waiting : .ringing, videoState: self.isVideoPossible ? .inactive : .notAvailable, remoteVideoState: .inactive, remoteAudioState: .active, remoteBatteryLevel: .normal))
}
@@ -457,6 +465,11 @@ public final class PresentationCallImpl: PresentationCall {
strongSelf.updateIsAudioSessionActive(value)
}
})
let screencastCapturer = OngoingCallVideoCapturer(isCustom: true)
self.screencastCapturer = screencastCapturer
self.resetScreencastContext()
if callKitIntegration == nil {
self.proximityManagerIndex = DeviceProximityManager.shared().add { _ in
@@ -473,6 +486,9 @@ public final class PresentationCallImpl: PresentationCall {
self.audioLevelDisposable?.dispose()
self.batteryLevelDisposable?.dispose()
self.audioSessionDisposable?.dispose()
self.screencastFramesDisposable.dispose()
self.screencastAudioDataDisposable.dispose()
self.screencastStateDisposable.dispose()
if let dropCallKitCallTimer = self.dropCallKitCallTimer {
dropCallKitCallTimer.invalidate()
@@ -530,11 +546,11 @@ public final class PresentationCallImpl: PresentationCall {
case .notAvailable:
mappedVideoState = .notAvailable
case .active:
mappedVideoState = .active
mappedVideoState = .active(isScreencast: self.isScreencastActive)
case .inactive:
mappedVideoState = .inactive
case .paused:
mappedVideoState = .paused
mappedVideoState = .paused(isScreencast: self.isScreencastActive)
}
switch callContextState.remoteVideoState {
case .inactive:
@@ -565,7 +581,7 @@ public final class PresentationCallImpl: PresentationCall {
mappedVideoState = previousVideoState
} else {
if self.isVideo {
mappedVideoState = .active
mappedVideoState = .active(isScreencast: self.isScreencastActive)
} else if self.isVideoPossible && sessionState.isVideoPossible {
mappedVideoState = .inactive
} else {
@@ -664,7 +680,7 @@ public final class PresentationCallImpl: PresentationCall {
if let _ = audioSessionControl, !wasActive || previousControl == nil {
let logName = "\(id.id)_\(id.accessHash)"
let ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: connections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, enableTCP: self.enableTCP, enableStunMarking: self.enableStunMarking, audioSessionActive: self.audioSessionActive.get(), logName: logName, preferredVideoCodec: self.preferredVideoCodec)
let ongoingContext = OngoingCallContext(account: self.context.account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: connections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, enableTCP: self.enableTCP, enableStunMarking: self.enableStunMarking, audioSessionActive: self.audioSessionActive.get(), logName: logName, preferredVideoCodec: self.preferredVideoCodec)
self.ongoingContext = ongoingContext
ongoingContext.setIsMuted(self.isMutedValue)
if let requestedVideoAspect = self.requestedVideoAspect {
@@ -927,6 +943,57 @@ public final class PresentationCallImpl: PresentationCall {
self.ongoingContext?.disableVideo()
}
}
private func resetScreencastContext() {
let basePath = self.context.sharedContext.basePath + "/broadcast-coordination"
let screencastBufferServerContext = IpcGroupCallBufferAppContext(basePath: basePath)
self.screencastBufferServerContext = screencastBufferServerContext
self.screencastFramesDisposable.set((screencastBufferServerContext.frames
|> deliverOnMainQueue).start(next: { [weak screencastCapturer] screencastFrame in
guard let screencastCapturer = screencastCapturer else {
return
}
screencastCapturer.injectPixelBuffer(screencastFrame.0, rotation: screencastFrame.1)
}))
self.screencastAudioDataDisposable.set((screencastBufferServerContext.audioData
|> deliverOnMainQueue).start(next: { _ in
}))
self.screencastStateDisposable.set((screencastBufferServerContext.isActive
|> distinctUntilChanged
|> deliverOnMainQueue).start(next: { [weak self] isActive in
guard let strongSelf = self else {
return
}
if isActive {
strongSelf.requestScreencast()
} else {
strongSelf.disableScreencast(reset: false)
}
}))
}
private func requestScreencast() {
self.disableVideo()
if let screencastCapturer = self.screencastCapturer {
self.isScreencastActive = true
self.ongoingContext?.requestVideo(screencastCapturer)
}
}
func disableScreencast(reset: Bool = true) {
if self.isScreencastActive {
if let _ = self.videoCapturer {
self.videoCapturer = nil
}
self.isScreencastActive = false
self.ongoingContext?.disableVideo()
if reset {
self.resetScreencastContext()
}
}
}
public func setOutgoingVideoIsPaused(_ isPaused: Bool) {
self.videoCapturer?.setIsVideoEnabled(!isPaused)