Conference updates

This commit is contained in:
Isaac 2025-04-04 16:51:46 +04:00
parent e8b7f53c84
commit 0a499f4e2b
10 changed files with 340 additions and 92 deletions

View File

@ -961,7 +961,6 @@ private final class NotificationServiceHandler {
if let locKey = payloadJson["loc-key"] as? String, (locKey == "CONF_CALL_REQUEST" || locKey == "CONF_CALL_MISSED"), let callIdString = payloadJson["call_id"] as? String { if let locKey = payloadJson["loc-key"] as? String, (locKey == "CONF_CALL_REQUEST" || locKey == "CONF_CALL_MISSED"), let callIdString = payloadJson["call_id"] as? String {
if let callId = Int64(callIdString) { if let callId = Int64(callIdString) {
if let updates = payloadJson["updates"] as? String { if let updates = payloadJson["updates"] as? String {
var updateString = updates var updateString = updates
updateString = updateString.replacingOccurrences(of: "-", with: "+") updateString = updateString.replacingOccurrences(of: "-", with: "+")

View File

@ -487,6 +487,7 @@ public protocol PresentationGroupCall: AnyObject {
func updateTitle(_ title: String) func updateTitle(_ title: String)
func invitePeer(_ peerId: EnginePeer.Id, isVideo: Bool) -> Bool func invitePeer(_ peerId: EnginePeer.Id, isVideo: Bool) -> Bool
func kickPeer(id: EnginePeer.Id)
func removedPeer(_ peerId: EnginePeer.Id) func removedPeer(_ peerId: EnginePeer.Id)
var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> { get } var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> { get }

View File

@ -217,6 +217,12 @@ public final class SharedCallAudioContext {
} }
} }
} }
public func switchToSpeakerIfBuiltin() {
if case .builtin = self.currentAudioOutputValue {
self.setCurrentAudioOutput(.speaker)
}
}
} }
public final class PresentationCallImpl: PresentationCall { public final class PresentationCallImpl: PresentationCall {
@ -1032,6 +1038,8 @@ public final class PresentationCallImpl: PresentationCall {
self.conferenceCallImpl = conferenceCall self.conferenceCallImpl = conferenceCall
conferenceCall.upgradedConferenceCall = self conferenceCall.upgradedConferenceCall = self
self.sharedAudioContext?.switchToSpeakerIfBuiltin()
for (peerId, isVideo) in self.pendingInviteToConferencePeerIds { for (peerId, isVideo) in self.pendingInviteToConferencePeerIds {
let _ = conferenceCall.invitePeer(peerId, isVideo: isVideo) let _ = conferenceCall.invitePeer(peerId, isVideo: isVideo)
} }

View File

@ -3986,6 +3986,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
} }
public func kickPeer(id: EnginePeer.Id) {
if self.isConference {
self.removedPeer(id)
self.e2eContext?.kickPeer(id: id)
}
}
public func removedPeer(_ peerId: PeerId) { public func removedPeer(_ peerId: PeerId) {
var updatedInvitedPeers = self.invitedPeersValue var updatedInvitedPeers = self.invitedPeersValue
updatedInvitedPeers.removeAll(where: { $0.id == peerId}) updatedInvitedPeers.removeAll(where: { $0.id == peerId})

View File

@ -149,6 +149,7 @@ final class VideoChatParticipantsComponent: Component {
let safeInsets: UIEdgeInsets let safeInsets: UIEdgeInsets
let interfaceOrientation: UIInterfaceOrientation let interfaceOrientation: UIInterfaceOrientation
let openParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void let openParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
let openInvitedParticipantContextMenu: (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void
let updateMainParticipant: (VideoParticipantKey?, Bool?) -> Void let updateMainParticipant: (VideoParticipantKey?, Bool?) -> Void
let updateIsMainParticipantPinned: (Bool) -> Void let updateIsMainParticipantPinned: (Bool) -> Void
let updateIsExpandedUIHidden: (Bool) -> Void let updateIsExpandedUIHidden: (Bool) -> Void
@ -169,6 +170,7 @@ final class VideoChatParticipantsComponent: Component {
safeInsets: UIEdgeInsets, safeInsets: UIEdgeInsets,
interfaceOrientation: UIInterfaceOrientation, interfaceOrientation: UIInterfaceOrientation,
openParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void, openParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
openInvitedParticipantContextMenu: @escaping (EnginePeer.Id, ContextExtractedContentContainingView, ContextGesture?) -> Void,
updateMainParticipant: @escaping (VideoParticipantKey?, Bool?) -> Void, updateMainParticipant: @escaping (VideoParticipantKey?, Bool?) -> Void,
updateIsMainParticipantPinned: @escaping (Bool) -> Void, updateIsMainParticipantPinned: @escaping (Bool) -> Void,
updateIsExpandedUIHidden: @escaping (Bool) -> Void, updateIsExpandedUIHidden: @escaping (Bool) -> Void,
@ -188,6 +190,7 @@ final class VideoChatParticipantsComponent: Component {
self.safeInsets = safeInsets self.safeInsets = safeInsets
self.interfaceOrientation = interfaceOrientation self.interfaceOrientation = interfaceOrientation
self.openParticipantContextMenu = openParticipantContextMenu self.openParticipantContextMenu = openParticipantContextMenu
self.openInvitedParticipantContextMenu = openInvitedParticipantContextMenu
self.updateMainParticipant = updateMainParticipant self.updateMainParticipant = updateMainParticipant
self.updateIsMainParticipantPinned = updateIsMainParticipantPinned self.updateIsMainParticipantPinned = updateIsMainParticipantPinned
self.updateIsExpandedUIHidden = updateIsExpandedUIHidden self.updateIsExpandedUIHidden = updateIsExpandedUIHidden
@ -1317,8 +1320,18 @@ final class VideoChatParticipantsComponent: Component {
inset: 2.0, inset: 2.0,
background: UIColor(white: 0.1, alpha: 1.0) background: UIColor(white: 0.1, alpha: 1.0)
), ),
action: nil, action: { [weak self] peer, _, itemView in
contextAction: nil guard let self, let component = self.component else {
return
}
component.openInvitedParticipantContextMenu(peer.id, itemView.extractedContainerView, nil)
},
contextAction: { [weak self] peer, sourceView, gesture in
guard let self, let component = self.component else {
return
}
component.openInvitedParticipantContextMenu(peer.id, sourceView, gesture)
}
) )
} }

View File

@ -2329,6 +2329,12 @@ final class VideoChatScreenComponent: Component {
} }
self.openParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture) self.openParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
}, },
openInvitedParticipantContextMenu: { [weak self] id, sourceView, gesture in
guard let self else {
return
}
self.openInvitedParticipantContextMenu(id: id, sourceView: sourceView, gesture: gesture)
},
updateMainParticipant: { [weak self] key, alsoSetIsUIHidden in updateMainParticipant: { [weak self] key, alsoSetIsUIHidden in
guard let self else { guard let self else {
return return

View File

@ -299,7 +299,11 @@ extension VideoChatScreenComponent.View {
} }
let _ = groupCall.accountContext.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: groupCall.accountContext.engine, peerId: callPeerId, memberId: peer.id, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)).start() let _ = groupCall.accountContext.peerChannelMemberCategoriesContextsManager.updateMemberBannedRights(engine: groupCall.accountContext.engine, peerId: callPeerId, memberId: peer.id, bannedRights: TelegramChatBannedRights(flags: [.banReadMessages], untilDate: Int32.max)).start()
groupCall.removedPeer(peer.id) if groupCall.isConference {
groupCall.kickPeer(id: peer.id)
} else {
groupCall.removedPeer(peer.id)
}
self.presentUndoOverlay(content: .banned(text: environment.strings.VoiceChat_RemovedPeerText(EnginePeer(peer).displayTitle(strings: environment.strings, displayOrder: nameDisplayOrder)).string), action: { _ in return false }) self.presentUndoOverlay(content: .banned(text: environment.strings.VoiceChat_RemovedPeerText(EnginePeer(peer).displayTitle(strings: environment.strings, displayOrder: nameDisplayOrder)).string), action: { _ in return false })
})) }))
@ -347,6 +351,62 @@ extension VideoChatScreenComponent.View {
environment.controller()?.presentInGlobalOverlay(contextController) environment.controller()?.presentInGlobalOverlay(contextController)
} }
func openInvitedParticipantContextMenu(id: EnginePeer.Id, sourceView: ContextExtractedContentContainingView, gesture: ContextGesture?) {
guard let environment = self.environment else {
return
}
guard let currentCall = self.currentCall else {
return
}
guard case .group = self.currentCall else {
return
}
let itemsForEntry: () -> [ContextMenuItem] = { [weak self] in
guard let self, let environment = self.environment else {
return []
}
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: environment.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
}, action: { [weak self] c, _ in
c?.dismiss(result: .dismissWithoutContent, completion: nil)
guard let self else {
return
}
guard case let .group(groupCall) = self.currentCall else {
return
}
groupCall.kickPeer(id: id)
})))
return items
}
let items = itemsForEntry()
let presentationData = currentCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
let contextController = ContextController(
presentationData: presentationData,
source: .extracted(ParticipantExtractedContentSource(contentView: sourceView)),
items: .single(ContextController.Items(content: .list(items))),
recognizer: nil,
gesture: gesture
)
environment.controller()?.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismiss()
}
return true
})
environment.controller()?.presentInGlobalOverlay(contextController)
}
private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) { private func openAvatarForEditing(fromGallery: Bool = false, completion: @escaping () -> Void = {}) {
guard let currentCall = self.currentCall else { guard let currentCall = self.currentCall else {
return return

View File

@ -52,6 +52,8 @@ public final class ConferenceCallE2EContext {
private var scheduledSynchronizeRemovedParticipantsAfterPoll: Bool = false private var scheduledSynchronizeRemovedParticipantsAfterPoll: Bool = false
private var synchronizeRemovedParticipantsDisposable: Disposable? private var synchronizeRemovedParticipantsDisposable: Disposable?
private var synchronizeRemovedParticipantsTimer: Foundation.Timer? private var synchronizeRemovedParticipantsTimer: Foundation.Timer?
private var pendingKickPeers: [EnginePeer.Id] = []
init(queue: Queue, engine: TelegramEngine, callId: Int64, accessHash: Int64, userId: Int64, reference: InternalGroupCallReference, state: Atomic<ContextStateHolder>, initializeState: @escaping (TelegramKeyPair, Int64, Data) -> ConferenceCallE2EContextState?, keyPair: TelegramKeyPair) { init(queue: Queue, engine: TelegramEngine, callId: Int64, accessHash: Int64, userId: Int64, reference: InternalGroupCallReference, state: Atomic<ContextStateHolder>, initializeState: @escaping (TelegramKeyPair, Int64, Data) -> ConferenceCallE2EContextState?, keyPair: TelegramKeyPair) {
precondition(queue.isCurrent()) precondition(queue.isCurrent())
@ -91,37 +93,53 @@ public final class ConferenceCallE2EContext {
} }
func addChainBlocksUpdate(subChainId: Int, blocks: [Data], nextOffset: Int) { func addChainBlocksUpdate(subChainId: Int, blocks: [Data], nextOffset: Int) {
var processBlock = true
let updateBaseOffset = nextOffset - blocks.count let updateBaseOffset = nextOffset - blocks.count
if subChainId == 0 { var blocksToProcess: [Data] = []
if let e2ePoll0Offset = self.e2ePoll0Offset { var shouldPoll = false
if e2ePoll0Offset == updateBaseOffset { for i in 0 ..< blocks.count {
self.e2ePoll0Offset = nextOffset let blockOffset = updateBaseOffset + i
} else if e2ePoll0Offset < updateBaseOffset { if subChainId == 0 {
self.e2ePoll(subChainId: subChainId) if var e2ePoll0Offset = self.e2ePoll0Offset {
} else { if blockOffset == e2ePoll0Offset {
processBlock = false e2ePoll0Offset += 1
self.e2ePoll0Offset = e2ePoll0Offset
blocksToProcess.append(blocks[i])
} else if blockOffset > e2ePoll0Offset {
shouldPoll = true
}
} }
} else { } else if subChainId == 1 {
processBlock = false if var e2ePoll1Offset = self.e2ePoll1Offset {
} if blockOffset == e2ePoll1Offset {
} else if subChainId == 1 { e2ePoll1Offset += 1
if let e2ePoll1Offset = self.e2ePoll1Offset { self.e2ePoll1Offset = e2ePoll1Offset
if e2ePoll1Offset == updateBaseOffset { blocksToProcess.append(blocks[i])
self.e2ePoll1Offset = nextOffset } else if blockOffset > e2ePoll1Offset {
} else if e2ePoll1Offset < updateBaseOffset { shouldPoll = true
self.e2ePoll(subChainId: subChainId) }
} else {
processBlock = false
} }
} else {
processBlock = false
} }
} else {
processBlock = false
} }
if processBlock {
self.addE2EBlocks(blocks: blocks, subChainId: subChainId) if !blocksToProcess.isEmpty {
if subChainId == 0 {
if self.e2ePoll0Disposable != nil {
self.e2ePoll0Disposable?.dispose()
self.e2ePoll0Disposable = nil
shouldPoll = true
}
} else if subChainId == 1 {
if self.e2ePoll1Disposable != nil {
self.e2ePoll1Disposable?.dispose()
self.e2ePoll1Disposable = nil
shouldPoll = true
}
}
self.addE2EBlocks(blocks: blocksToProcess, subChainId: subChainId)
}
if shouldPoll {
self.e2ePoll(subChainId: subChainId)
} }
} }
@ -186,6 +204,14 @@ public final class ConferenceCallE2EContext {
guard let self else { guard let self else {
return return
} }
if subChainId == 0 {
self.e2ePoll0Disposable?.dispose()
self.e2ePoll0Disposable = nil
} else if subChainId == 1 {
self.e2ePoll1Disposable?.dispose()
self.e2ePoll1Disposable = nil
}
var delayPoll = true var delayPoll = true
if let result { if let result {
@ -247,71 +273,139 @@ public final class ConferenceCallE2EContext {
let callId = self.callId let callId = self.callId
let accessHash = self.accessHash let accessHash = self.accessHash
self.synchronizeRemovedParticipantsDisposable?.dispose() if !self.pendingKickPeers.isEmpty {
self.synchronizeRemovedParticipantsDisposable = (_internal_getGroupCallParticipants( let pendingKickPeers = self.pendingKickPeers
account: self.engine.account, self.pendingKickPeers.removeAll()
reference: self.reference,
offset: "",
ssrcs: [],
limit: 100,
sortAscending: true
)
|> map(Optional.init)
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<Bool, NoError> in
guard let result else {
return .single(false)
}
let blockchainPeerIds = state.with { state -> [Int64] in
guard let state = state.state else {
return []
}
return state.getParticipantIds()
}
// Peer ids that are in the blockchain but not in the server list
let removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in
return !result.participants.contains(where: { $0.peer.id.id._internalGetInt64Value() == blockchainPeerId })
}
if removedPeerIds.isEmpty { self.synchronizeRemovedParticipantsDisposable?.dispose()
return .single(false)
} let removeBlock = state.with({ state -> Data? in
guard let removeBlock = state.with({ state -> Data? in
guard let state = state.state else { guard let state = state.state else {
return nil return nil
} }
return state.generateRemoveParticipantsBlock(participantIds: removedPeerIds) let currentIds = state.getParticipantIds()
}) else { let remainingIds = pendingKickPeers.filter({ currentIds.contains($0.id._internalGetInt64Value()) })
return .single(false) if remainingIds.isEmpty {
} return nil
}
return engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .cleanup, participantIds: removedPeerIds, block: removeBlock)
|> map { result -> Bool in return state.generateRemoveParticipantsBlock(participantIds: remainingIds.map { $0.id._internalGetInt64Value() })
switch result { })
case .success: if let removeBlock {
return true self.synchronizeRemovedParticipantsDisposable = (engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .kick, participantIds: pendingKickPeers.map { $0.id._internalGetInt64Value() }, block: removeBlock)
case .pollBlocksAndRetry: |> map { result -> Bool in
return false switch result {
case .success:
return true
case .pollBlocksAndRetry:
return false
}
}
|> deliverOnMainQueue).startStrict(next: { [weak self] shouldRetry in
guard let self else {
return
}
if shouldRetry {
for id in pendingKickPeers {
if !self.pendingKickPeers.contains(id) {
self.pendingKickPeers.append(id)
}
}
}
self.isSynchronizingRemovedParticipants = false
if self.scheduledSynchronizeRemovedParticipants {
self.scheduledSynchronizeRemovedParticipants = false
self.synchronizeRemovedParticipants()
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
self.e2ePoll(subChainId: 0)
}
})
} else {
self.isSynchronizingRemovedParticipants = false
if self.scheduledSynchronizeRemovedParticipants {
self.scheduledSynchronizeRemovedParticipants = false
self.synchronizeRemovedParticipants()
} }
} }
} else {
self.synchronizeRemovedParticipantsDisposable?.dispose()
self.synchronizeRemovedParticipantsDisposable = (_internal_getGroupCallParticipants(
account: self.engine.account,
reference: self.reference,
offset: "",
ssrcs: [],
limit: 100,
sortAscending: true
)
|> map(Optional.init)
|> `catch` { _ -> Signal<GroupCallParticipantsContext.State?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<Bool, NoError> in
guard let result else {
return .single(false)
}
let blockchainPeerIds = state.with { state -> [Int64] in
guard let state = state.state else {
return []
}
return state.getParticipantIds()
}
// Peer ids that are in the blockchain but not in the server list
let removedPeerIds = blockchainPeerIds.filter { blockchainPeerId in
return !result.participants.contains(where: { $0.peer.id.id._internalGetInt64Value() == blockchainPeerId })
}
if removedPeerIds.isEmpty {
return .single(false)
}
guard let removeBlock = state.with({ state -> Data? in
guard let state = state.state else {
return nil
}
return state.generateRemoveParticipantsBlock(participantIds: removedPeerIds)
}) else {
return .single(false)
}
return engine.calls.removeGroupCallBlockchainParticipants(callId: callId, accessHash: accessHash, mode: .cleanup, participantIds: removedPeerIds, block: removeBlock)
|> map { result -> Bool in
switch result {
case .success:
return true
case .pollBlocksAndRetry:
return false
}
}
}
|> deliverOn(self.queue)).startStrict(next: { [weak self] shouldRetry in
guard let self else {
return
}
self.isSynchronizingRemovedParticipants = false
if self.scheduledSynchronizeRemovedParticipants {
self.scheduledSynchronizeRemovedParticipants = false
self.synchronizeRemovedParticipants()
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
self.e2ePoll(subChainId: 0)
}
})
}
}
func kickPeer(id: EnginePeer.Id) {
//TODO:release
if !self.pendingKickPeers.contains(id) {
self.pendingKickPeers.append(id)
self.synchronizeRemovedParticipants()
} }
|> deliverOn(self.queue)).startStrict(next: { [weak self] shouldRetry in
guard let self else {
return
}
self.isSynchronizingRemovedParticipants = false
if self.scheduledSynchronizeRemovedParticipants {
self.scheduledSynchronizeRemovedParticipants = false
self.synchronizeRemovedParticipants()
} else if shouldRetry && !self.scheduledSynchronizeRemovedParticipantsAfterPoll {
self.scheduledSynchronizeRemovedParticipantsAfterPoll = true
self.e2ePoll(subChainId: 0)
}
})
} }
} }
@ -349,4 +443,10 @@ public final class ConferenceCallE2EContext {
impl.synchronizeRemovedParticipants() impl.synchronizeRemovedParticipants()
} }
} }
public func kickPeer(id: EnginePeer.Id) {
self.impl.with { impl in
impl.kickPeer(id: id)
}
}
} }

View File

@ -83,6 +83,13 @@ static NSString *hexStringFromData(NSData *data) {
if (self != nil) { if (self != nil) {
_callId = callId; _callId = callId;
_keyPair = keyPair; _keyPair = keyPair;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
#if DEBUG
tde2e_api::set_log_verbosity_level(4);
#endif
});
} }
return self; return self;
} }
@ -130,7 +137,17 @@ static NSString *hexStringFromData(NSData *data) {
#if DEBUG #if DEBUG
auto describeResult = tde2e_api::call_describe_message(it); auto describeResult = tde2e_api::call_describe_message(it);
if (describeResult.is_ok()) { if (describeResult.is_ok()) {
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: block %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]); NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
if (utf8String) {
NSLog(@"TdCall.call_pull_outbound_messages block: %@", utf8String);
} else {
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
if (lossyString) {
NSLog(@"TdCall.call_pull_outbound_messages block (lossy conversion): %@", lossyString);
} else {
NSLog(@"TdCall.call_pull_outbound_messages block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
}
}
} else { } else {
NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: describe block failed"); NSLog(@"TdCall.takeOutgoingBroadcastBlocks call_pull_outbound_messages: describe block failed");
} }
@ -178,7 +195,17 @@ static NSString *hexStringFromData(NSData *data) {
#if DEBUG #if DEBUG
auto describeResult = tde2e_api::call_describe_block(mappedBlock); auto describeResult = tde2e_api::call_describe_block(mappedBlock);
if (describeResult.is_ok()) { if (describeResult.is_ok()) {
NSLog(@"TdCall.applyBlock block: %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]); NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
if (utf8String) {
NSLog(@"TdCall.applyBlock block: %@", utf8String);
} else {
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
if (lossyString) {
NSLog(@"TdCall.applyBlock block (lossy conversion): %@", lossyString);
} else {
NSLog(@"TdCall.applyBlock block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
}
}
} else { } else {
NSLog(@"TdCall.applyBlock block: describe block failed"); NSLog(@"TdCall.applyBlock block: describe block failed");
} }
@ -196,7 +223,17 @@ static NSString *hexStringFromData(NSData *data) {
#if DEBUG #if DEBUG
auto describeResult = tde2e_api::call_describe_message(mappedBlock); auto describeResult = tde2e_api::call_describe_message(mappedBlock);
if (describeResult.is_ok()) { if (describeResult.is_ok()) {
NSLog(@"TdCall.applyBroadcastBlock block: %@", [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding]); NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
if (utf8String) {
NSLog(@"TdCall.applyBroadcastBlock block: %@", utf8String);
} else {
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
if (lossyString) {
NSLog(@"TdCall.applyBroadcastBlock block (lossy conversion): %@", lossyString);
} else {
NSLog(@"TdCall.applyBroadcastBlock block: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
}
}
} else { } else {
NSLog(@"TdCall.applyBroadcastBlock block: describe block failed"); NSLog(@"TdCall.applyBroadcastBlock block: describe block failed");
} }
@ -206,6 +243,23 @@ static NSString *hexStringFromData(NSData *data) {
if (!result.is_ok()) { if (!result.is_ok()) {
return; return;
} }
describeResult = tde2e_api::call_describe(_callId);
if (describeResult.is_ok()) {
NSString *utf8String = [[NSString alloc] initWithBytes:describeResult.value().data() length:describeResult.value().size() encoding:NSUTF8StringEncoding];
if (utf8String) {
NSLog(@"TdCall.applyBroadcastBlock call after apply: %@", utf8String);
} else {
NSString *lossyString = [[NSString alloc] initWithData:[NSData dataWithBytes:describeResult.value().data() length:describeResult.value().size()] encoding:NSASCIIStringEncoding];
if (lossyString) {
NSLog(@"TdCall.applyBroadcastBlock call after apply (lossy conversion): %@", lossyString);
} else {
NSLog(@"TdCall.applyBroadcastBlock call after apply: [binary data, length: %lu]", (unsigned long)describeResult.value().size());
}
}
} else {
NSLog(@"TdCall.applyBroadcastBlock call after apply: describe block failed");
}
} }
- (nullable NSData *)generateRemoveParticipantsBlock:(NSArray<NSNumber *> *)participantIds { - (nullable NSData *)generateRemoveParticipantsBlock:(NSArray<NSNumber *> *)participantIds {

View File

@ -14,7 +14,6 @@ options=""
options="$options -DOPENSSL_FOUND=1" options="$options -DOPENSSL_FOUND=1"
options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}" options="$options -DOPENSSL_CRYPTO_LIBRARY=${openssl_crypto_library}"
options="$options -DOPENSSL_INCLUDE_DIR=${OPENSSL_DIR}/src/include" options="$options -DOPENSSL_INCLUDE_DIR=${OPENSSL_DIR}/src/include"
#options="$options -DOPENSSL_LIBRARIES=${openssl_crypto_library}"
options="$options -DCMAKE_BUILD_TYPE=Release" options="$options -DCMAKE_BUILD_TYPE=Release"
cd "$BUILD_DIR" cd "$BUILD_DIR"