mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Call updates
This commit is contained in:
parent
c37cc451ec
commit
92a6a73f6f
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -11,9 +11,6 @@ url=https://github.com/bazelbuild/rules_swift.git
|
|||||||
[submodule "build-system/bazel-rules/apple_support"]
|
[submodule "build-system/bazel-rules/apple_support"]
|
||||||
path = build-system/bazel-rules/apple_support
|
path = build-system/bazel-rules/apple_support
|
||||||
url = https://github.com/bazelbuild/apple_support.git
|
url = https://github.com/bazelbuild/apple_support.git
|
||||||
[submodule "submodules/TgVoip/libtgvoip"]
|
|
||||||
path = submodules/TgVoip/libtgvoip
|
|
||||||
url = https://github.com/telegramdesktop/libtgvoip.git
|
|
||||||
[submodule "submodules/TgVoipWebrtc/tgcalls"]
|
[submodule "submodules/TgVoipWebrtc/tgcalls"]
|
||||||
path = submodules/TgVoipWebrtc/tgcalls
|
path = submodules/TgVoipWebrtc/tgcalls
|
||||||
url=../tgcalls.git
|
url=../tgcalls.git
|
||||||
|
@ -15,7 +15,6 @@ swift_library(
|
|||||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||||
"//submodules/TelegramCore:TelegramCore",
|
"//submodules/TelegramCore:TelegramCore",
|
||||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||||
"//submodules/TgVoip:TgVoip",
|
|
||||||
"//submodules/TgVoipWebrtc:TgVoipWebrtc",
|
"//submodules/TgVoipWebrtc:TgVoipWebrtc",
|
||||||
"//submodules/FFMpegBinding",
|
"//submodules/FFMpegBinding",
|
||||||
"//submodules/ManagedFile",
|
"//submodules/ManagedFile",
|
||||||
|
@ -4,7 +4,6 @@ import TelegramCore
|
|||||||
import Network
|
import Network
|
||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
|
|
||||||
import TgVoip
|
|
||||||
import TgVoipWebrtc
|
import TgVoipWebrtc
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -13,14 +12,6 @@ import AppBundle
|
|||||||
import Accelerate
|
import Accelerate
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private func debugUseLegacyVersionForReflectors() -> Bool {
|
|
||||||
#if DEBUG && false
|
|
||||||
return true
|
|
||||||
#else
|
|
||||||
return false
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct PeerTag: Hashable, CustomStringConvertible {
|
private struct PeerTag: Hashable, CustomStringConvertible {
|
||||||
var bytes: [UInt8] = Array<UInt8>(repeating: 0, count: 16)
|
var bytes: [UInt8] = Array<UInt8>(repeating: 0, count: 16)
|
||||||
|
|
||||||
@ -167,11 +158,6 @@ private func cleanupCallLogs(account: Account) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private let setupLogs: Bool = {
|
private let setupLogs: Bool = {
|
||||||
OngoingCallThreadLocalContext.setupLoggingFunction({ value in
|
|
||||||
if let value = value {
|
|
||||||
Logger.shared.log("TGVOIP", value)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
OngoingCallThreadLocalContextWebrtc.setupLoggingFunction({ value in
|
OngoingCallThreadLocalContextWebrtc.setupLoggingFunction({ value in
|
||||||
if let value = value {
|
if let value = value {
|
||||||
Logger.shared.log("TGVOIP", value)
|
Logger.shared.log("TGVOIP", value)
|
||||||
@ -253,26 +239,6 @@ private final class OngoingCallThreadLocalContextQueueImpl: NSObject, OngoingCal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func ongoingNetworkTypeForType(_ type: NetworkType) -> OngoingCallNetworkType {
|
|
||||||
switch type {
|
|
||||||
case .none:
|
|
||||||
return .wifi
|
|
||||||
case .wifi:
|
|
||||||
return .wifi
|
|
||||||
case let .cellular(cellular):
|
|
||||||
switch cellular {
|
|
||||||
case .edge:
|
|
||||||
return .cellularEdge
|
|
||||||
case .gprs:
|
|
||||||
return .cellularGprs
|
|
||||||
case .thirdG, .unknown:
|
|
||||||
return .cellular3g
|
|
||||||
case .lte:
|
|
||||||
return .cellularLte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func ongoingNetworkTypeForTypeWebrtc(_ type: NetworkType) -> OngoingCallNetworkTypeWebrtc {
|
private func ongoingNetworkTypeForTypeWebrtc(_ type: NetworkType) -> OngoingCallNetworkTypeWebrtc {
|
||||||
switch type {
|
switch type {
|
||||||
case .none:
|
case .none:
|
||||||
@ -293,39 +259,6 @@ private func ongoingNetworkTypeForTypeWebrtc(_ type: NetworkType) -> OngoingCall
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private func ongoingNetworkTypeForTypeWebrtcCustom(_ type: NetworkType) -> OngoingCallNetworkTypeWebrtcCustom {
|
|
||||||
switch type {
|
|
||||||
case .none:
|
|
||||||
return .wifi
|
|
||||||
case .wifi:
|
|
||||||
return .wifi
|
|
||||||
case let .cellular(cellular):
|
|
||||||
switch cellular {
|
|
||||||
case .edge:
|
|
||||||
return .cellularEdge
|
|
||||||
case .gprs:
|
|
||||||
return .cellularGprs
|
|
||||||
case .thirdG, .unknown:
|
|
||||||
return .cellular3g
|
|
||||||
case .lte:
|
|
||||||
return .cellularLte
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private func ongoingDataSavingForType(_ type: VoiceCallDataSaving) -> OngoingCallDataSaving {
|
|
||||||
switch type {
|
|
||||||
case .never:
|
|
||||||
return .never
|
|
||||||
case .cellular:
|
|
||||||
return .cellular
|
|
||||||
case .always:
|
|
||||||
return .always
|
|
||||||
default:
|
|
||||||
return .never
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func ongoingDataSavingForTypeWebrtc(_ type: VoiceCallDataSaving) -> OngoingCallDataSavingWebrtc {
|
private func ongoingDataSavingForTypeWebrtc(_ type: VoiceCallDataSaving) -> OngoingCallDataSavingWebrtc {
|
||||||
switch type {
|
switch type {
|
||||||
case .never:
|
case .never:
|
||||||
@ -363,56 +296,6 @@ private final class OngoingCallThreadLocalContextHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension OngoingCallThreadLocalContext: OngoingCallThreadLocalContextProtocol {
|
|
||||||
func nativeSetNetworkType(_ type: NetworkType) {
|
|
||||||
self.setNetworkType(ongoingNetworkTypeForType(type))
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeStop(_ completion: @escaping (String?, Int64, Int64, Int64, Int64) -> Void) {
|
|
||||||
self.stop(completion)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeBeginTermination() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeSetIsMuted(_ value: Bool) {
|
|
||||||
self.setIsMuted(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeSetIsLowBatteryLevel(_ value: Bool) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeSetRequestedVideoAspect(_ aspect: Float) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeDisableVideo() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeSwitchVideoCamera() {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeDebugInfo() -> String {
|
|
||||||
return self.debugInfo() ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeVersion() -> String {
|
|
||||||
return self.version() ?? ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeGetDerivedState() -> Data {
|
|
||||||
return self.getDerivedState()
|
|
||||||
}
|
|
||||||
|
|
||||||
func addExternalAudioData(data: Data) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func nativeSetIsAudioSessionActive(isActive: Bool) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if targetEnvironment(simulator)
|
#if targetEnvironment(simulator)
|
||||||
private extension UIImage {
|
private extension UIImage {
|
||||||
@available(iOS 13.0, *)
|
@available(iOS 13.0, *)
|
||||||
@ -816,23 +699,6 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension OngoingCallContextState.State {
|
|
||||||
init(_ state: OngoingCallState) {
|
|
||||||
switch state {
|
|
||||||
case .initializing:
|
|
||||||
self = .initializing
|
|
||||||
case .connected:
|
|
||||||
self = .connected
|
|
||||||
case .failed:
|
|
||||||
self = .failed
|
|
||||||
case .reconnecting:
|
|
||||||
self = .reconnecting
|
|
||||||
default:
|
|
||||||
self = .failed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension OngoingCallContextState.State {
|
private extension OngoingCallContextState.State {
|
||||||
init(_ state: OngoingCallStateWebrtc) {
|
init(_ state: OngoingCallStateWebrtc) {
|
||||||
switch state {
|
switch state {
|
||||||
@ -1014,7 +880,7 @@ public final class OngoingCallContext {
|
|||||||
private var networkTypeDisposable: Disposable?
|
private var networkTypeDisposable: Disposable?
|
||||||
|
|
||||||
public static var maxLayer: Int32 {
|
public static var maxLayer: Int32 {
|
||||||
return OngoingCallThreadLocalContext.maxLayer()
|
return OngoingCallThreadLocalContextWebrtc.maxLayer()
|
||||||
}
|
}
|
||||||
|
|
||||||
private let tempStatsLogFile: EngineTempBox.File
|
private let tempStatsLogFile: EngineTempBox.File
|
||||||
@ -1024,26 +890,15 @@ public final class OngoingCallContext {
|
|||||||
private let audioDevice: AudioDevice?
|
private let audioDevice: AudioDevice?
|
||||||
|
|
||||||
public static func versions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] {
|
public static func versions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] {
|
||||||
#if os(iOS) && DEBUG && false
|
var result: [(version: String, supportsVideo: Bool)] = []
|
||||||
if "".isEmpty {
|
result.append(contentsOf: OngoingCallThreadLocalContextWebrtc.versions(withIncludeReference: includeReference).map { version -> (version: String, supportsVideo: Bool) in
|
||||||
return [("5.0.0", true)]
|
return (version, true)
|
||||||
}
|
})
|
||||||
#endif
|
return result
|
||||||
|
|
||||||
if debugUseLegacyVersionForReflectors() {
|
|
||||||
return [(OngoingCallThreadLocalContext.version(), true)]
|
|
||||||
} else {
|
|
||||||
var result: [(version: String, supportsVideo: Bool)] = [(OngoingCallThreadLocalContext.version(), false)]
|
|
||||||
result.append(contentsOf: OngoingCallThreadLocalContextWebrtc.versions(withIncludeReference: includeReference).map { version -> (version: String, supportsVideo: Bool) in
|
|
||||||
return (version, true)
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(account: Account, callSessionManager: CallSessionManager, callId: CallId, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowP2P: Bool, enableTCP: Bool, enableStunMarking: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?, audioDevice: AudioDevice?) {
|
public init(account: Account, callSessionManager: CallSessionManager, callId: CallId, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, customParameters: String?, allowP2P: Bool, enableTCP: Bool, enableStunMarking: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?, audioDevice: AudioDevice?) {
|
||||||
let _ = setupLogs
|
let _ = setupLogs
|
||||||
OngoingCallThreadLocalContext.applyServerConfig(serializedData)
|
|
||||||
|
|
||||||
self.callId = callId
|
self.callId = callId
|
||||||
self.internalId = internalId
|
self.internalId = internalId
|
||||||
@ -1068,311 +923,274 @@ public final class OngoingCallContext {
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOn(queue)).start(next: { [weak self] _ in
|
|> deliverOn(queue)).start(next: { [weak self] _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
var useModernImplementation = true
|
|
||||||
var version = version
|
|
||||||
var allowP2P = allowP2P
|
var allowP2P = allowP2P
|
||||||
if debugUseLegacyVersionForReflectors() {
|
|
||||||
useModernImplementation = true
|
var voipProxyServer: VoipProxyServerWebrtc?
|
||||||
version = "12.0.0"
|
if let proxyServer = proxyServer {
|
||||||
allowP2P = false
|
switch proxyServer.connection {
|
||||||
} else {
|
case let .socks5(username, password):
|
||||||
useModernImplementation = version != OngoingCallThreadLocalContext.version()
|
voipProxyServer = VoipProxyServerWebrtc(host: proxyServer.host, port: proxyServer.port, username: username, password: password)
|
||||||
|
case .mtp:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if useModernImplementation {
|
var unfilteredConnections: [CallSessionConnection]
|
||||||
var voipProxyServer: VoipProxyServerWebrtc?
|
unfilteredConnections = [connections.primary] + connections.alternatives
|
||||||
if let proxyServer = proxyServer {
|
|
||||||
switch proxyServer.connection {
|
if version == "12.0.0" {
|
||||||
case let .socks5(username, password):
|
|
||||||
voipProxyServer = VoipProxyServerWebrtc(host: proxyServer.host, port: proxyServer.port, username: username, password: password)
|
|
||||||
case .mtp:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var unfilteredConnections: [CallSessionConnection]
|
|
||||||
unfilteredConnections = [connections.primary] + connections.alternatives
|
|
||||||
|
|
||||||
if version == "12.0.0" {
|
|
||||||
for connection in unfilteredConnections {
|
|
||||||
if case let .reflector(reflector) = connection {
|
|
||||||
unfilteredConnections.append(.reflector(CallSessionConnection.Reflector(
|
|
||||||
id: 123456,
|
|
||||||
ip: "91.108.9.38",
|
|
||||||
ipv6: "",
|
|
||||||
isTcp: true,
|
|
||||||
port: 595,
|
|
||||||
peerTag: reflector.peerTag
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var reflectorIdList: [Int64] = []
|
|
||||||
for connection in unfilteredConnections {
|
for connection in unfilteredConnections {
|
||||||
switch connection {
|
if case let .reflector(reflector) = connection {
|
||||||
case let .reflector(reflector):
|
unfilteredConnections.append(.reflector(CallSessionConnection.Reflector(
|
||||||
reflectorIdList.append(reflector.id)
|
id: 123456,
|
||||||
case .webRtcReflector:
|
ip: "91.108.9.38",
|
||||||
break
|
ipv6: "",
|
||||||
|
isTcp: true,
|
||||||
|
port: 595,
|
||||||
|
peerTag: reflector.peerTag
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
reflectorIdList.sort()
|
|
||||||
|
var reflectorIdList: [Int64] = []
|
||||||
var reflectorIdMapping: [Int64: UInt8] = [:]
|
for connection in unfilteredConnections {
|
||||||
for i in 0 ..< reflectorIdList.count {
|
switch connection {
|
||||||
reflectorIdMapping[reflectorIdList[i]] = UInt8(i + 1)
|
case let .reflector(reflector):
|
||||||
|
reflectorIdList.append(reflector.id)
|
||||||
|
case .webRtcReflector:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reflectorIdList.sort()
|
||||||
|
|
||||||
|
var reflectorIdMapping: [Int64: UInt8] = [:]
|
||||||
|
for i in 0 ..< reflectorIdList.count {
|
||||||
|
reflectorIdMapping[reflectorIdList[i]] = UInt8(i + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var signalingReflector: OngoingCallConnectionDescriptionWebrtc?
|
||||||
|
|
||||||
|
var processedConnections: [CallSessionConnection] = []
|
||||||
|
var filteredConnections: [OngoingCallConnectionDescriptionWebrtc] = []
|
||||||
|
connectionsLoop: for connection in unfilteredConnections {
|
||||||
|
if processedConnections.contains(connection) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
processedConnections.append(connection)
|
||||||
|
|
||||||
var signalingReflector: OngoingCallConnectionDescriptionWebrtc?
|
switch connection {
|
||||||
|
case let .reflector(reflector):
|
||||||
var processedConnections: [CallSessionConnection] = []
|
if reflector.isTcp {
|
||||||
var filteredConnections: [OngoingCallConnectionDescriptionWebrtc] = []
|
if version == "12.0.0" {
|
||||||
connectionsLoop: for connection in unfilteredConnections {
|
/*if signalingReflector == nil {
|
||||||
if processedConnections.contains(connection) {
|
signalingReflector = OngoingCallConnectionDescriptionWebrtc(reflectorId: 0, hasStun: false, hasTurn: true, hasTcp: true, ip: reflector.ip, port: reflector.port, username: "reflector", password: hexString(reflector.peerTag))
|
||||||
continue
|
}*/
|
||||||
}
|
} else {
|
||||||
processedConnections.append(connection)
|
if signalingReflector == nil {
|
||||||
|
signalingReflector = OngoingCallConnectionDescriptionWebrtc(reflectorId: 0, hasStun: false, hasTurn: true, hasTcp: true, ip: reflector.ip, port: reflector.port, username: "reflector", password: hexString(reflector.peerTag))
|
||||||
switch connection {
|
|
||||||
case let .reflector(reflector):
|
|
||||||
if reflector.isTcp {
|
|
||||||
if version == "12.0.0" {
|
|
||||||
/*if signalingReflector == nil {
|
|
||||||
signalingReflector = OngoingCallConnectionDescriptionWebrtc(reflectorId: 0, hasStun: false, hasTurn: true, hasTcp: true, ip: reflector.ip, port: reflector.port, username: "reflector", password: hexString(reflector.peerTag))
|
|
||||||
}*/
|
|
||||||
} else {
|
|
||||||
if signalingReflector == nil {
|
|
||||||
signalingReflector = OngoingCallConnectionDescriptionWebrtc(reflectorId: 0, hasStun: false, hasTurn: true, hasTcp: true, ip: reflector.ip, port: reflector.port, username: "reflector", password: hexString(reflector.peerTag))
|
|
||||||
}
|
|
||||||
|
|
||||||
continue connectionsLoop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case .webRtcReflector:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
var webrtcConnections: [OngoingCallConnectionDescriptionWebrtc] = []
|
|
||||||
for connection in callConnectionDescriptionsWebrtc(connection, idMapping: reflectorIdMapping) {
|
|
||||||
webrtcConnections.append(connection)
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredConnections.append(contentsOf: webrtcConnections)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let signalingReflector = signalingReflector {
|
|
||||||
if #available(iOS 12.0, *) {
|
|
||||||
let peerTag = dataWithHexString(signalingReflector.password)
|
|
||||||
|
|
||||||
strongSelf.signalingConnectionManager = QueueLocalObject(queue: queue, generate: {
|
|
||||||
return CallSignalingConnectionManager(queue: queue, peerTag: peerTag, servers: [signalingReflector], dataReceived: { data in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
strongSelf.withContext { context in
|
|
||||||
if let context = context as? OngoingCallThreadLocalContextWebrtc {
|
|
||||||
context.addSignaling(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var directConnection: OngoingCallDirectConnection?
|
|
||||||
if version == "9.0.0" && !"".isEmpty {
|
|
||||||
if #available(iOS 12.0, *) {
|
|
||||||
for connection in filteredConnections {
|
|
||||||
if connection.username == "reflector" && connection.reflectorId == 1 && !connection.hasTcp && connection.hasTurn {
|
|
||||||
directConnection = CallDirectConnectionImpl(host: connection.ip, port: Int(connection.port), peerTag: dataWithHexString(connection.password))
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
continue connectionsLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
case .webRtcReflector:
|
||||||
directConnection = nil
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG && true
|
var webrtcConnections: [OngoingCallConnectionDescriptionWebrtc] = []
|
||||||
var customParameters = customParameters
|
for connection in callConnectionDescriptionsWebrtc(connection, idMapping: reflectorIdMapping) {
|
||||||
if let initialCustomParameters = try? JSONSerialization.jsonObject(with: (customParameters ?? "{}").data(using: .utf8)!) as? [String: Any] {
|
webrtcConnections.append(connection)
|
||||||
var customParametersValue: [String: Any]
|
}
|
||||||
customParametersValue = initialCustomParameters
|
|
||||||
if version == "12.0.0" {
|
filteredConnections.append(contentsOf: webrtcConnections)
|
||||||
customParametersValue["network_use_tcponly"] = true as NSNumber
|
}
|
||||||
customParameters = String(data: try! JSONSerialization.data(withJSONObject: customParametersValue), encoding: .utf8)!
|
|
||||||
}
|
if let signalingReflector = signalingReflector {
|
||||||
|
if #available(iOS 12.0, *) {
|
||||||
|
let peerTag = dataWithHexString(signalingReflector.password)
|
||||||
|
|
||||||
if let value = customParametersValue["network_use_tcponly"] as? Bool, value {
|
strongSelf.signalingConnectionManager = QueueLocalObject(queue: queue, generate: {
|
||||||
filteredConnections = filteredConnections.filter { connection in
|
return CallSignalingConnectionManager(queue: queue, peerTag: peerTag, servers: [signalingReflector], dataReceived: { data in
|
||||||
if connection.hasTcp {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
allowP2P = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*#if DEBUG
|
|
||||||
if let initialCustomParameters = try? JSONSerialization.jsonObject(with: (customParameters ?? "{}").data(using: .utf8)!) as? [String: Any] {
|
|
||||||
var customParametersValue: [String: Any]
|
|
||||||
customParametersValue = initialCustomParameters
|
|
||||||
customParametersValue["network_kcp_experiment"] = true as NSNumber
|
|
||||||
customParameters = String(data: try! JSONSerialization.data(withJSONObject: customParametersValue), encoding: .utf8)!
|
|
||||||
}
|
|
||||||
#endif*/
|
|
||||||
|
|
||||||
let context = OngoingCallThreadLocalContextWebrtc(
|
|
||||||
version: version,
|
|
||||||
customParameters: customParameters,
|
|
||||||
queue: OngoingCallThreadLocalContextQueueImpl(queue: queue),
|
|
||||||
proxy: voipProxyServer,
|
|
||||||
networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType),
|
|
||||||
dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving),
|
|
||||||
derivedState: Data(),
|
|
||||||
key: key,
|
|
||||||
isOutgoing: isOutgoing,
|
|
||||||
connections: filteredConnections,
|
|
||||||
maxLayer: maxLayer,
|
|
||||||
allowP2P: allowP2P,
|
|
||||||
allowTCP: enableTCP,
|
|
||||||
enableStunMarking: enableStunMarking,
|
|
||||||
logPath: logPath,
|
|
||||||
statsLogPath: tempStatsLogPath,
|
|
||||||
sendSignalingData: { [weak callSessionManager] data in
|
|
||||||
queue.async {
|
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let signalingConnectionManager = strongSelf.signalingConnectionManager {
|
strongSelf.withContext { context in
|
||||||
signalingConnectionManager.with { impl in
|
if let context = context as? OngoingCallThreadLocalContextWebrtc {
|
||||||
impl.send(payloadData: data)
|
context.addSignaling(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
if let callSessionManager = callSessionManager {
|
})
|
||||||
callSessionManager.sendSignalingData(internalId: internalId, data: data)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var directConnection: OngoingCallDirectConnection?
|
||||||
|
if version == "9.0.0" && !"".isEmpty {
|
||||||
|
if #available(iOS 12.0, *) {
|
||||||
|
for connection in filteredConnections {
|
||||||
|
if connection.username == "reflector" && connection.reflectorId == 1 && !connection.hasTcp && connection.hasTurn {
|
||||||
|
directConnection = CallDirectConnectionImpl(host: connection.ip, port: Int(connection.port), peerTag: dataWithHexString(connection.password))
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
videoCapturer: video?.impl,
|
}
|
||||||
preferredVideoCodec: preferredVideoCodec,
|
} else {
|
||||||
audioInputDeviceId: "",
|
directConnection = nil
|
||||||
audioDevice: audioDevice?.impl,
|
}
|
||||||
directConnection: directConnection
|
|
||||||
)
|
#if DEBUG && true
|
||||||
|
var customParameters = customParameters
|
||||||
|
if let initialCustomParameters = try? JSONSerialization.jsonObject(with: (customParameters ?? "{}").data(using: .utf8)!) as? [String: Any] {
|
||||||
|
var customParametersValue: [String: Any]
|
||||||
|
customParametersValue = initialCustomParameters
|
||||||
|
if version == "12.0.0" {
|
||||||
|
customParametersValue["network_use_tcponly"] = true as NSNumber
|
||||||
|
customParameters = String(data: try! JSONSerialization.data(withJSONObject: customParametersValue), encoding: .utf8)!
|
||||||
|
}
|
||||||
|
|
||||||
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
|
if let value = customParametersValue["network_use_tcponly"] as? Bool, value {
|
||||||
context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in
|
filteredConnections = filteredConnections.filter { connection in
|
||||||
|
if connection.hasTcp {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
allowP2P = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*#if DEBUG
|
||||||
|
if let initialCustomParameters = try? JSONSerialization.jsonObject(with: (customParameters ?? "{}").data(using: .utf8)!) as? [String: Any] {
|
||||||
|
var customParametersValue: [String: Any]
|
||||||
|
customParametersValue = initialCustomParameters
|
||||||
|
customParametersValue["network_kcp_experiment"] = true as NSNumber
|
||||||
|
customParameters = String(data: try! JSONSerialization.data(withJSONObject: customParametersValue), encoding: .utf8)!
|
||||||
|
}
|
||||||
|
#endif*/
|
||||||
|
|
||||||
|
let context = OngoingCallThreadLocalContextWebrtc(
|
||||||
|
version: version,
|
||||||
|
customParameters: customParameters,
|
||||||
|
queue: OngoingCallThreadLocalContextQueueImpl(queue: queue),
|
||||||
|
proxy: voipProxyServer,
|
||||||
|
networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType),
|
||||||
|
dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving),
|
||||||
|
derivedState: Data(),
|
||||||
|
key: key,
|
||||||
|
isOutgoing: isOutgoing,
|
||||||
|
connections: filteredConnections,
|
||||||
|
maxLayer: maxLayer,
|
||||||
|
allowP2P: allowP2P,
|
||||||
|
allowTCP: enableTCP,
|
||||||
|
enableStunMarking: enableStunMarking,
|
||||||
|
logPath: logPath,
|
||||||
|
statsLogPath: tempStatsLogPath,
|
||||||
|
sendSignalingData: { [weak callSessionManager] data in
|
||||||
queue.async {
|
queue.async {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let mappedState = OngoingCallContextState.State(state)
|
if let signalingConnectionManager = strongSelf.signalingConnectionManager {
|
||||||
let mappedVideoState: OngoingCallContextState.VideoState
|
signalingConnectionManager.with { impl in
|
||||||
switch videoState {
|
impl.send(payloadData: data)
|
||||||
case .inactive:
|
}
|
||||||
mappedVideoState = .inactive
|
|
||||||
case .active:
|
|
||||||
mappedVideoState = .active
|
|
||||||
case .paused:
|
|
||||||
mappedVideoState = .paused
|
|
||||||
@unknown default:
|
|
||||||
mappedVideoState = .notAvailable
|
|
||||||
}
|
}
|
||||||
let mappedRemoteVideoState: OngoingCallContextState.RemoteVideoState
|
|
||||||
switch remoteVideoState {
|
if let callSessionManager = callSessionManager {
|
||||||
case .inactive:
|
callSessionManager.sendSignalingData(internalId: internalId, data: data)
|
||||||
mappedRemoteVideoState = .inactive
|
|
||||||
case .active:
|
|
||||||
mappedRemoteVideoState = .active
|
|
||||||
case .paused:
|
|
||||||
mappedRemoteVideoState = .paused
|
|
||||||
@unknown default:
|
|
||||||
mappedRemoteVideoState = .inactive
|
|
||||||
}
|
}
|
||||||
let mappedRemoteAudioState: OngoingCallContextState.RemoteAudioState
|
|
||||||
switch remoteAudioState {
|
|
||||||
case .active:
|
|
||||||
mappedRemoteAudioState = .active
|
|
||||||
case .muted:
|
|
||||||
mappedRemoteAudioState = .muted
|
|
||||||
@unknown default:
|
|
||||||
mappedRemoteAudioState = .active
|
|
||||||
}
|
|
||||||
let mappedRemoteBatteryLevel: OngoingCallContextState.RemoteBatteryLevel
|
|
||||||
switch remoteBatteryLevel {
|
|
||||||
case .normal:
|
|
||||||
mappedRemoteBatteryLevel = .normal
|
|
||||||
case .low:
|
|
||||||
mappedRemoteBatteryLevel = .low
|
|
||||||
@unknown default:
|
|
||||||
mappedRemoteBatteryLevel = .normal
|
|
||||||
}
|
|
||||||
if case .active = mappedVideoState, !strongSelf.didReportCallAsVideo {
|
|
||||||
strongSelf.didReportCallAsVideo = true
|
|
||||||
callSessionManager?.updateCallType(internalId: internalId, type: .video)
|
|
||||||
}
|
|
||||||
strongSelf.contextState.set(.single(OngoingCallContextState(state: mappedState, videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)))
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
strongSelf.receptionPromise.set(.single(4))
|
videoCapturer: video?.impl,
|
||||||
context.signalBarsChanged = { signalBars in
|
preferredVideoCodec: preferredVideoCodec,
|
||||||
self?.receptionPromise.set(.single(signalBars))
|
audioInputDeviceId: "",
|
||||||
}
|
audioDevice: audioDevice?.impl,
|
||||||
context.audioLevelUpdated = { level in
|
directConnection: directConnection
|
||||||
self?.audioLevelPromise.set(.single(level))
|
)
|
||||||
}
|
|
||||||
|
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
|
||||||
if audioDevice == nil {
|
context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in
|
||||||
strongSelf.audioSessionActiveDisposable.set((audioSessionActive
|
queue.async {
|
||||||
|> deliverOn(queue)).start(next: { isActive in
|
guard let strongSelf = self else {
|
||||||
guard let strongSelf = self else {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
strongSelf.withContext { context in
|
|
||||||
context.nativeSetIsAudioSessionActive(isActive: isActive)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
strongSelf.networkTypeDisposable = (updatedNetworkType
|
|
||||||
|> deliverOn(queue)).start(next: { networkType in
|
|
||||||
self?.withContext { context in
|
|
||||||
context.nativeSetNetworkType(networkType)
|
|
||||||
}
|
}
|
||||||
})
|
let mappedState = OngoingCallContextState.State(state)
|
||||||
} else {
|
let mappedVideoState: OngoingCallContextState.VideoState
|
||||||
var voipProxyServer: VoipProxyServer?
|
switch videoState {
|
||||||
if let proxyServer = proxyServer {
|
case .inactive:
|
||||||
switch proxyServer.connection {
|
mappedVideoState = .inactive
|
||||||
case let .socks5(username, password):
|
case .active:
|
||||||
voipProxyServer = VoipProxyServer(host: proxyServer.host, port: proxyServer.port, username: username, password: password)
|
mappedVideoState = .active
|
||||||
case .mtp:
|
case .paused:
|
||||||
break
|
mappedVideoState = .paused
|
||||||
|
@unknown default:
|
||||||
|
mappedVideoState = .notAvailable
|
||||||
}
|
}
|
||||||
}
|
let mappedRemoteVideoState: OngoingCallContextState.RemoteVideoState
|
||||||
let context = OngoingCallThreadLocalContext(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForType(initialNetworkType), dataSaving: ongoingDataSavingForType(dataSaving), derivedState: Data(), key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescription(connections.primary)!, alternativeConnections: connections.alternatives.compactMap(callConnectionDescription), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
|
switch remoteVideoState {
|
||||||
|
case .inactive:
|
||||||
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
|
mappedRemoteVideoState = .inactive
|
||||||
context.stateChanged = { state in
|
case .active:
|
||||||
self?.contextState.set(.single(OngoingCallContextState(state: OngoingCallContextState.State(state), videoState: .notAvailable, remoteVideoState: .inactive, remoteAudioState: .active, remoteBatteryLevel: .normal)))
|
mappedRemoteVideoState = .active
|
||||||
}
|
case .paused:
|
||||||
context.signalBarsChanged = { signalBars in
|
mappedRemoteVideoState = .paused
|
||||||
self?.receptionPromise.set(.single(signalBars))
|
@unknown default:
|
||||||
}
|
mappedRemoteVideoState = .inactive
|
||||||
|
|
||||||
strongSelf.networkTypeDisposable = (updatedNetworkType
|
|
||||||
|> deliverOn(queue)).start(next: { networkType in
|
|
||||||
self?.withContext { context in
|
|
||||||
context.nativeSetNetworkType(networkType)
|
|
||||||
}
|
}
|
||||||
})
|
let mappedRemoteAudioState: OngoingCallContextState.RemoteAudioState
|
||||||
|
switch remoteAudioState {
|
||||||
|
case .active:
|
||||||
|
mappedRemoteAudioState = .active
|
||||||
|
case .muted:
|
||||||
|
mappedRemoteAudioState = .muted
|
||||||
|
@unknown default:
|
||||||
|
mappedRemoteAudioState = .active
|
||||||
|
}
|
||||||
|
let mappedRemoteBatteryLevel: OngoingCallContextState.RemoteBatteryLevel
|
||||||
|
switch remoteBatteryLevel {
|
||||||
|
case .normal:
|
||||||
|
mappedRemoteBatteryLevel = .normal
|
||||||
|
case .low:
|
||||||
|
mappedRemoteBatteryLevel = .low
|
||||||
|
@unknown default:
|
||||||
|
mappedRemoteBatteryLevel = .normal
|
||||||
|
}
|
||||||
|
if case .active = mappedVideoState, !strongSelf.didReportCallAsVideo {
|
||||||
|
strongSelf.didReportCallAsVideo = true
|
||||||
|
callSessionManager?.updateCallType(internalId: internalId, type: .video)
|
||||||
|
}
|
||||||
|
strongSelf.contextState.set(.single(OngoingCallContextState(state: mappedState, videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
strongSelf.receptionPromise.set(.single(4))
|
||||||
|
context.signalBarsChanged = { signalBars in
|
||||||
|
self?.receptionPromise.set(.single(signalBars))
|
||||||
|
}
|
||||||
|
context.audioLevelUpdated = { level in
|
||||||
|
self?.audioLevelPromise.set(.single(level))
|
||||||
|
}
|
||||||
|
|
||||||
|
if audioDevice == nil {
|
||||||
|
strongSelf.audioSessionActiveDisposable.set((audioSessionActive
|
||||||
|
|> deliverOn(queue)).start(next: { isActive in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.withContext { context in
|
||||||
|
context.nativeSetIsAudioSessionActive(isActive: isActive)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.networkTypeDisposable = (updatedNetworkType
|
||||||
|
|> deliverOn(queue)).start(next: { networkType in
|
||||||
|
self?.withContext { context in
|
||||||
|
context.nativeSetNetworkType(networkType)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
strongSelf.signalingDataDisposable = callSessionManager.beginReceivingCallSignalingData(internalId: internalId, { [weak self] dataList in
|
strongSelf.signalingDataDisposable = callSessionManager.beginReceivingCallSignalingData(internalId: internalId, { [weak self] dataList in
|
||||||
queue.async {
|
queue.async {
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
|
|
||||||
copts_arm = [
|
|
||||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
|
||||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
|
||||||
"-DWEBRTC_POSIX",
|
|
||||||
"-DTGVOIP_HAVE_TGLOG",
|
|
||||||
"-DWEBRTC_NS_FLOAT",
|
|
||||||
"-DWEBRTC_IOS",
|
|
||||||
"-DWEBRTC_HAS_NEON",
|
|
||||||
"-DTGVOIP_NO_DSP",
|
|
||||||
]
|
|
||||||
|
|
||||||
copts_x86 = [
|
|
||||||
"-DTGVOIP_USE_CUSTOM_CRYPTO",
|
|
||||||
"-DWEBRTC_APM_DEBUG_DUMP=0",
|
|
||||||
"-DWEBRTC_POSIX",
|
|
||||||
"-DTGVOIP_HAVE_TGLOG",
|
|
||||||
"-DTGVOIP_NO_DSP",
|
|
||||||
"-DWEBRTC_NS_FLOAT",
|
|
||||||
"-DWEBRTC_IOS",
|
|
||||||
]
|
|
||||||
|
|
||||||
objc_library(
|
|
||||||
name = "TgVoip",
|
|
||||||
enable_modules = True,
|
|
||||||
module_name = "TgVoip",
|
|
||||||
srcs = glob([
|
|
||||||
"Sources/**/*.m",
|
|
||||||
"Sources/**/*.mm",
|
|
||||||
"Sources/**/*.h",
|
|
||||||
"libtgvoip/*.h",
|
|
||||||
"libtgvoip/*.hpp",
|
|
||||||
"libtgvoip/*.m",
|
|
||||||
"libtgvoip/*.mm",
|
|
||||||
"libtgvoip/*.cpp",
|
|
||||||
"libtgvoip/audio/*.h",
|
|
||||||
"libtgvoip/audio/*.cpp",
|
|
||||||
"libtgvoip/video/*.h",
|
|
||||||
"libtgvoip/video/*.cpp",
|
|
||||||
"libtgvoip/os/darwin/*.h",
|
|
||||||
"libtgvoip/os/darwin/*.m",
|
|
||||||
"libtgvoip/os/darwin/*.mm",
|
|
||||||
"libtgvoip/os/darwin/*.cpp",
|
|
||||||
"libtgvoip/os/posix/*.h",
|
|
||||||
"libtgvoip/os/posix/*.cpp",
|
|
||||||
], exclude = ["libtgvoip/os/darwin/*OSX*"]),
|
|
||||||
hdrs = glob([
|
|
||||||
"PublicHeaders/**/*.h",
|
|
||||||
]),
|
|
||||||
copts = [
|
|
||||||
"-I{}/PublicHeaders/TgVoip".format(package_name()),
|
|
||||||
"-I{}/libtgvoip".format(package_name()),
|
|
||||||
"-I{}/third-party/webrtc/webrtc".format(package_name()),
|
|
||||||
"-Isubmodules/Opus/Public/opus",
|
|
||||||
"-DTGVOIP_USE_INSTALLED_OPUS",
|
|
||||||
"-Drtc=rtc1",
|
|
||||||
"-Dwebrtc=webrtc1",
|
|
||||||
] + select({
|
|
||||||
"@build_bazel_rules_apple//apple:ios_arm64": copts_arm,
|
|
||||||
"//build-system:ios_sim_arm64": copts_arm,
|
|
||||||
"@build_bazel_rules_apple//apple:ios_x86_64": copts_x86,
|
|
||||||
}),
|
|
||||||
includes = [
|
|
||||||
"PublicHeaders",
|
|
||||||
],
|
|
||||||
deps = [
|
|
||||||
"//submodules/MtProtoKit:MtProtoKit",
|
|
||||||
"//third-party/opus:opus",
|
|
||||||
],
|
|
||||||
sdk_frameworks = [
|
|
||||||
"Foundation",
|
|
||||||
"UIKit",
|
|
||||||
"AudioToolbox",
|
|
||||||
"VideoToolbox",
|
|
||||||
"CoreTelephony",
|
|
||||||
"CoreMedia",
|
|
||||||
"AVFoundation",
|
|
||||||
],
|
|
||||||
visibility = [
|
|
||||||
"//visibility:public",
|
|
||||||
],
|
|
||||||
)
|
|
@ -1,81 +0,0 @@
|
|||||||
#ifndef OngoingCallContext_h
|
|
||||||
#define OngoingCallContext_h
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@interface OngoingCallConnectionDescription : NSObject
|
|
||||||
|
|
||||||
@property (nonatomic, readonly) int64_t connectionId;
|
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nonnull ip;
|
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nonnull ipv6;
|
|
||||||
@property (nonatomic, readonly) int32_t port;
|
|
||||||
@property (nonatomic, strong, readonly) NSData * _Nonnull peerTag;
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
typedef NS_ENUM(int32_t, OngoingCallState) {
|
|
||||||
OngoingCallStateInitializing,
|
|
||||||
OngoingCallStateConnected,
|
|
||||||
OngoingCallStateFailed,
|
|
||||||
OngoingCallStateReconnecting
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NS_ENUM(int32_t, OngoingCallNetworkType) {
|
|
||||||
OngoingCallNetworkTypeWifi,
|
|
||||||
OngoingCallNetworkTypeCellularGprs,
|
|
||||||
OngoingCallNetworkTypeCellularEdge,
|
|
||||||
OngoingCallNetworkTypeCellular3g,
|
|
||||||
OngoingCallNetworkTypeCellularLte
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef NS_ENUM(int32_t, OngoingCallDataSaving) {
|
|
||||||
OngoingCallDataSavingNever,
|
|
||||||
OngoingCallDataSavingCellular,
|
|
||||||
OngoingCallDataSavingAlways
|
|
||||||
};
|
|
||||||
|
|
||||||
@protocol OngoingCallThreadLocalContextQueue <NSObject>
|
|
||||||
|
|
||||||
- (void)dispatch:(void (^ _Nonnull)())f;
|
|
||||||
- (bool)isCurrent;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface VoipProxyServer : NSObject
|
|
||||||
|
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nonnull host;
|
|
||||||
@property (nonatomic, readonly) int32_t port;
|
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nullable username;
|
|
||||||
@property (nonatomic, strong, readonly) NSString * _Nullable password;
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface OngoingCallThreadLocalContext : NSObject
|
|
||||||
|
|
||||||
+ (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction;
|
|
||||||
+ (void)applyServerConfig:(NSString * _Nullable)data;
|
|
||||||
+ (int32_t)maxLayer;
|
|
||||||
+ (NSString * _Nonnull)version;
|
|
||||||
|
|
||||||
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
|
|
||||||
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath;
|
|
||||||
- (void)stop:(void (^_Nonnull)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
|
|
||||||
|
|
||||||
- (bool)needRate;
|
|
||||||
|
|
||||||
- (NSString * _Nullable)debugInfo;
|
|
||||||
- (NSString * _Nullable)version;
|
|
||||||
- (NSData * _Nonnull)getDerivedState;
|
|
||||||
|
|
||||||
- (void)setIsMuted:(bool)isMuted;
|
|
||||||
- (void)setNetworkType:(OngoingCallNetworkType)networkType;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,419 +0,0 @@
|
|||||||
#import "OngoingCallThreadLocalContext.h"
|
|
||||||
|
|
||||||
#import "TgVoip.h"
|
|
||||||
|
|
||||||
#import <MtProtoKit/MtProtoKit.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#import <libkern/OSAtomic.h>
|
|
||||||
|
|
||||||
static void TGCallAesIgeEncrypt(uint8_t *inBytes, uint8_t *outBytes, size_t length, uint8_t *key, uint8_t *iv) {
|
|
||||||
MTAesEncryptRaw(inBytes, outBytes, length, key, iv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TGCallAesIgeDecrypt(uint8_t *inBytes, uint8_t *outBytes, size_t length, uint8_t *key, uint8_t *iv) {
|
|
||||||
MTAesDecryptRaw(inBytes, outBytes, length, key, iv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TGCallSha1(uint8_t *msg, size_t length, uint8_t *output) {
|
|
||||||
MTRawSha1(msg, length, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TGCallSha256(uint8_t *msg, size_t length, uint8_t *output) {
|
|
||||||
MTRawSha256(msg, length, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TGCallAesCtrEncrypt(uint8_t *inOut, size_t length, uint8_t *key, uint8_t *iv, uint8_t *ecount, uint32_t *num) {
|
|
||||||
uint8_t *outData = (uint8_t *)malloc(length);
|
|
||||||
MTAesCtr *aesCtr = [[MTAesCtr alloc] initWithKey:key keyLength:32 iv:iv ecount:ecount num:*num];
|
|
||||||
[aesCtr encryptIn:inOut out:outData len:length];
|
|
||||||
memcpy(inOut, outData, length);
|
|
||||||
free(outData);
|
|
||||||
|
|
||||||
[aesCtr getIv:iv];
|
|
||||||
|
|
||||||
memcpy(ecount, [aesCtr ecount], 16);
|
|
||||||
*num = [aesCtr num];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TGCallRandomBytes(uint8_t *buffer, size_t length) {
|
|
||||||
arc4random_buf(buffer, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation OngoingCallConnectionDescription
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag {
|
|
||||||
self = [super init];
|
|
||||||
if (self != nil) {
|
|
||||||
_connectionId = connectionId;
|
|
||||||
_ip = ip;
|
|
||||||
_ipv6 = ipv6;
|
|
||||||
_port = port;
|
|
||||||
_peerTag = peerTag;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
static MTAtomic *callContexts() {
|
|
||||||
static MTAtomic *instance = nil;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^{
|
|
||||||
instance = [[MTAtomic alloc] initWithValue:[[NSMutableDictionary alloc] init]];
|
|
||||||
});
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface OngoingCallThreadLocalContextReference : NSObject
|
|
||||||
|
|
||||||
@property (nonatomic, weak) OngoingCallThreadLocalContext *context;
|
|
||||||
@property (nonatomic, strong, readonly) id<OngoingCallThreadLocalContextQueue> queue;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation OngoingCallThreadLocalContextReference
|
|
||||||
|
|
||||||
- (instancetype)initWithContext:(OngoingCallThreadLocalContext *)context queue:(id<OngoingCallThreadLocalContextQueue>)queue {
|
|
||||||
self = [super init];
|
|
||||||
if (self != nil) {
|
|
||||||
self.context = context;
|
|
||||||
_queue = queue;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
static int32_t nextId = 1;
|
|
||||||
|
|
||||||
static int32_t addContext(OngoingCallThreadLocalContext *context, id<OngoingCallThreadLocalContextQueue> queue) {
|
|
||||||
int32_t contextId = OSAtomicIncrement32(&nextId);
|
|
||||||
[callContexts() with:^id(NSMutableDictionary *dict) {
|
|
||||||
dict[@(contextId)] = [[OngoingCallThreadLocalContextReference alloc] initWithContext:context queue:queue];
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
return contextId;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void removeContext(int32_t contextId) {
|
|
||||||
[callContexts() with:^id(NSMutableDictionary *dict) {
|
|
||||||
[dict removeObjectForKey:@(contextId)];
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void withContext(int32_t contextId, void (^f)(OngoingCallThreadLocalContext *)) {
|
|
||||||
__block OngoingCallThreadLocalContextReference *reference = nil;
|
|
||||||
[callContexts() with:^id(NSMutableDictionary *dict) {
|
|
||||||
reference = dict[@(contextId)];
|
|
||||||
return nil;
|
|
||||||
}];
|
|
||||||
if (reference != nil) {
|
|
||||||
[reference.queue dispatch:^{
|
|
||||||
__strong OngoingCallThreadLocalContext *context = reference.context;
|
|
||||||
if (context != nil) {
|
|
||||||
f(context);
|
|
||||||
}
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface OngoingCallThreadLocalContext () {
|
|
||||||
id<OngoingCallThreadLocalContextQueue> _queue;
|
|
||||||
int32_t _contextId;
|
|
||||||
|
|
||||||
OngoingCallNetworkType _networkType;
|
|
||||||
NSTimeInterval _callReceiveTimeout;
|
|
||||||
NSTimeInterval _callRingTimeout;
|
|
||||||
NSTimeInterval _callConnectTimeout;
|
|
||||||
NSTimeInterval _callPacketTimeout;
|
|
||||||
|
|
||||||
std::unique_ptr<TgVoip> _tgVoip;
|
|
||||||
|
|
||||||
OngoingCallState _state;
|
|
||||||
int32_t _signalBars;
|
|
||||||
NSData *_lastDerivedState;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)controllerStateChanged:(TgVoipState)state;
|
|
||||||
- (void)signalBarsChanged:(int32_t)signalBars;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation VoipProxyServer
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
|
|
||||||
self = [super init];
|
|
||||||
if (self != nil) {
|
|
||||||
_host = host;
|
|
||||||
_port = port;
|
|
||||||
_username = username;
|
|
||||||
_password = password;
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
static TgVoipNetworkType callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
|
||||||
switch (type) {
|
|
||||||
case OngoingCallNetworkTypeWifi:
|
|
||||||
return TgVoipNetworkType::WiFi;
|
|
||||||
case OngoingCallNetworkTypeCellularGprs:
|
|
||||||
return TgVoipNetworkType::Gprs;
|
|
||||||
case OngoingCallNetworkTypeCellular3g:
|
|
||||||
return TgVoipNetworkType::ThirdGeneration;
|
|
||||||
case OngoingCallNetworkTypeCellularLte:
|
|
||||||
return TgVoipNetworkType::Lte;
|
|
||||||
default:
|
|
||||||
return TgVoipNetworkType::ThirdGeneration;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static TgVoipDataSaving callControllerDataSavingForType(OngoingCallDataSaving type) {
|
|
||||||
switch (type) {
|
|
||||||
case OngoingCallDataSavingNever:
|
|
||||||
return TgVoipDataSaving::Never;
|
|
||||||
case OngoingCallDataSavingCellular:
|
|
||||||
return TgVoipDataSaving::Mobile;
|
|
||||||
case OngoingCallDataSavingAlways:
|
|
||||||
return TgVoipDataSaving::Always;
|
|
||||||
default:
|
|
||||||
return TgVoipDataSaving::Never;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@implementation OngoingCallThreadLocalContext
|
|
||||||
|
|
||||||
static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
|
||||||
|
|
||||||
+ (void)setupLoggingFunction:(void (*)(NSString *))loggingFunction {
|
|
||||||
InternalVoipLoggingFunction = loggingFunction;
|
|
||||||
TgVoip::setLoggingFunction([](std::string const &string) {
|
|
||||||
if (InternalVoipLoggingFunction) {
|
|
||||||
InternalVoipLoggingFunction([[NSString alloc] initWithUTF8String:string.c_str()]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)applyServerConfig:(NSString *)string {
|
|
||||||
if (string.length != 0) {
|
|
||||||
TgVoip::setGlobalServerConfig(std::string(string.UTF8String));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (int32_t)maxLayer {
|
|
||||||
return 92;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (NSString *)version {
|
|
||||||
return [NSString stringWithUTF8String:TgVoip::getVersion().c_str()];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescription * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescription *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
|
|
||||||
self = [super init];
|
|
||||||
if (self != nil) {
|
|
||||||
_queue = queue;
|
|
||||||
assert([queue isCurrent]);
|
|
||||||
_contextId = addContext(self, queue);
|
|
||||||
|
|
||||||
_callReceiveTimeout = 20.0;
|
|
||||||
_callRingTimeout = 90.0;
|
|
||||||
_callConnectTimeout = 30.0;
|
|
||||||
_callPacketTimeout = 10.0;
|
|
||||||
_networkType = networkType;
|
|
||||||
|
|
||||||
std::vector<uint8_t> derivedStateValue;
|
|
||||||
derivedStateValue.resize(derivedState.length);
|
|
||||||
[derivedState getBytes:derivedStateValue.data() length:derivedState.length];
|
|
||||||
|
|
||||||
std::unique_ptr<TgVoipProxy> proxyValue = nullptr;
|
|
||||||
if (proxy != nil) {
|
|
||||||
TgVoipProxy *proxyObject = new TgVoipProxy();
|
|
||||||
proxyObject->host = proxy.host.UTF8String;
|
|
||||||
proxyObject->port = (uint16_t)proxy.port;
|
|
||||||
proxyObject->login = proxy.username.UTF8String ?: "";
|
|
||||||
proxyObject->password = proxy.password.UTF8String ?: "";
|
|
||||||
proxyValue = std::unique_ptr<TgVoipProxy>(proxyObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
TgVoipCrypto crypto;
|
|
||||||
crypto.sha1 = &TGCallSha1;
|
|
||||||
crypto.sha256 = &TGCallSha256;
|
|
||||||
crypto.rand_bytes = &TGCallRandomBytes;
|
|
||||||
crypto.aes_ige_encrypt = &TGCallAesIgeEncrypt;
|
|
||||||
crypto.aes_ige_decrypt = &TGCallAesIgeDecrypt;
|
|
||||||
crypto.aes_ctr_encrypt = &TGCallAesCtrEncrypt;
|
|
||||||
|
|
||||||
std::vector<TgVoipEndpoint> endpoints;
|
|
||||||
NSArray<OngoingCallConnectionDescription *> *connections = [@[primaryConnection] arrayByAddingObjectsFromArray:alternativeConnections];
|
|
||||||
for (OngoingCallConnectionDescription *connection in connections) {
|
|
||||||
unsigned char peerTag[16];
|
|
||||||
[connection.peerTag getBytes:peerTag length:16];
|
|
||||||
|
|
||||||
TgVoipEndpoint endpoint;
|
|
||||||
endpoint.endpointId = connection.connectionId;
|
|
||||||
endpoint.host = {
|
|
||||||
.ipv4 = std::string(connection.ip.UTF8String),
|
|
||||||
.ipv6 = std::string(connection.ipv6.UTF8String)
|
|
||||||
};
|
|
||||||
endpoint.port = (uint16_t)connection.port;
|
|
||||||
endpoint.type = TgVoipEndpointType::UdpRelay;
|
|
||||||
memcpy(endpoint.peerTag, peerTag, 16);
|
|
||||||
endpoints.push_back(endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
TgVoipConfig config;
|
|
||||||
config.initializationTimeout = _callConnectTimeout;
|
|
||||||
config.receiveTimeout = _callPacketTimeout;
|
|
||||||
config.dataSaving = callControllerDataSavingForType(dataSaving);
|
|
||||||
config.enableP2P = static_cast<bool>(allowP2P);
|
|
||||||
config.enableAEC = false;
|
|
||||||
config.enableNS = true;
|
|
||||||
config.enableAGC = true;
|
|
||||||
config.enableVolumeControl = false;
|
|
||||||
config.enableCallUpgrade = false;
|
|
||||||
config.logPath = logPath.length == 0 ? "" : std::string(logPath.UTF8String);
|
|
||||||
config.maxApiLayer = [OngoingCallThreadLocalContext maxLayer];
|
|
||||||
|
|
||||||
std::vector<uint8_t> encryptionKeyValue;
|
|
||||||
encryptionKeyValue.resize(key.length);
|
|
||||||
memcpy(encryptionKeyValue.data(), key.bytes, key.length);
|
|
||||||
|
|
||||||
TgVoipEncryptionKey encryptionKey;
|
|
||||||
encryptionKey.value = encryptionKeyValue;
|
|
||||||
encryptionKey.isOutgoing = isOutgoing;
|
|
||||||
|
|
||||||
_tgVoip = TgVoip::makeInstance(
|
|
||||||
config,
|
|
||||||
{ derivedStateValue },
|
|
||||||
endpoints,
|
|
||||||
proxyValue.get(),
|
|
||||||
callControllerNetworkTypeForType(networkType),
|
|
||||||
encryptionKey,
|
|
||||||
crypto
|
|
||||||
);
|
|
||||||
|
|
||||||
_state = OngoingCallStateInitializing;
|
|
||||||
_signalBars = -1;
|
|
||||||
|
|
||||||
__weak OngoingCallThreadLocalContext *weakSelf = self;
|
|
||||||
_tgVoip->setOnStateUpdated([weakSelf](TgVoipState state) {
|
|
||||||
__strong OngoingCallThreadLocalContext *strongSelf = weakSelf;
|
|
||||||
if (strongSelf) {
|
|
||||||
[strongSelf controllerStateChanged:state];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_tgVoip->setOnSignalBarsUpdated([weakSelf](int signalBars) {
|
|
||||||
__strong OngoingCallThreadLocalContext *strongSelf = weakSelf;
|
|
||||||
if (strongSelf) {
|
|
||||||
[strongSelf signalBarsChanged:signalBars];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)dealloc {
|
|
||||||
assert([_queue isCurrent]);
|
|
||||||
removeContext(_contextId);
|
|
||||||
if (_tgVoip != NULL) {
|
|
||||||
[self stop:nil];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
|
||||||
if (_tgVoip) {
|
|
||||||
TgVoipFinalState finalState = _tgVoip->stop();
|
|
||||||
|
|
||||||
NSString *debugLog = [NSString stringWithUTF8String:finalState.debugLog.c_str()];
|
|
||||||
_lastDerivedState = [[NSData alloc] initWithBytes:finalState.persistentState.value.data() length:finalState.persistentState.value.size()];
|
|
||||||
|
|
||||||
_tgVoip.reset();
|
|
||||||
|
|
||||||
if (completion) {
|
|
||||||
completion(debugLog, finalState.trafficStats.bytesSentWifi, finalState.trafficStats.bytesReceivedWifi, finalState.trafficStats.bytesSentMobile, finalState.trafficStats.bytesReceivedMobile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)debugInfo {
|
|
||||||
if (_tgVoip != nil) {
|
|
||||||
auto rawDebugString = _tgVoip->getDebugInfo();
|
|
||||||
return [NSString stringWithUTF8String:rawDebugString.c_str()];
|
|
||||||
} else {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSString *)version {
|
|
||||||
if (_tgVoip != nil) {
|
|
||||||
return [NSString stringWithUTF8String:_tgVoip->getVersion().c_str()];
|
|
||||||
} else {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSData * _Nonnull)getDerivedState {
|
|
||||||
if (_tgVoip) {
|
|
||||||
auto persistentState = _tgVoip->getPersistentState();
|
|
||||||
return [[NSData alloc] initWithBytes:persistentState.value.data() length:persistentState.value.size()];
|
|
||||||
} else if (_lastDerivedState != nil) {
|
|
||||||
return _lastDerivedState;
|
|
||||||
} else {
|
|
||||||
return [NSData data];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)controllerStateChanged:(TgVoipState)state {
|
|
||||||
OngoingCallState callState = OngoingCallStateInitializing;
|
|
||||||
switch (state) {
|
|
||||||
case TgVoipState::Established:
|
|
||||||
callState = OngoingCallStateConnected;
|
|
||||||
break;
|
|
||||||
case TgVoipState::Failed:
|
|
||||||
callState = OngoingCallStateFailed;
|
|
||||||
break;
|
|
||||||
case TgVoipState::Reconnecting:
|
|
||||||
callState = OngoingCallStateReconnecting;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callState != _state) {
|
|
||||||
_state = callState;
|
|
||||||
|
|
||||||
if (_stateChanged) {
|
|
||||||
_stateChanged(callState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)signalBarsChanged:(int32_t)signalBars {
|
|
||||||
if (signalBars != _signalBars) {
|
|
||||||
_signalBars = signalBars;
|
|
||||||
|
|
||||||
if (_signalBarsChanged) {
|
|
||||||
_signalBarsChanged(signalBars);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setIsMuted:(bool)isMuted {
|
|
||||||
if (_tgVoip) {
|
|
||||||
_tgVoip->setMuteMicrophone(isMuted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)setNetworkType:(OngoingCallNetworkType)networkType {
|
|
||||||
if (_networkType != networkType) {
|
|
||||||
_networkType = networkType;
|
|
||||||
if (_tgVoip) {
|
|
||||||
_tgVoip->setNetworkType(callControllerNetworkTypeForType(networkType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 37d98e984fd6fa389262307db826d52ab86c8241
|
|
@ -11,6 +11,36 @@
|
|||||||
#define UIView NSView
|
#define UIView NSView
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@interface OngoingCallConnectionDescription : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, readonly) int64_t connectionId;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull ip;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull ipv6;
|
||||||
|
@property (nonatomic, readonly) int32_t port;
|
||||||
|
@property (nonatomic, strong, readonly) NSData * _Nonnull peerTag;
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol OngoingCallThreadLocalContextQueue <NSObject>
|
||||||
|
|
||||||
|
- (void)dispatch:(void (^ _Nonnull)())f;
|
||||||
|
- (bool)isCurrent;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface VoipProxyServer : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nonnull host;
|
||||||
|
@property (nonatomic, readonly) int32_t port;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nullable username;
|
||||||
|
@property (nonatomic, strong, readonly) NSString * _Nullable password;
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
@interface CallAudioTone : NSObject
|
@interface CallAudioTone : NSObject
|
||||||
|
|
||||||
@property (nonatomic, strong, readonly) NSData * _Nonnull samples;
|
@property (nonatomic, strong, readonly) NSData * _Nonnull samples;
|
||||||
|
@ -42,6 +42,38 @@
|
|||||||
#import "platform/darwin/TGRTCCVPixelBuffer.h"
|
#import "platform/darwin/TGRTCCVPixelBuffer.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
|
|
||||||
|
@implementation OngoingCallConnectionDescription
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithConnectionId:(int64_t)connectionId ip:(NSString * _Nonnull)ip ipv6:(NSString * _Nonnull)ipv6 port:(int32_t)port peerTag:(NSData * _Nonnull)peerTag {
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
_connectionId = connectionId;
|
||||||
|
_ip = ip;
|
||||||
|
_ipv6 = ipv6;
|
||||||
|
_port = port;
|
||||||
|
_peerTag = peerTag;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation VoipProxyServer
|
||||||
|
|
||||||
|
- (instancetype _Nonnull)initWithHost:(NSString * _Nonnull)host port:(int32_t)port username:(NSString * _Nullable)username password:(NSString * _Nullable)password {
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
_host = host;
|
||||||
|
_port = port;
|
||||||
|
_username = username;
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation CallAudioTone
|
@implementation CallAudioTone
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithSamples:(NSData * _Nonnull)samples sampleRate:(NSInteger)sampleRate loopCount:(NSInteger)loopCount {
|
- (instancetype _Nonnull)initWithSamples:(NSData * _Nonnull)samples sampleRate:(NSInteger)sampleRate loopCount:(NSInteger)loopCount {
|
||||||
@ -1488,9 +1520,6 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (void)applyServerConfig:(NSString *)string {
|
+ (void)applyServerConfig:(NSString *)string {
|
||||||
if (string.length != 0) {
|
|
||||||
//TgVoip::setGlobalServerConfig(std::string(string.UTF8String));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)setupAudioSession {
|
+ (void)setupAudioSession {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit d50eeeb40ce6a2d36d505bcaf0b5f4e5ed473f22
|
Subproject commit 1ea67f88b8d9fd04fc151d164669f6c229d651d3
|
2
third-party/webrtc/webrtc
vendored
2
third-party/webrtc/webrtc
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 77d3d1fe2ff2f364e8edee58179a7b7b95239b01
|
Subproject commit e8d2ef8c74f07c4f952db43bdfc08f39228f79c3
|
Loading…
x
Reference in New Issue
Block a user