Video call improvements

This commit is contained in:
Ali
2020-08-21 21:11:29 +01:00
parent bb974d4cc1
commit bead41710b
35 changed files with 2734 additions and 2545 deletions

View File

@@ -34,8 +34,6 @@ private func callConnectionDescriptionsWebrtc(_ connection: CallSessionConnectio
}
}
private let callLogsLimit = 20
public func callLogNameForId(id: Int64, account: Account) -> String? {
let path = callLogsPath(account: account)
let namePrefix = "\(id)_"
@@ -63,26 +61,25 @@ private func cleanupCallLogs(account: Account) {
try? fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
}
var oldest: (URL, Date)? = nil
var oldest: [(URL, Date)] = []
var count = 0
if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [.contentModificationDateKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
for url in enumerator {
if let url = url as? URL {
if let date = (try? url.resourceValues(forKeys: Set([.contentModificationDateKey])))?.contentModificationDate {
if let currentOldest = oldest {
if date < currentOldest.1 {
oldest = (url, date)
}
} else {
oldest = (url, date)
}
oldest.append((url, date))
count += 1
}
}
}
}
if count > callLogsLimit, let oldest = oldest {
try? fileManager.removeItem(atPath: oldest.0.path)
let callLogsLimit = 40
if count > callLogsLimit {
oldest.sort(by: { $0.1 > $1.1 })
while oldest.count > callLogsLimit {
try? fileManager.removeItem(atPath: oldest[oldest.count - 1].0.path)
oldest.removeLast()
}
}
}
@@ -271,6 +268,7 @@ private protocol OngoingCallThreadLocalContextProtocol: class {
func nativeSetIsMuted(_ value: Bool)
func nativeSetIsLowBatteryLevel(_ value: Bool)
func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer)
func nativeSetRequestedVideoAspect(_ aspect: Float)
func nativeDisableVideo()
func nativeStop(_ completion: @escaping (String?, Int64, Int64, Int64, Int64) -> Void)
func nativeBeginTermination()
@@ -309,6 +307,9 @@ extension OngoingCallThreadLocalContext: OngoingCallThreadLocalContextProtocol {
func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer) {
}
func nativeSetRequestedVideoAspect(_ aspect: Float) {
}
func nativeDisableVideo() {
}
@@ -347,10 +348,24 @@ public final class OngoingCallVideoCapturer {
setOnFirstFrameReceived: { [weak view] f in
view?.setOnFirstFrameReceived(f)
},
getOrientation: {
return .rotation0
getOrientation: { [weak view] in
if let view = view {
return OngoingCallVideoOrientation(view.orientation)
} else {
return .rotation0
}
},
setOnOrientationUpdated: { _ in
getAspect: { [weak view] in
if let view = view {
return view.aspect
} else {
return 0.0
}
},
setOnOrientationUpdated: { [weak view] f in
view?.setOnOrientationUpdated { value, aspect in
f?(OngoingCallVideoOrientation(value), aspect)
}
},
setOnIsMirroredUpdated: { [weak view] f in
view?.setOnIsMirroredUpdated(f)
@@ -392,6 +407,10 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt
self.requestVideo(capturer.impl)
}
func nativeSetRequestedVideoAspect(_ aspect: Float) {
self.setRequestedVideoAspect(aspect)
}
func nativeDisableVideo() {
self.disableVideo()
}
@@ -456,11 +475,11 @@ private extension OngoingCallVideoOrientation {
case .orientation0:
self = .rotation0
case .orientation90:
self = .rotation270
self = .rotation90
case .orientation180:
self = .rotation180
case .orientation270:
self = .rotation90
self = .rotation270
@unknown default:
self = .rotation0
}
@@ -471,19 +490,22 @@ public final class OngoingCallContextPresentationCallVideoView {
public let view: UIView
public let setOnFirstFrameReceived: (((Float) -> Void)?) -> Void
public let getOrientation: () -> OngoingCallVideoOrientation
public let setOnOrientationUpdated: (((OngoingCallVideoOrientation) -> Void)?) -> Void
public let getAspect: () -> CGFloat
public let setOnOrientationUpdated: (((OngoingCallVideoOrientation, CGFloat) -> Void)?) -> Void
public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void
public init(
view: UIView,
setOnFirstFrameReceived: @escaping (((Float) -> Void)?) -> Void,
getOrientation: @escaping () -> OngoingCallVideoOrientation,
setOnOrientationUpdated: @escaping (((OngoingCallVideoOrientation) -> Void)?) -> Void,
getAspect: @escaping () -> CGFloat,
setOnOrientationUpdated: @escaping (((OngoingCallVideoOrientation, CGFloat) -> Void)?) -> Void,
setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void
) {
self.view = view
self.setOnFirstFrameReceived = setOnFirstFrameReceived
self.getOrientation = getOrientation
self.getAspect = getAspect
self.setOnOrientationUpdated = setOnOrientationUpdated
self.setOnIsMirroredUpdated = setOnIsMirroredUpdated
}
@@ -541,6 +563,9 @@ public final class OngoingCallContext {
return OngoingCallThreadLocalContext.maxLayer()
}
private let tempLogFile: TempBoxFile
private let tempStatsLogFile: TempBoxFile
public static func versions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] {
var result: [(version: String, supportsVideo: Bool)] = [(OngoingCallThreadLocalContext.version(), false)]
if includeExperimental {
@@ -551,7 +576,7 @@ public final class OngoingCallContext {
return result
}
public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?) {
public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, enableStunMarking: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?) {
let _ = setupLogs
OngoingCallThreadLocalContext.applyServerConfig(serializedData)
@@ -560,6 +585,11 @@ public final class OngoingCallContext {
self.callSessionManager = callSessionManager
self.logPath = logName.isEmpty ? "" : callLogsPath(account: self.account) + "/" + logName + ".log"
let logPath = self.logPath
self.tempLogFile = TempBox.shared.tempFile(fileName: "CallLog.txt")
let tempLogPath = self.tempLogFile.path
self.tempStatsLogFile = TempBox.shared.tempFile(fileName: "CallStats.json")
let tempStatsLogPath = self.tempStatsLogFile.path
let queue = self.queue
@@ -581,11 +611,6 @@ public final class OngoingCallContext {
}
}
let screenSize = UIScreen.main.bounds.size
let portraitSize = CGSize(width: min(screenSize.width, screenSize.height), height: max(screenSize.width, screenSize.height))
let preferredAspectRatio = portraitSize.width / portraitSize.height
let unfilteredConnections = [connections.primary] + connections.alternatives
var processedConnections: [CallSessionConnection] = []
var filteredConnections: [OngoingCallConnectionDescriptionWebrtc] = []
@@ -597,9 +622,9 @@ public final class OngoingCallContext {
filteredConnections.append(contentsOf: callConnectionDescriptionsWebrtc(connection))
}
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, enableStunMarking: enableStunMarking, logPath: tempLogPath, statsLogPath: tempStatsLogPath, sendSignalingData: { [weak callSessionManager] data in
callSessionManager?.sendSignalingData(internalId: internalId, data: data)
}, videoCapturer: video?.impl, preferredAspectRatio: Float(preferredAspectRatio), preferredVideoCodec: preferredVideoCodec)
}, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec)
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in
@@ -748,10 +773,15 @@ public final class OngoingCallContext {
public func stop(callId: CallId? = nil, sendDebugLogs: Bool = false, debugLogValue: Promise<String?>) {
let account = self.account
let logPath = self.logPath
var statsLogPath = ""
if !logPath.isEmpty {
statsLogPath = logPath + ".json"
}
let tempLogPath = self.tempLogFile.path
let tempStatsLogPath = self.tempStatsLogFile.path
self.withContextThenDeallocate { context in
context.nativeStop { debugLog, bytesSentWifi, bytesReceivedWifi, bytesSentMobile, bytesReceivedMobile in
debugLogValue.set(.single(debugLog))
let delta = NetworkUsageStatsConnectionsEntry(
cellular: NetworkUsageStatsDirectionsEntry(
incoming: bytesReceivedMobile,
@@ -761,17 +791,22 @@ public final class OngoingCallContext {
outgoing: bytesSentWifi))
updateAccountNetworkUsageStats(account: self.account, category: .call, delta: delta)
if !logPath.isEmpty, let debugLog = debugLog {
if !logPath.isEmpty {
let logsPath = callLogsPath(account: account)
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
if let data = debugLog.data(using: .utf8) {
let _ = try? data.write(to: URL(fileURLWithPath: logPath))
}
let _ = try? FileManager.default.moveItem(atPath: tempLogPath, toPath: logPath)
}
if let callId = callId, let debugLog = debugLog {
if !statsLogPath.isEmpty {
let logsPath = callLogsPath(account: account)
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
let _ = try? FileManager.default.moveItem(atPath: tempStatsLogPath, toPath: statsLogPath)
}
if let callId = callId, !statsLogPath.isEmpty, let data = try? Data(contentsOf: URL(fileURLWithPath: statsLogPath)), let dataString = String(data: data, encoding: .utf8) {
debugLogValue.set(.single(dataString))
if sendDebugLogs {
let _ = saveCallDebugLog(network: self.account.network, callId: callId, log: debugLog).start()
let _ = saveCallDebugLog(network: self.account.network, callId: callId, log: dataString).start()
}
}
}
@@ -800,6 +835,12 @@ public final class OngoingCallContext {
}
}
public func setRequestedVideoAspect(_ aspect: Float) {
self.withContext { context in
context.nativeSetRequestedVideoAspect(aspect)
}
}
public func disableVideo() {
self.withContext { context in
context.nativeDisableVideo()
@@ -837,9 +878,16 @@ public final class OngoingCallContext {
return .rotation0
}
},
getAspect: { [weak view] in
if let view = view {
return view.aspect
} else {
return 0.0
}
},
setOnOrientationUpdated: { [weak view] f in
view?.setOnOrientationUpdated { value in
f?(OngoingCallVideoOrientation(value))
view?.setOnOrientationUpdated { value, aspect in
f?(OngoingCallVideoOrientation(value), aspect)
}
},
setOnIsMirroredUpdated: { [weak view] f in