Use internal signalling

This commit is contained in:
Ali 2020-05-11 18:25:17 +04:00
parent 346b8160c4
commit b8bee2bd70
12 changed files with 293 additions and 325 deletions

View File

@ -3,7 +3,7 @@
@implementation Serialization
- (NSUInteger)currentLayer {
return 113;
return 114;
}
- (id _Nullable)parseMessage:(NSData * _Nullable)data {

View File

@ -250,6 +250,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[654302845] = { return Api.Update.parse_updateDialogFilter($0) }
dict[-1512627963] = { return Api.Update.parse_updateDialogFilterOrder($0) }
dict[889491791] = { return Api.Update.parse_updateDialogFilters($0) }
dict[643940105] = { return Api.Update.parse_updatePhoneCallSignalingData($0) }
dict[136574537] = { return Api.messages.VotesList.parse_votesList($0) }
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
@ -841,7 +842,7 @@ public struct Api {
return parser(reader)
}
else {
telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found")
telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found")
return nil
}
}

View File

@ -5894,6 +5894,7 @@ public extension Api {
case updateDialogFilter(flags: Int32, id: Int32, filter: Api.DialogFilter?)
case updateDialogFilterOrder(order: [Int32])
case updateDialogFilters
case updatePhoneCallSignalingData(phoneCallId: Int64, data: Buffer)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -6566,6 +6567,13 @@ public extension Api {
buffer.appendInt32(889491791)
}
break
case .updatePhoneCallSignalingData(let phoneCallId, let data):
if boxed {
buffer.appendInt32(643940105)
}
serializeInt64(phoneCallId, buffer: buffer, boxed: false)
serializeBytes(data, buffer: buffer, boxed: false)
break
}
}
@ -6732,6 +6740,8 @@ public extension Api {
return ("updateDialogFilterOrder", [("order", order)])
case .updateDialogFilters:
return ("updateDialogFilters", [])
case .updatePhoneCallSignalingData(let phoneCallId, let data):
return ("updatePhoneCallSignalingData", [("phoneCallId", phoneCallId), ("data", data)])
}
}
@ -8063,6 +8073,20 @@ public extension Api {
public static func parse_updateDialogFilters(_ reader: BufferReader) -> Update? {
return Api.Update.updateDialogFilters
}
public static func parse_updatePhoneCallSignalingData(_ reader: BufferReader) -> Update? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Buffer?
_2 = parseBytes(reader)
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.Update.updatePhoneCallSignalingData(phoneCallId: _1!, data: _2!)
}
else {
return nil
}
}
}
public enum PopularContact: TypeConstructorDescription {

View File

@ -6477,6 +6477,21 @@ public extension Api {
return result
})
}
public static func sendSignalingData(peer: Api.InputPhoneCall, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()
buffer.appendInt32(-8744061)
peer.serialize(buffer, true)
serializeBytes(data, buffer: buffer, boxed: false)
return (FunctionDescription(name: "phone.sendSignalingData", parameters: [("peer", peer), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
let reader = BufferReader(buffer)
var result: Api.Bool?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
}
return result
})
}
}
}
}

View File

@ -98,6 +98,7 @@ enum AccountStateMutationOperation {
case UpdateRecentGifs
case UpdateChatInputState(PeerId, SynchronizeableChatInputState?)
case UpdateCall(Api.PhoneCall)
case AddCallSignalingData(Int64, Data)
case UpdateLangPack(String, Api.LangPackDifference?)
case UpdateMinAvailableMessage(MessageId)
case UpdatePeerChatInclusion(peerId: PeerId, groupId: PeerGroupId, changedGroup: Bool)
@ -425,6 +426,10 @@ struct AccountMutableState {
self.addOperation(.UpdateCall(call))
}
mutating func addCallSignalingData(callId: Int64, data: Data) {
self.addOperation(.AddCallSignalingData(callId, data))
}
mutating func addSyncChatListFilters() {
self.addOperation(.SyncChatListFilters)
}
@ -439,7 +444,7 @@ struct AccountMutableState {
mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter:
break
case let .AddMessages(messages, location):
for message in messages {
@ -555,6 +560,7 @@ struct AccountReplayedFinalState {
let updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]]
let updatedWebpages: [MediaId: TelegramMediaWebpage]
let updatedCalls: [Api.PhoneCall]
let addedCallSignalingData: [(Int64, Data)]
let updatedPeersNearby: [PeerNearby]?
let isContactUpdates: [(PeerId, Bool)]
let delayNotificatonsUntil: Int32?
@ -566,6 +572,7 @@ struct AccountFinalStateEvents {
let updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]]
let updatedWebpages: [MediaId: TelegramMediaWebpage]
let updatedCalls: [Api.PhoneCall]
let addedCallSignalingData: [(Int64, Data)]
let updatedPeersNearby: [PeerNearby]?
let isContactUpdates: [(PeerId, Bool)]
let displayAlerts: [(text: String, isDropAuth: Bool)]
@ -576,15 +583,16 @@ struct AccountFinalStateEvents {
let authorizationListUpdated: Bool
var isEmpty: Bool {
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated
return self.addedIncomingMessageIds.isEmpty && self.wasScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated
}
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false) {
init(addedIncomingMessageIds: [MessageId] = [], wasScheduledMessageIds: [MessageId] = [], updatedTypingActivities: [PeerId: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false) {
self.addedIncomingMessageIds = addedIncomingMessageIds
self.wasScheduledMessageIds = wasScheduledMessageIds
self.updatedTypingActivities = updatedTypingActivities
self.updatedWebpages = updatedWebpages
self.updatedCalls = updatedCalls
self.addedCallSignalingData = addedCallSignalingData
self.updatedPeersNearby = updatedPeersNearby
self.isContactUpdates = isContactUpdates
self.displayAlerts = displayAlerts
@ -601,6 +609,7 @@ struct AccountFinalStateEvents {
self.updatedTypingActivities = state.updatedTypingActivities
self.updatedWebpages = state.updatedWebpages
self.updatedCalls = state.updatedCalls
self.addedCallSignalingData = state.addedCallSignalingData
self.updatedPeersNearby = state.updatedPeersNearby
self.isContactUpdates = state.isContactUpdates
self.displayAlerts = state.state.state.displayAlerts
@ -634,6 +643,6 @@ struct AccountFinalStateEvents {
let externallyUpdatedPeerId = self.externallyUpdatedPeerId.union(other.externallyUpdatedPeerId)
let authorizationListUpdated = self.authorizationListUpdated || other.authorizationListUpdated
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated)
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated)
}
}

View File

@ -1282,6 +1282,8 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo
updatedState.addUpdateChatInputState(peerId: peer.peerId, state: inputState)
case let .updatePhoneCall(phoneCall):
updatedState.addUpdateCall(phoneCall)
case let .updatePhoneCallSignalingData(phoneCallId, data):
updatedState.addCallSignalingData(callId: phoneCallId, data: data.makeData())
case let .updateLangPackTooLong(langCode):
updatedState.updateLangPack(langCode: langCode, difference: nil)
case let .updateLangPack(difference):
@ -2073,7 +2075,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddScheduledMessages: OptimizeAddMessagesState?
for operation in operations {
switch operation {
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll/*, .UpdateMessageReactions*/, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
}
@ -2157,6 +2159,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
var updatedSecretChatTypingActivities = Set<PeerId>()
var updatedWebpages: [MediaId: TelegramMediaWebpage] = [:]
var updatedCalls: [Api.PhoneCall] = []
var addedCallSignalingData: [(Int64, Data)] = []
var updatedPeersNearby: [PeerNearby]?
var isContactUpdates: [(PeerId, Bool)] = []
var stickerPackOperations: [AccountStateUpdateStickerPacksOperation] = []
@ -2760,6 +2763,8 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
})
case let .UpdateCall(call):
updatedCalls.append(call)
case let .AddCallSignalingData(callId, data):
addedCallSignalingData.append((callId, data))
case let .UpdateLangPack(langCode, difference):
if let difference = difference {
if langPackDifferences[langCode] == nil {
@ -3141,5 +3146,5 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
requestChatListFiltersSync(transaction: transaction)
}
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil)
return AccountReplayedFinalState(state: finalState, addedIncomingMessageIds: addedIncomingMessageIds, wasScheduledMessageIds: wasScheduledMessageIds, addedSecretMessageIds: addedSecretMessageIds, updatedTypingActivities: updatedTypingActivities, updatedWebpages: updatedWebpages, updatedCalls: updatedCalls, addedCallSignalingData: addedCallSignalingData, updatedPeersNearby: updatedPeersNearby, isContactUpdates: isContactUpdates, delayNotificatonsUntil: delayNotificatonsUntil)
}

View File

@ -653,6 +653,11 @@ public final class AccountStateManager {
strongSelf.callSessionManager.updateSession(call, completion: { _ in })
}
}
if !events.addedCallSignalingData.isEmpty {
for (id, data) in events.addedCallSignalingData {
strongSelf.callSessionManager.addCallSignalingData(id: id, data: data)
}
}
if !events.isContactUpdates.isEmpty {
strongSelf.addIsContactUpdates(events.isContactUpdates)
}

View File

@ -213,12 +213,15 @@ private final class CallSessionContext {
let isOutgoing: Bool
var state: CallSessionInternalState
let subscribers = Bag<(CallSession) -> Void>()
let signalingSubscribers = Bag<(Data) -> Void>()
let signalingDisposables = DisposableSet()
let acknowledgeIncomingCallDisposable = MetaDisposable()
var isEmpty: Bool {
if case .terminated = self.state {
return self.subscribers.isEmpty
return self.subscribers.isEmpty && self.signalingSubscribers.isEmpty
} else {
return false
}
@ -321,6 +324,31 @@ private final class CallSessionManagerContext {
}
}
func callSignalingData(internalId: CallSessionInternalId) -> Signal<Data, NoError> {
let queue = self.queue
return Signal { [weak self] subscriber in
let disposable = MetaDisposable()
queue.async {
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
let index = context.signalingSubscribers.add { next in
subscriber.putNext(next)
}
disposable.set(ActionDisposable {
queue.async {
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
context.signalingSubscribers.remove(index)
if context.isEmpty {
strongSelf.contexts.removeValue(forKey: internalId)
}
}
}
})
}
}
return disposable
}
}
private func ringingStatesValue() -> [CallSessionRingingState] {
var ringingContexts: [CallSessionRingingState] = []
for (id, context) in self.contexts {
@ -523,6 +551,17 @@ private final class CallSessionManagerContext {
}
}
func sendSignalingData(internalId: CallSessionInternalId, data: Data) {
if let context = self.contexts[internalId] {
switch context.state {
case let .active(id, accessHash, _, _, _, _, _, _, _, _):
context.signalingDisposables.add(self.network.request(Api.functions.phone.sendSignalingData(peer: .inputPhoneCall(id: id, accessHash: accessHash), data: Buffer(data: data))).start())
default:
break
}
}
}
func updateSession(_ call: Api.PhoneCall, completion: @escaping ((CallSessionRingingState, CallSession)?) -> Void) {
var resultRingingState: (CallSessionRingingState, CallSession)?
@ -723,6 +762,15 @@ private final class CallSessionManagerContext {
completion(resultRingingState)
}
func addCallSignalingData(id: Int64, data: Data) {
guard let internalId = self.contextIdByStableId[id], let context = self.contexts[internalId] else {
return
}
for f in context.signalingSubscribers.copyItems() {
f(data)
}
}
private func makeSessionEncryptionKey(config: SecretChatEncryptionConfig, gAHash: Data, b: Data, gA: Data) -> (key: Data, keyId: Int64, keyVisualHash: Data)? {
var key = MTExp(self.network.encryptionProvider, gA, b, config.p.makeData())!
@ -818,6 +866,12 @@ public final class CallSessionManager {
}
}
func addCallSignalingData(id: Int64, data: Data) {
self.withContext { context in
context.addCallSignalingData(id: id, data: data)
}
}
public func drop(internalId: CallSessionInternalId, reason: DropCallReason, debugLog: Signal<String?, NoError>) {
self.withContext { context in
context.drop(internalId: internalId, reason: reason, debugLog: debugLog)
@ -857,6 +911,12 @@ public final class CallSessionManager {
}
}
public func sendSignalingData(internalId: CallSessionInternalId, data: Data) {
self.withContext { context in
context.sendSignalingData(internalId: internalId, data: data)
}
}
public func ringingStates() -> Signal<[CallSessionRingingState], NoError> {
return Signal { [weak self] subscriber in
let disposable = MetaDisposable()
@ -880,6 +940,18 @@ public final class CallSessionManager {
return disposable
}
}
public func callSignalingData(internalId: CallSessionInternalId) -> Signal<Data, NoError> {
return Signal { [weak self] subscriber in
let disposable = MetaDisposable()
self?.withContext { context in
disposable.set(context.callSignalingData(internalId: internalId).start(next: { next in
subscriber.putNext(next)
}))
}
return disposable
}
}
}
private enum AcceptedCall {

View File

@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt {
return 113
return 114
}
public func parseMessage(_ data: Data!) -> Any! {

View File

@ -383,6 +383,8 @@ public final class OngoingCallContext {
return self.contextState.get()
}
private var signalingDataDisposable: Disposable?
private let receptionPromise = Promise<Int32?>(nil)
public var reception: Signal<Int32?, NoError> {
return self.receptionPromise.get()
@ -428,7 +430,9 @@ public final class OngoingCallContext {
break
}
}
let context = OngoingCallThreadLocalContextWebrtcCustom(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtcCustom(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtcCustom(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtcCustom(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtcCustom), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath)
let context = OngoingCallThreadLocalContextWebrtcCustom(queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtcCustom(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtcCustom(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, primaryConnection: callConnectionDescriptionWebrtcCustom(connections.primary), alternativeConnections: connections.alternatives.map(callConnectionDescriptionWebrtcCustom), maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in
callSessionManager?.sendSignalingData(internalId: internalId, data: data)
})
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { state in
@ -499,6 +503,15 @@ public final class OngoingCallContext {
}
}
}))
self.signalingDataDisposable = (callSessionManager.callSignalingData(internalId: internalId)
|> deliverOn(self.queue)).start(next: { [weak self] data in
self?.withContext { context in
if let context = context as? OngoingCallThreadLocalContextWebrtcCustom {
context.receiveSignaling(data)
}
}
})
}
deinit {

View File

@ -66,7 +66,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtcCustom) {
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallStateWebrtcCustom);
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom> _Nonnull)queue proxy:(VoipProxyServerWebrtcCustom * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtcCustom)networkType dataSaving:(OngoingCallDataSavingWebrtcCustom)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtcCustom * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtcCustom *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath;
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom> _Nonnull)queue proxy:(VoipProxyServerWebrtcCustom * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtcCustom)networkType dataSaving:(OngoingCallDataSavingWebrtcCustom)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtcCustom * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtcCustom *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData;
- (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
- (bool)needRate;
@ -75,6 +75,9 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtcCustom) {
- (NSString * _Nullable)version;
- (NSData * _Nonnull)getDerivedState;
- (void)receiveSignalingData:(NSData * _Nonnull)data;
- (void)setIsMuted:(bool)isMuted;
- (void)setNetworkType:(OngoingCallNetworkTypeWebrtcCustom)networkType;
- (void)getRemoteCameraView:(void (^_Nonnull)(UIView * _Nullable))completion;

View File

@ -38,233 +38,6 @@ static void voipLog(NSString* format, ...) {
}
}
@class NativeWebSocketDelegate;
API_AVAILABLE(ios(13.0))
@interface NativeWebSocket : NSObject {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> _queue;
NativeWebSocketDelegate *_socketDelegate;
void (^_receivedData)(NSData *);
NSURLSession *_session;
NSURLSessionWebSocketTask *_socket;
}
@end
API_AVAILABLE(ios(13.0))
@interface NativeWebSocketDelegate: NSObject <NSURLSessionDelegate, NSURLSessionWebSocketDelegate> {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> _queue;
__weak NativeWebSocket *_target;
}
@end
@implementation NativeWebSocketDelegate
- (instancetype)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom>)queue target:(NativeWebSocket *)target {
self = [super init];
if (self != nil) {
_queue = queue;
_target = target;
}
return self;
}
- (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask didOpenWithProtocol:(NSString *)protocol {
}
- (void)URLSession:(NSURLSession *)session webSocketTask:(NSURLSessionWebSocketTask *)webSocketTask didCloseWithCode:(NSURLSessionWebSocketCloseCode)closeCode reason:(NSData *)reason {
}
@end
@implementation NativeWebSocket
- (instancetype)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom>)queue receivedData:(void (^)(NSData *))receivedData {
self = [super init];
if (self != nil) {
_queue = queue;
_receivedData = [receivedData copy];
_socketDelegate = [[NativeWebSocketDelegate alloc] initWithQueue:queue target:self];
_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:_socketDelegate delegateQueue:nil];
}
return self;
}
- (void)connect {
_socket = [_session webSocketTaskWithURL:[[NSURL alloc] initWithString:@"ws://192.168.8.118:8080"]];
[_socket resume];
[self readMessage];
}
- (void)readMessage {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> queue = _queue;
__weak NativeWebSocket *weakSelf = self;
[_socket receiveMessageWithCompletionHandler:^(NSURLSessionWebSocketMessage * _Nullable message, NSError * _Nullable error) {
[queue dispatch:^{
__strong NativeWebSocket *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (error != nil) {
voipLog(@"WebSocket error: %@", error);
} else if (message.data != nil) {
if (strongSelf->_receivedData) {
strongSelf->_receivedData(message.data);
}
[strongSelf readMessage];
} else {
[strongSelf readMessage];
}
}];
}];
}
- (void)sendData:(NSData *)data {
[_socket sendMessage:[[NSURLSessionWebSocketMessage alloc] initWithData:data] completionHandler:^(__unused NSError * _Nullable error) {
}];
}
- (void)disconned {
[_socket cancel];
}
@end
@protocol NativeWebrtcSignallingClientDelegate <NSObject>
@end
API_AVAILABLE(ios(13.0))
@interface NativeWebrtcSignallingClient : NSObject {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> _queue;
NativeWebSocket *_socket;
void (^_didReceiveSessionDescription)(RTCSessionDescription *);
void (^_didReceiveIceCandidate)(RTCIceCandidate *);
}
@property (nonatomic, weak) id<NativeWebrtcSignallingClientDelegate> delegate;
@end
@implementation NativeWebrtcSignallingClient
- (instancetype)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom>)queue didReceiveSessionDescription:(void (^)(RTCSessionDescription *))didReceiveSessionDescription didReceiveIceCandidate:(void (^)(RTCIceCandidate *))didReceiveIceCandidate {
self = [super init];
if (self != nil) {
_queue = queue;
_didReceiveSessionDescription = [didReceiveSessionDescription copy];
_didReceiveIceCandidate = [didReceiveIceCandidate copy];
__weak NativeWebrtcSignallingClient *weakSelf = self;
_socket = [[NativeWebSocket alloc] initWithQueue:queue receivedData:^(NSData *data) {
__strong NativeWebrtcSignallingClient *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf didReceiveData:data];
}];
}
return self;
}
- (void)connect {
[_socket connect];
}
- (void)sendSdp:(RTCSessionDescription *)rtcSdp {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"messageType"] = @"sessionDescription";
json[@"sdp"] = rtcSdp.sdp;
if (rtcSdp.type == RTCSdpTypeOffer) {
json[@"type"] = @"offer";
} else if (rtcSdp.type == RTCSdpTypePrAnswer) {
json[@"type"] = @"prAnswer";
} else if (rtcSdp.type == RTCSdpTypeAnswer) {
json[@"type"] = @"answer";
}
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
if (data != nil) {
[_socket sendData:data];
}
}
- (void)sendCandidate:(RTCIceCandidate *)rtcIceCandidate {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"messageType"] = @"iceCandidate";
json[@"sdp"] = rtcIceCandidate.sdp;
json[@"mLineIndex"] = @(rtcIceCandidate.sdpMLineIndex);
if (rtcIceCandidate.sdpMid != nil) {
json[@"sdpMid"] = rtcIceCandidate.sdpMid;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
if (data != nil) {
[_socket sendData:data];
}
}
- (void)didReceiveData:(NSData *)data {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (![json isKindOfClass:[NSDictionary class]]) {
return;
}
NSString *messageType = json[@"messageType"];
if (![messageType isKindOfClass:[NSString class]]) {
return;
}
if ([messageType isEqualToString:@"sessionDescription"]) {
NSString *sdp = json[@"sdp"];
if (![sdp isKindOfClass:[NSString class]]) {
return;
}
NSString *typeString = json[@"type"];
if (![typeString isKindOfClass:[NSString class]]) {
return;
}
RTCSdpType type;
if ([typeString isEqualToString:@"offer"]) {
type = RTCSdpTypeOffer;
} else if ([typeString isEqualToString:@"prAnswer"]) {
type = RTCSdpTypePrAnswer;
} else if ([typeString isEqualToString:@"answer"]) {
type = RTCSdpTypeAnswer;
} else {
return;
}
if (_didReceiveSessionDescription) {
_didReceiveSessionDescription([[RTCSessionDescription alloc] initWithType:type sdp:sdp]);
}
} else if ([messageType isEqualToString:@"iceCandidate"]) {
NSString *sdp = json[@"sdp"];
if (![sdp isKindOfClass:[NSString class]]) {
return;
}
NSNumber *mLineIndex = json[@"mLineIndex"];
if (![mLineIndex isKindOfClass:[NSNumber class]]) {
return;
}
NSString *sdpMidString = json[@"sdpMid"];
NSString *sdpMid = nil;
if ([sdpMidString isKindOfClass:[NSString class]]) {
sdpMid = sdpMidString;
}
if (_didReceiveIceCandidate) {
_didReceiveIceCandidate([[RTCIceCandidate alloc] initWithSdp:sdp sdpMLineIndex:[mLineIndex intValue] sdpMid:sdpMid]);
}
}
}
@end
@interface NativePeerConnectionDelegate : NSObject <RTCPeerConnectionDelegate> {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> _queue;
void (^_didGenerateIceCandidate)(RTCIceCandidate *);
@ -361,6 +134,9 @@ API_AVAILABLE(ios(13.0))
id<OngoingCallThreadLocalContextQueueWebrtcCustom> _queue;
int32_t _contextId;
bool _isOutgoing;
void (^_sendSignalingData)(NSData * _Nonnull);
NativePeerConnectionDelegate *_peerConnectionDelegate;
OngoingCallNetworkTypeWebrtcCustom _networkType;
@ -372,10 +148,10 @@ API_AVAILABLE(ios(13.0))
OngoingCallStateWebrtcCustom _state;
int32_t _signalBars;
NativeWebrtcSignallingClient *_signallingClient;
RTCPeerConnectionFactory *_peerConnectionFactory;
RTCPeerConnection *_peerConnection;
RTCVideoCapturer *_videoCapturer;
RTCVideoTrack *_localVideoTrack;
RTCVideoTrack *_remoteVideoTrack;
@ -420,12 +196,15 @@ API_AVAILABLE(ios(13.0))
return 80;
}
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom> _Nonnull)queue proxy:(VoipProxyServerWebrtcCustom * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtcCustom)networkType dataSaving:(OngoingCallDataSavingWebrtcCustom)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtcCustom * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtcCustom *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath {
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueueWebrtcCustom> _Nonnull)queue proxy:(VoipProxyServerWebrtcCustom * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtcCustom)networkType dataSaving:(OngoingCallDataSavingWebrtcCustom)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing primaryConnection:(OngoingCallConnectionDescriptionWebrtcCustom * _Nonnull)primaryConnection alternativeConnections:(NSArray<OngoingCallConnectionDescriptionWebrtcCustom *> * _Nonnull)alternativeConnections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P logPath:(NSString * _Nonnull)logPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData {
self = [super init];
if (self != nil) {
_queue = queue;
assert([queue isCurrent]);
_isOutgoing = isOutgoing;
_sendSignalingData = [sendSignalingData copy];
_callReceiveTimeout = 20.0;
_callRingTimeout = 90.0;
_callConnectTimeout = 30.0;
@ -468,7 +247,7 @@ API_AVAILABLE(ios(13.0))
if (strongSelf == nil) {
return;
}
[strongSelf->_signallingClient sendCandidate:iceCandidate];
[strongSelf sendCandidate:iceCandidate];
} didChangeIceState: ^(OngoingCallStateWebrtcCustom state) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
@ -501,58 +280,6 @@ API_AVAILABLE(ios(13.0))
_localVideoTrack = [_peerConnectionFactory videoTrackWithSource:videoSource trackId:@"video0"];
[_peerConnection addTrack:_localVideoTrack streamIds:@[streamId]];
NSDictionary *mediaConstraints = @{
kRTCMediaConstraintsOfferToReceiveAudio: kRTCMediaConstraintsValueTrue,
kRTCMediaConstraintsOfferToReceiveVideo: kRTCMediaConstraintsValueTrue
};
RTCMediaConstraints *connectionConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mediaConstraints optionalConstraints:nil];
_signallingClient = [[NativeWebrtcSignallingClient alloc] initWithQueue:queue didReceiveSessionDescription:^(RTCSessionDescription *sessionDescription) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
if (strongSelf->_receivedRemoteDescription) {
return;
}
strongSelf->_receivedRemoteDescription = true;
[strongSelf->_peerConnection setRemoteDescription:sessionDescription completionHandler:^(__unused NSError * _Nullable error) {
}];
if (!isOutgoing) {
[strongSelf->_peerConnection answerForConstraints:connectionConstraints completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf->_peerConnection setLocalDescription:sdp completionHandler:^(__unused NSError * _Nullable error) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf->_signallingClient sendSdp:sdp];
}];
}];
}];
}
} didReceiveIceCandidate:^(RTCIceCandidate *iceCandidate) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
voipLog(@"didReceiveIceCandidate: %@", iceCandidate);
[strongSelf->_peerConnection addIceCandidate:iceCandidate];
}];
[_signallingClient connect];
if (isOutgoing) {
id<OngoingCallThreadLocalContextQueueWebrtcCustom> queue = _queue;
NSDictionary *mediaConstraints = @{
@ -596,7 +323,7 @@ API_AVAILABLE(ios(13.0))
return;
}
[_signallingClient sendSdp:sessionDescription];
[self sendSdp:sessionDescription];
__weak OngoingCallThreadLocalContextWebrtcCustom *weakSelf = self;
[_queue dispatchAfter:1.0 block:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
@ -657,35 +384,6 @@ API_AVAILABLE(ios(13.0))
[cameraCapturer startCaptureWithDevice:frontCamera format:bestFormat fps:27 completionHandler:^(NSError * _Nonnull error) {
}];
//add renderer
/*
guard let capturer = self.videoCapturer as? RTCCameraVideoCapturer else {
return
}
guard
let frontCamera = (RTCCameraVideoCapturer.captureDevices().first { $0.position == .front }),
// choose highest res
let format = (RTCCameraVideoCapturer.supportedFormats(for: frontCamera).sorted { (f1, f2) -> Bool in
let width1 = CMVideoFormatDescriptionGetDimensions(f1.formatDescription).width
let width2 = CMVideoFormatDescriptionGetDimensions(f2.formatDescription).width
return width1 < width2
}).last,
// choose highest fps
let fps = (format.videoSupportedFrameRateRanges.sorted { return $0.maxFrameRate < $1.maxFrameRate }.last) else {
return
}
capturer.startCapture(with: frontCamera,
format: format,
fps: Int(fps.maxFrameRate))
self.localVideoTrack?.add(renderer)
*/
}
- (bool)needRate {
@ -716,6 +414,129 @@ API_AVAILABLE(ios(13.0))
return [NSData data];
}
- (void)sendSdp:(RTCSessionDescription *)rtcSdp {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"messageType"] = @"sessionDescription";
json[@"sdp"] = rtcSdp.sdp;
if (rtcSdp.type == RTCSdpTypeOffer) {
json[@"type"] = @"offer";
} else if (rtcSdp.type == RTCSdpTypePrAnswer) {
json[@"type"] = @"prAnswer";
} else if (rtcSdp.type == RTCSdpTypeAnswer) {
json[@"type"] = @"answer";
}
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
if (data != nil) {
_sendSignalingData(data);
}
}
- (void)sendCandidate:(RTCIceCandidate *)rtcIceCandidate {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"messageType"] = @"iceCandidate";
json[@"sdp"] = rtcIceCandidate.sdp;
json[@"mLineIndex"] = @(rtcIceCandidate.sdpMLineIndex);
if (rtcIceCandidate.sdpMid != nil) {
json[@"sdpMid"] = rtcIceCandidate.sdpMid;
}
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil];
if (data != nil) {
_sendSignalingData(data);
}
}
- (void)receiveSignalingData:(NSData *)data {
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
if (![json isKindOfClass:[NSDictionary class]]) {
return;
}
NSString *messageType = json[@"messageType"];
if (![messageType isKindOfClass:[NSString class]]) {
return;
}
if ([messageType isEqualToString:@"sessionDescription"]) {
NSString *sdp = json[@"sdp"];
if (![sdp isKindOfClass:[NSString class]]) {
return;
}
NSString *typeString = json[@"type"];
if (![typeString isKindOfClass:[NSString class]]) {
return;
}
RTCSdpType type;
if ([typeString isEqualToString:@"offer"]) {
type = RTCSdpTypeOffer;
} else if ([typeString isEqualToString:@"prAnswer"]) {
type = RTCSdpTypePrAnswer;
} else if ([typeString isEqualToString:@"answer"]) {
type = RTCSdpTypeAnswer;
} else {
return;
}
if (_receivedRemoteDescription) {
return;
}
_receivedRemoteDescription = true;
RTCSessionDescription *sessionDescription = [[RTCSessionDescription alloc] initWithType:type sdp:sdp];
NSDictionary *mediaConstraints = @{
kRTCMediaConstraintsOfferToReceiveAudio: kRTCMediaConstraintsValueTrue,
kRTCMediaConstraintsOfferToReceiveVideo: kRTCMediaConstraintsValueTrue
};
RTCMediaConstraints *connectionConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mediaConstraints optionalConstraints:nil];
[_peerConnection setRemoteDescription:sessionDescription completionHandler:^(__unused NSError * _Nullable error) {
}];
if (!_isOutgoing) {
__weak OngoingCallThreadLocalContextWebrtcCustom *weakSelf = self;
[_peerConnection answerForConstraints:connectionConstraints completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
id<OngoingCallThreadLocalContextQueueWebrtcCustom> queue = strongSelf->_queue;
[strongSelf->_peerConnection setLocalDescription:sdp completionHandler:^(__unused NSError * _Nullable error) {
[queue dispatch:^{
__strong OngoingCallThreadLocalContextWebrtcCustom *strongSelf = weakSelf;
if (strongSelf == nil) {
return;
}
[strongSelf sendSdp:sdp];
}];
}];
}];
}
} else if ([messageType isEqualToString:@"iceCandidate"]) {
NSString *sdp = json[@"sdp"];
if (![sdp isKindOfClass:[NSString class]]) {
return;
}
NSNumber *mLineIndex = json[@"mLineIndex"];
if (![mLineIndex isKindOfClass:[NSNumber class]]) {
return;
}
NSString *sdpMidString = json[@"sdpMid"];
NSString *sdpMid = nil;
if ([sdpMidString isKindOfClass:[NSString class]]) {
sdpMid = sdpMidString;
}
RTCIceCandidate *iceCandidate = [[RTCIceCandidate alloc] initWithSdp:sdp sdpMLineIndex:[mLineIndex intValue] sdpMid:sdpMid];
voipLog(@"didReceiveIceCandidate: %@", iceCandidate);
[_peerConnection addIceCandidate:iceCandidate];
}
}
- (void)setIsMuted:(bool)isMuted {
for (RTCRtpTransceiver *transceiver in _peerConnection.transceivers) {
if ([transceiver isKindOfClass:[RTCAudioTrack class]]) {