Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2022-11-07 17:34:39 +04:00
commit ec4283159b
35 changed files with 701 additions and 168 deletions

View File

@ -8242,5 +8242,8 @@ Sorry for the inconvenience.";
"Undo.DeletedTopic" = "Topic Deleted";
"ChatList.MaxThreadPinsFinalText_1" = "Sorry, you can't pin more than **%@** thread to the top. Unpin some that are currently pinned.";
"ChatList.MaxThreadPinsFinalText_any" = "Sorry, you can't pin more than **%@** threads to the top. Unpin some that are currently pinned.";
"EmojiSearch.SearchTopicIconsPlaceholder" = "Search Topic Icons";
"EmojiSearch.SearchTopicIconsEmptyResult" = "No emoji found";

View File

@ -519,7 +519,19 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
items.append(.action(ContextMenuActionItem(text: isPinned ? presentationData.strings.ChatList_Context_Unpin : presentationData.strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
let _ = context.engine.peers.setForumChannelTopicPinned(id: peerId, threadId: threadId, isPinned: !isPinned).start()
let _ = (context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId)
|> deliverOnMainQueue).start(error: { error in
switch error {
case let .limitReached(count):
if let chatListController = chatListController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text = presentationData.strings.ChatList_MaxThreadPinsFinalText(Int32(count))
chatListController.present(textAlertController(context: context, title: presentationData.strings.Premium_LimitReached, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], parseMarkdown: true), in: .window(.root))
}
default:
break
}
})
})))
}

View File

@ -3874,7 +3874,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
private func setPeerThreadPinned(peerId: EnginePeer.Id, threadId: Int64, isPinned: Bool) {
self.actionDisposables.add(self.context.engine.peers.setForumChannelTopicPinned(id: peerId, threadId: threadId, isPinned: isPinned).start())
self.actionDisposables.add(self.context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId).start())
}
public func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool = false, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) {

View File

@ -795,7 +795,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
}
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
}
@ -829,7 +829,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} else {
result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage
}
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false)
if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author {
result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)"
}
@ -1387,7 +1387,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var hideAuthor = false
switch contentPeer {
case let .chat(itemPeer):
var (peer, initialHideAuthor, messageText, spoilers, customEmojiRanges) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
var (peer, initialHideAuthor, messageText, spoilers, customEmojiRanges) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup)
if case let .psa(_, maybePsaText) = promoInfo, let psaText = maybePsaText {
initialHideAuthor = true

View File

@ -45,11 +45,18 @@ private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType {
return currentType
}
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?) {
public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, contentSettings: ContentSettings, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?) {
let peer: EnginePeer?
let message = messages.last
if let restrictionReason = message?._asMessage().restrictionReason(platform: "ios", contentSettings: contentSettings) {
return (nil, false, restrictionReason, nil, nil)
}
if let restrictionReason = chatPeer.chatMainPeer?.restrictionText(platform: "ios", contentSettings: contentSettings) {
return (nil, false, restrictionReason, nil, nil)
}
var hideAuthor = false
var messageText: String
var spoilers: [NSRange]?

View File

@ -1697,12 +1697,15 @@ public final class ChatListNode: ListView {
})
self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal<Bool, NoError> in
if let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries {
guard case let .chatList(groupId) = strongSelf.location else {
guard let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries else {
return .single(false)
}
guard fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count else {
return .single(false)
}
if fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count {
switch strongSelf.location {
case let .chatList(groupId):
let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex]
let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex]
@ -1772,11 +1775,83 @@ public final class ChatListNode: ListView {
return .single(false)
}
}
}
}
}
} else {
return .single(false)
}
case let .forum(peerId):
let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex]
let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex]
var referenceId: Int64?
var beforeAll = false
switch toEntry {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _):
if promoInfo != nil {
beforeAll = true
} else {
if case let .forum(_, _, threadId, _, _) = index {
referenceId = threadId
}
}
default:
break
}
if case let .index(index) = fromEntry.sortIndex, case let .forum(pinningIndex, _, _, _, _) = index, case .index = pinningIndex {
let engine = strongSelf.context.engine
return engine.peers.getForumChannelPinnedTopics(id: peerId)
|> mapToSignal { itemIds -> Signal<Bool, NoError> in
var itemIds = itemIds
var itemId: Int64?
switch fromEntry {
case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
if case let .forum(_, _, threadId, _, _) = index {
itemId = threadId
}
default:
break
}
if let itemId = itemId {
itemIds = itemIds.filter({ $0 != itemId })
if let referenceId = referenceId {
var inserted = false
for i in 0 ..< itemIds.count {
if itemIds[i] == referenceId {
if fromIndex < toIndex {
itemIds.insert(itemId, at: i + 1)
} else {
itemIds.insert(itemId, at: i)
}
inserted = true
break
}
}
if !inserted {
itemIds.append(itemId)
}
} else if beforeAll {
itemIds.insert(itemId, at: 0)
} else {
itemIds.append(itemId)
}
return engine.peers.setForumChannelPinnedTopics(id: peerId, threadIds: itemIds)
|> map { _ -> Bool in
}
|> `catch` { _ -> Signal<Bool, NoError> in
return .single(false)
}
|> then(Signal<Bool, NoError>.single(true))
} else {
return .single(false)
}
}
} else {
return .single(false)
}
}
}
var startedScrollingAtUpperBound = false
self.beganInteractiveDragging = { [weak self] _ in

View File

@ -4,10 +4,16 @@ import Postbox
public extension Message {
func isRestricted(platform: String, contentSettings: ContentSettings) -> Bool {
if let attribute = self.restrictedContentAttribute {
return attribute.platformText(platform: platform, contentSettings: contentSettings) != nil
return self.restrictionReason(platform: platform, contentSettings: contentSettings) != nil
}
return false
func restrictionReason(platform: String, contentSettings: ContentSettings) -> String? {
if let attribute = self.restrictedContentAttribute {
if let value = attribute.platformText(platform: platform, contentSettings: contentSettings) {
return value
}
}
return nil
}
}

View File

@ -268,7 +268,7 @@ private final class ChatListViewSpaceState {
}
postboxLog("allIndices not unique, repeated: \(debugRepeatedIndices)")
assert(false)
//assert(false)
//preconditionFailure()
}
if Set(allEntityIds).count != allEntityIds.count {

View File

@ -778,7 +778,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-761649164] = { return Api.Update.parse_updateChannelMessageForwards($0) }
dict[-232346616] = { return Api.Update.parse_updateChannelMessageViews($0) }
dict[-1738720581] = { return Api.Update.parse_updateChannelParticipant($0) }
dict[-158027602] = { return Api.Update.parse_updateChannelPinnedTopic($0) }
dict[422509539] = { return Api.Update.parse_updateChannelPinnedTopic($0) }
dict[-31881726] = { return Api.Update.parse_updateChannelPinnedTopics($0) }
dict[-366410403] = { return Api.Update.parse_updateChannelReadMessagesContents($0) }
dict[277713951] = { return Api.Update.parse_updateChannelTooLong($0) }
dict[-1937192669] = { return Api.Update.parse_updateChannelUserTyping($0) }

View File

@ -671,7 +671,8 @@ public extension Api {
case updateChannelMessageForwards(channelId: Int64, id: Int32, forwards: Int32)
case updateChannelMessageViews(channelId: Int64, id: Int32, views: Int32)
case updateChannelParticipant(flags: Int32, channelId: Int64, date: Int32, actorId: Int64, userId: Int64, prevParticipant: Api.ChannelParticipant?, newParticipant: Api.ChannelParticipant?, invite: Api.ExportedChatInvite?, qts: Int32)
case updateChannelPinnedTopic(flags: Int32, channelId: Int64, topicId: Int32?)
case updateChannelPinnedTopic(flags: Int32, channelId: Int64, topicId: Int32)
case updateChannelPinnedTopics(flags: Int32, channelId: Int64, order: [Int32]?)
case updateChannelReadMessagesContents(flags: Int32, channelId: Int64, topMsgId: Int32?, messages: [Int32])
case updateChannelTooLong(flags: Int32, channelId: Int64, pts: Int32?)
case updateChannelUserTyping(flags: Int32, channelId: Int64, topMsgId: Int32?, fromId: Api.Peer, action: Api.SendMessageAction)
@ -927,11 +928,23 @@ public extension Api {
break
case .updateChannelPinnedTopic(let flags, let channelId, let topicId):
if boxed {
buffer.appendInt32(-158027602)
buffer.appendInt32(422509539)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(channelId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topicId!, buffer: buffer, boxed: false)}
serializeInt32(topicId, buffer: buffer, boxed: false)
break
case .updateChannelPinnedTopics(let flags, let channelId, let order):
if boxed {
buffer.appendInt32(-31881726)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeInt64(channelId, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(order!.count))
for item in order! {
serializeInt32(item, buffer: buffer, boxed: false)
}}
break
case .updateChannelReadMessagesContents(let flags, let channelId, let topMsgId, let messages):
if boxed {
@ -1741,6 +1754,8 @@ public extension Api {
return ("updateChannelParticipant", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("date", String(describing: date)), ("actorId", String(describing: actorId)), ("userId", String(describing: userId)), ("prevParticipant", String(describing: prevParticipant)), ("newParticipant", String(describing: newParticipant)), ("invite", String(describing: invite)), ("qts", String(describing: qts))])
case .updateChannelPinnedTopic(let flags, let channelId, let topicId):
return ("updateChannelPinnedTopic", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("topicId", String(describing: topicId))])
case .updateChannelPinnedTopics(let flags, let channelId, let order):
return ("updateChannelPinnedTopics", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("order", String(describing: order))])
case .updateChannelReadMessagesContents(let flags, let channelId, let topMsgId, let messages):
return ("updateChannelReadMessagesContents", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("topMsgId", String(describing: topMsgId)), ("messages", String(describing: messages))])
case .updateChannelTooLong(let flags, let channelId, let pts):
@ -2307,12 +2322,31 @@ public extension Api {
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.Update.updateChannelPinnedTopic(flags: _1!, channelId: _2!, topicId: _3!)
}
else {
return nil
}
}
public static func parse_updateChannelPinnedTopics(_ reader: BufferReader) -> Update? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
var _3: [Int32]?
if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.Update.updateChannelPinnedTopic(flags: _1!, channelId: _2!, topicId: _3)
return Api.Update.updateChannelPinnedTopics(flags: _1!, channelId: _2!, order: _3)
}
else {
return nil

View File

@ -2443,6 +2443,27 @@ public extension Api.functions.channels {
})
}
}
public extension Api.functions.channels {
static func reorderPinnedForumTopics(flags: Int32, channel: Api.InputChannel, order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(693150095)
serializeInt32(flags, buffer: buffer, boxed: false)
channel.serialize(buffer, true)
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(order.count))
for item in order {
serializeInt32(item, buffer: buffer, boxed: false)
}
return (FunctionDescription(name: "channels.reorderPinnedForumTopics", parameters: [("flags", String(describing: flags)), ("channel", String(describing: channel)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
}
public extension Api.functions.channels {
static func reorderUsernames(channel: Api.InputChannel, order: [String]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View File

@ -179,6 +179,8 @@ public class ManagedAudioSessionControl {
}
public final class ManagedAudioSession {
public private(set) static var shared: ManagedAudioSession?
private var nextId: Int32 = 0
private let queue: Queue
private let hasLoudspeaker: Bool
@ -256,6 +258,8 @@ public final class ManagedAudioSession {
self.isHeadsetPluggedInValue = self.isHeadsetPluggedIn()
self.updateCurrentAudioRouteInfo()
}
ManagedAudioSession.shared = self
}
deinit {
@ -784,6 +788,61 @@ public final class ManagedAudioSession {
}
}
public func applyVoiceChatOutputModeInCurrentAudioSession(outputMode: AudioSessionOutputMode) {
managedAudioSessionLog("applyVoiceChatOutputModeInCurrentAudioSession \(outputMode)")
do {
var resetToBuiltin = false
switch outputMode {
case .system:
resetToBuiltin = true
case let .custom(output):
switch output {
case .builtin:
resetToBuiltin = true
case .speaker:
if let routes = AVAudioSession.sharedInstance().availableInputs {
for route in routes {
if route.portType == .builtInMic {
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
break
}
}
}
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
case .headphones:
break
case let .port(port):
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
if let routes = AVAudioSession.sharedInstance().availableInputs {
for route in routes {
if route.uid == port.uid {
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
break
}
}
}
}
case .speakerIfNoHeadphones:
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
}
if resetToBuiltin {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none)
if let routes = AVAudioSession.sharedInstance().availableInputs {
for route in routes {
if route.portType == .builtInMic {
let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route)
break
}
}
}
}
} catch let e {
managedAudioSessionLog("applyVoiceChatOutputModeInCurrentAudioSession error: \(e)")
}
}
private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws {
managedAudioSessionLog("ManagedAudioSession setup \(outputMode) for \(type)")
var resetToBuiltin = false

View File

@ -8,6 +8,7 @@ import TelegramCore
import SwiftSignalKit
import AppBundle
import AccountContext
import TelegramAudio
private let sharedProviderDelegate: AnyObject? = {
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
@ -107,6 +108,10 @@ public final class CallKitIntegration {
}
}
}
public func applyVoiceChatOutputMode(outputMode: AudioSessionOutputMode) {
(sharedProviderDelegate as? CallKitProviderDelegate)?.applyVoiceChatOutputMode(outputMode: outputMode)
}
}
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
@ -125,6 +130,9 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
private var setCallMuted: ((UUID, Bool) -> Void)?
private var audioSessionActivationChanged: ((Bool) -> Void)?
private var isAudioSessionActive: Bool = false
private var pendingVoiceChatOutputMode: AudioSessionOutputMode?
private let disposableSet = DisposableSet()
fileprivate var audioSessionActivePromise: ValuePromise<Bool>?
@ -163,7 +171,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
private func requestTransaction(_ transaction: CXTransaction, completion: ((Bool) -> Void)? = nil) {
self.callController.request(transaction) { error in
if let error = error {
print("Error requesting transaction: \(error)")
print("Error requesting transaction \(transaction): \(error)")
}
completion?(error == nil)
}
@ -238,6 +246,12 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
update.supportsDTMF = false
update.hasVideo = isVideo
do {
try AVAudioSession.sharedInstance().setMode(.default)
} catch let e {
print("AVAudioSession.sharedInstance().setMode(.default) error \(e)")
}
self.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in
completion?(error as NSError?)
})
@ -321,13 +335,28 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
}
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) {
print("provider didActivate default? \(audioSession === AVAudioSession.sharedInstance())")
self.isAudioSessionActive = true
self.audioSessionActivationChanged?(true)
self.audioSessionActivePromise?.set(true)
if let outputMode = self.pendingVoiceChatOutputMode {
self.pendingVoiceChatOutputMode = nil
ManagedAudioSession.shared?.applyVoiceChatOutputModeInCurrentAudioSession(outputMode: outputMode)
}
}
func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) {
self.isAudioSessionActive = false
self.audioSessionActivationChanged?(false)
self.audioSessionActivePromise?.set(false)
}
}
func applyVoiceChatOutputMode(outputMode: AudioSessionOutputMode) {
if self.isAudioSessionActive {
ManagedAudioSession.shared?.applyVoiceChatOutputModeInCurrentAudioSession(outputMode: outputMode)
} else {
self.pendingVoiceChatOutputMode = outputMode
}
}
}

View File

@ -413,6 +413,9 @@ public final class PresentationCallImpl: PresentationCall {
return
}
strongSelf.audioOutputStateValue = (availableOutputs, currentOutput)
if let currentOutput = currentOutput {
strongSelf.currentAudioOutputValue = currentOutput
}
var signal: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> = .single((availableOutputs, currentOutput))
if !didReceiveAudioOutputs {
@ -437,7 +440,7 @@ public final class PresentationCallImpl: PresentationCall {
let audioSessionActive: Signal<Bool, NoError>
if let callKitIntegration = strongSelf.callKitIntegration {
audioSessionActive = callKitIntegration.audioSessionActive
|> filter { $0 }
/*|> filter { $0 }
|> timeout(2.0, queue: Queue.mainQueue(), alternate: Signal { subscriber in
if let strongSelf = self, let _ = strongSelf.audioSessionControl {
//audioSessionControl.activate({ _ in })
@ -445,7 +448,7 @@ public final class PresentationCallImpl: PresentationCall {
subscriber.putNext(true)
subscriber.putCompletion()
return EmptyDisposable
})
})*/
} else {
audioSessionControl.activate({ _ in })
audioSessionActive = .single(true)
@ -534,9 +537,13 @@ public final class PresentationCallImpl: PresentationCall {
}
if let audioSessionControl = audioSessionControl, previous == nil || previousControl == nil {
if let callKitIntegration = self.callKitIntegration {
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
} else {
audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue))
audioSessionControl.setup(synchronous: true)
}
}
let mappedVideoState: PresentationCallState.VideoState
let mappedRemoteVideoState: PresentationCallState.RemoteVideoState
@ -1031,9 +1038,13 @@ public final class PresentationCallImpl: PresentationCall {
))
if let audioSessionControl = self.audioSessionControl {
if let callKitIntegration = self.callKitIntegration {
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
} else {
audioSessionControl.setOutputMode(.custom(output))
}
}
}
public func debugInfo() -> Signal<(String, String), NoError> {
return self.debugInfoValue.get()

View File

@ -1648,7 +1648,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
outgoingAudioBitrateKbit = Int32(value)
}
genericCallContext = .call(OngoingGroupCallContext(video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in
genericCallContext = .call(OngoingGroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in
let disposable = MetaDisposable()
Queue.mainQueue().async {
guard let strongSelf = self else {
@ -2966,7 +2966,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
self.hasScreencast = true
let screencastCallContext = OngoingGroupCallContext(video: self.screencastCapturer, requestMediaChannelDescriptions: { _, _ in EmptyDisposable }, rejoinNeeded: { }, outgoingAudioBitrateKbit: nil, videoContentType: .screencast, enableNoiseSuppression: false, disableAudioInput: true, preferX264: false, logPath: "")
let screencastCallContext = OngoingGroupCallContext(audioSessionActive: .single(true), video: self.screencastCapturer, requestMediaChannelDescriptions: { _, _ in EmptyDisposable }, rejoinNeeded: { }, outgoingAudioBitrateKbit: nil, videoContentType: .screencast, enableNoiseSuppression: false, disableAudioInput: true, preferX264: false, logPath: "")
self.screencastCallContext = screencastCallContext
self.screencastJoinDisposable.set((screencastCallContext.joinPayload

View File

@ -93,7 +93,8 @@ enum AccountStateMutationOperation {
case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32)
case AddPeerInputActivity(chatPeerId: PeerActivitySpace, peerId: PeerId?, activity: PeerInputActivity?)
case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation)
case UpdatePinnedTopic(peerId: PeerId, threadId: Int64?)
case UpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool)
case UpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64])
case ReadMessageContents((PeerId?, [Int32]))
case UpdateMessageImpressionCount(MessageId, Int32)
case UpdateMessageForwardsCount(MessageId, Int32)
@ -475,8 +476,12 @@ struct AccountMutableState {
self.addOperation(.UpdatePinnedItemIds(groupId, operation))
}
mutating func addUpdatePinnedTopic(peerId: PeerId, threadId: Int64?) {
self.addOperation(.UpdatePinnedTopic(peerId: peerId, threadId: threadId))
mutating func addUpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool) {
self.addOperation(.UpdatePinnedTopic(peerId: peerId, threadId: threadId, isPinned: isPinned))
}
mutating func addUpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64]) {
self.addOperation(.UpdatePinnedTopicOrder(peerId: peerId, threadIds: threadIds))
}
mutating func addReadMessagesContents(_ peerIdsAndMessageIds: (PeerId?, [Int32])) {
@ -545,7 +550,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, .UpdatePinnedTopic, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic:
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic:
break
case let .AddMessages(messages, location):
for message in messages {

View File

@ -367,21 +367,16 @@ func _internal_setForumChannelTopicClosed(account: Account, id: EnginePeer.Id, t
public enum SetForumChannelTopicPinnedError {
case generic
case limitReached(Int)
}
func _internal_setForumChannelTopicPinned(account: Account, id: EnginePeer.Id, threadId: Int64, isPinned: Bool) -> Signal<Never, SetForumChannelTopicPinnedError> {
func _internal_setForumChannelPinnedTopics(account: Account, id: EnginePeer.Id, threadIds: [Int64]) -> Signal<Never, SetForumChannelTopicPinnedError> {
return account.postbox.transaction { transaction -> Api.InputChannel? in
guard let inputChannel = transaction.getPeer(id).flatMap(apiInputChannel) else {
return nil
}
if isPinned {
transaction.setPeerPinnedThreads(peerId: id, threadIds: [threadId])
} else {
if transaction.getPeerPinnedThreads(peerId: id).contains(threadId) {
transaction.setPeerPinnedThreads(peerId: id, threadIds: [])
}
}
transaction.setPeerPinnedThreads(peerId: id, threadIds: threadIds)
return inputChannel
}
@ -390,13 +385,11 @@ func _internal_setForumChannelTopicPinned(account: Account, id: EnginePeer.Id, t
guard let inputChannel = inputChannel else {
return .fail(.generic)
}
var flags: Int32 = 0
flags |= (1 << 2)
return account.network.request(Api.functions.channels.updatePinnedForumTopic(
return account.network.request(Api.functions.channels.reorderPinnedForumTopics(
flags: 1 << 0,
channel: inputChannel,
topicId: Int32(clamping: threadId),
pinned: isPinned ? .boolTrue : .boolFalse
order: threadIds.map(Int32.init(clamping:))
))
|> mapError { _ -> SetForumChannelTopicPinnedError in
return .generic

View File

@ -114,6 +114,11 @@ private func peerIdsRequiringLocalChatStateFromUpdates(_ updates: [Api.Update])
case let .updateChannelTooLong(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
peerIds.insert(peerId)
case let .updateChannelPinnedTopics(_, channelId, order):
if order == nil {
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
peerIds.insert(peerId)
}
case let .updateFolderPeers(folderPeers, _, _):
for peer in folderPeers {
switch peer {
@ -340,6 +345,11 @@ private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.upda
case let .updateChannelTooLong(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
peerIds.insert(peerId)
case let .updateChannelPinnedTopics(_, channelId, order):
if order == nil {
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
peerIds.insert(peerId)
}
default:
break
}
@ -362,6 +372,11 @@ private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.upda
case let .updateChannelTooLong(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
peerIds.insert(peerId)
case let .updateChannelPinnedTopics(_, channelId, order):
if order == nil {
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
peerIds.insert(peerId)
}
default:
break
}
@ -725,6 +740,20 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
} else {
updatesByChannel[peerId]!.append(update)
}
case let .updateChannelPinnedTopic(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
if updatesByChannel[peerId] == nil {
updatesByChannel[peerId] = [update]
} else {
updatesByChannel[peerId]!.append(update)
}
case let .updateChannelPinnedTopics(_, channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
if updatesByChannel[peerId] == nil {
updatesByChannel[peerId] = [update]
} else {
updatesByChannel[peerId]!.append(update)
}
case let .updateDeleteChannelMessages(channelId, _, _, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
if updatesByChannel[peerId] == nil {
@ -860,6 +889,15 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
channelsToPoll.insert(peerId)
}
}
case let .updateChannelPinnedTopics(_, channelId, order):
if let order = order {
updatedState.addUpdatePinnedTopicOrder(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadIds: order.map(Int64.init))
} else {
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
if !channelsToPoll.contains(peerId) {
channelsToPoll.insert(peerId)
}
}
case let .updateDeleteChannelMessages(channelId, messages, pts: pts, ptsCount):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId))
if let previousState = updatedState.channelStates[peerId] {
@ -1375,8 +1413,9 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox:
} else {
updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .sync)
}
case let .updateChannelPinnedTopic(_, channelId, topicId):
updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: topicId.flatMap(Int64.init))
case let .updateChannelPinnedTopic(flags, channelId, topicId):
let isPinned = (flags & (1 << 0)) != 0
updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: Int64(topicId), isPinned: isPinned)
case let .updateReadMessagesContents(messages, _, _):
updatedState.addReadMessagesContents((nil, messages))
case let .updateChannelReadMessagesContents(_, channelId, topMsgId, messages):
@ -2847,7 +2886,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, .UpdatePinnedTopic, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic:
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, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
}
@ -3757,12 +3796,18 @@ func replayFinalState(
case .sync:
addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId)
}
case let .UpdatePinnedTopic(peerId, threadId):
if let threadId = threadId {
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: [threadId])
} else {
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: [])
case let .UpdatePinnedTopic(peerId, threadId, isPinned):
var currentThreadIds = transaction.getPeerPinnedThreads(peerId: peerId)
if isPinned {
if !currentThreadIds.contains(threadId) {
currentThreadIds.insert(threadId, at: 0)
}
} else {
currentThreadIds.removeAll(where: { $0 == threadId })
}
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: currentThreadIds)
case let .UpdatePinnedTopicOrder(peerId, threadIds):
transaction.setPeerPinnedThreads(peerId: peerId, threadIds: threadIds)
case let .ReadMessageContents(peerIdAndMessageIds):
let (peerId, messageIds) = peerIdAndMessageIds

View File

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

View File

@ -858,8 +858,34 @@ public extension TelegramEngine {
|> ignoreValues
}
public func setForumChannelTopicPinned(id: EnginePeer.Id, threadId: Int64, isPinned: Bool) -> Signal<Never, SetForumChannelTopicPinnedError> {
return _internal_setForumChannelTopicPinned(account: self.account, id: id, threadId: threadId, isPinned: isPinned)
public func toggleForumChannelTopicPinned(id: EnginePeer.Id, threadId: Int64) -> Signal<Never, SetForumChannelTopicPinnedError> {
return self.account.postbox.transaction { transaction -> [Int64] in
return transaction.getPeerPinnedThreads(peerId: id)
}
|> castError(SetForumChannelTopicPinnedError.self)
|> mapToSignal { threadIds -> Signal<Never, SetForumChannelTopicPinnedError> in
var threadIds = threadIds
if threadIds.contains(threadId) {
threadIds.removeAll(where: { $0 == threadId })
} else {
if threadIds.count + 1 > 5 {
return .fail(.limitReached(5))
}
threadIds.insert(threadId, at: 0)
}
return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds)
}
}
public func getForumChannelPinnedTopics(id: EnginePeer.Id) -> Signal<[Int64], NoError> {
return self.account.postbox.transaction { transcation -> [Int64] in
return transcation.getPeerPinnedThreads(peerId: id)
}
}
public func setForumChannelPinnedTopics(id: EnginePeer.Id, threadIds: [Int64]) -> Signal<Never, SetForumChannelTopicPinnedError> {
return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds)
}
public func forumChannelTopicNotificationExceptions(id: EnginePeer.Id) -> Signal<[EngineMessageHistoryThread.NotificationException], NoError> {

View File

@ -30,7 +30,7 @@ public extension Peer {
if let restrictionInfo = restrictionInfo {
for rule in restrictionInfo.rules {
if rule.platform == "all" || rule.platform == platform {
if rule.platform == "all" || rule.platform == platform || contentSettings.addContentRestrictionReasons.contains(rule.platform) {
if !contentSettings.ignoreContentRestrictionReasons.contains(rule.reason) {
return rule.text
}

View File

@ -6132,12 +6132,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
var buttonKeyboardMessage = combinedInitialData.buttonKeyboardMessage
if let buttonKeyboardMessageValue = buttonKeyboardMessage, buttonKeyboardMessageValue.isRestricted(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with({ $0 })) {
buttonKeyboardMessage = nil
}
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { updated in
var updated = updated
updated = updated.updatedInterfaceState({ _ in return interfaceState })
updated = updated.updatedKeyboardButtonsMessage(combinedInitialData.buttonKeyboardMessage)
updated = updated.updatedKeyboardButtonsMessage(buttonKeyboardMessage)
updated = updated.updatedPinnedMessageId(pinnedMessageId)
updated = updated.updatedPinnedMessage(pinnedMessage)
updated = updated.updatedPeerIsBlocked(peerIsBlocked)

View File

@ -1396,7 +1396,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
forceUpdateAll = true
}
let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: updateAllOnEachVersion || forceUpdateAll)
var keyboardButtonsMessage = view.topTaggedMessages.first
if let keyboardButtonsMessageValue = keyboardButtonsMessage, keyboardButtonsMessageValue.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with({ $0 })) {
keyboardButtonsMessage = nil
}
let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: keyboardButtonsMessage, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: updateAllOnEachVersion || forceUpdateAll)
var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, transition: rawTransition)
if disableAnimations {

View File

@ -181,17 +181,6 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
}
}
}
} else {
if chatPresentationInterfaceState.interfaceState.replyMessageId == nil {
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
return (currentPanel, nil)
} else {
let panel = ChatRestrictedInputPanelNode()
panel.context = context
panel.interfaceInteraction = interfaceInteraction
return (panel, nil)
}
}
}
}
@ -248,6 +237,22 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
}
}
}
if channel.flags.contains(.isForum) {
if let _ = chatPresentationInterfaceState.threadData {
} else {
if chatPresentationInterfaceState.interfaceState.replyMessageId == nil {
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
return (currentPanel, nil)
} else {
let panel = ChatRestrictedInputPanelNode()
panel.context = context
panel.interfaceInteraction = interfaceInteraction
return (panel, nil)
}
}
}
}
} else if let group = peer as? TelegramGroup {
switch group.membership {
case .Removed, .Left:

View File

@ -1167,7 +1167,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
} else if let threadId = item.message.threadId, Int64(replyAttribute.messageId.id) == threadId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
} else {
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
presentationData: item.presentationData,

View File

@ -1418,7 +1418,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
}
} else if let attribute = attribute as? ReplyMessageAttribute {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == attribute.messageId {
} else if let threadId = firstMessage.threadId, Int64(attribute.messageId.id) == threadId, let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
} else {
replyMessage = firstMessage.associatedMessages[attribute.messageId]
}

View File

@ -207,7 +207,7 @@ final class ChatMessageAccessibilityData {
if let chatPeer = message.peers[item.message.id.peerId] {
let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
let (_, _, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
let (_, _, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId)
var text = messageText

View File

@ -97,8 +97,6 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
let previousMediaReference = maybeNode?.previousMediaReference
return { arguments in
//presentationData, strings, context, type, message, parentMessage, constrainedSize
let fontSize = floor(arguments.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0)
let titleFont = Font.medium(fontSize)
let textFont = Font.regular(fontSize)
@ -114,7 +112,12 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
}
}
let (textString, isMedia, isText) = descriptionStringForMessage(contentSettings: arguments.context.currentContentSettings.with { $0 }, message: EngineMessage(arguments.message), strings: arguments.strings, nameDisplayOrder: arguments.presentationData.nameDisplayOrder, dateTimeFormat: arguments.presentationData.dateTimeFormat, accountPeerId: arguments.context.account.peerId)
var (textString, isMedia, isText) = descriptionStringForMessage(contentSettings: arguments.context.currentContentSettings.with { $0 }, message: EngineMessage(arguments.message), strings: arguments.strings, nameDisplayOrder: arguments.presentationData.nameDisplayOrder, dateTimeFormat: arguments.presentationData.dateTimeFormat, accountPeerId: arguments.context.account.peerId)
if let threadId = arguments.parentMessage.threadId, Int64(arguments.message.id.id) == threadId, let channel = arguments.parentMessage.peers[arguments.parentMessage.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), let threadInfo = arguments.parentMessage.associatedThreadInfo {
titleString = "\(threadInfo.title)"
textString = NSAttributedString()
}
let placeholderColor: UIColor = arguments.message.effectivelyIncoming(arguments.context.account.peerId) ? arguments.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : arguments.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor
let titleColor: UIColor

View File

@ -611,7 +611,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] {
if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId {
} else if let threadId = item.message.threadId, Int64(replyAttribute.messageId.id) == threadId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) {
} else {
replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments(
presentationData: item.presentationData,

View File

@ -621,6 +621,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
if let components = URLComponents(string: "/?" + query) {
var channelId: Int64?
var postId: Int32?
var threadId: Int64?
if let queryItems = components.queryItems {
for queryItem in queryItems {
if let value = queryItem.value {
@ -628,13 +629,23 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
channelId = Int64(value)
} else if queryItem.name == "post" {
postId = Int32(value)
} else if queryItem.name == "thread" {
threadId = Int64(value)
}
}
}
}
if let channelId = channelId, let postId = postId {
if let channelId = channelId {
if let postId = postId {
if let threadId = threadId {
convertedUrl = "https://t.me/c/\(channelId)/\(threadId)/\(postId)"
} else {
convertedUrl = "https://t.me/c/\(channelId)/\(postId)"
}
} else if let threadId = threadId {
convertedUrl = "https://t.me/c/\(channelId)/\(threadId)"
}
}
}
}
@ -652,6 +663,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
var attach: String?
var startAttach: String?
var choose: String?
var threadId: Int64?
if let queryItems = components.queryItems {
for queryItem in queryItems {
if let value = queryItem.value {
@ -677,6 +689,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
startAttach = value
} else if queryItem.name == "choose" {
choose = value
} else if queryItem.name == "thread" {
threadId = Int64(value)
}
} else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
voiceChat = ""
@ -694,9 +708,16 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
convertedUrl = "https://t.me/+\(phone)"
} else if let domain = domain {
var result = "https://t.me/\(domain)"
if let threadId = threadId {
result += "/\(threadId)"
if let post = post, let postValue = Int(post) {
result += "/\(postValue)"
}
} else {
if let post = post, let postValue = Int(post) {
result += "/\(postValue)"
}
}
if let start = start {
result += "?start=\(start)"
} else if let startGroup = startGroup {

View File

@ -416,7 +416,9 @@ public final class OngoingGroupCallContext {
private let broadcastPartsSource = Atomic<BroadcastPartSource?>(value: nil)
init(queue: Queue, inputDeviceId: String, outputDeviceId: String, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set<UInt32>, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) {
private let audioSessionActiveDisposable = MetaDisposable()
init(queue: Queue, inputDeviceId: String, outputDeviceId: String, audioSessionActive: Signal<Bool, NoError>, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set<UInt32>, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) {
self.queue = queue
var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)?
@ -571,9 +573,18 @@ public final class OngoingGroupCallContext {
strongSelf.joinPayload.set(.single((payload, ssrc)))
}
})
self.audioSessionActiveDisposable.set((audioSessionActive
|> deliverOn(queue)).start(next: { [weak self] isActive in
guard let self else {
return
}
self.context.setManualAudioSessionIsActive(isActive)
}))
}
deinit {
self.audioSessionActiveDisposable.dispose()
}
func setJoinResponse(payload: String) {
@ -936,10 +947,10 @@ public final class OngoingGroupCallContext {
}
}
public init(inputDeviceId: String = "", outputDeviceId: String = "", video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set<UInt32>, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) {
public init(inputDeviceId: String = "", outputDeviceId: String = "", audioSessionActive: Signal<Bool, NoError>, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set<UInt32>, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) {
let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: {
return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, video: video, requestMediaChannelDescriptions: requestMediaChannelDescriptions, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, videoContentType: videoContentType, enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, preferX264: preferX264, logPath: logPath)
return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, audioSessionActive: audioSessionActive, video: video, requestMediaChannelDescriptions: requestMediaChannelDescriptions, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, videoContentType: videoContentType, enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, preferX264: preferX264, logPath: logPath)
})
}

View File

@ -326,6 +326,7 @@ private protocol OngoingCallThreadLocalContextProtocol: AnyObject {
func nativeVersion() -> String
func nativeGetDerivedState() -> Data
func addExternalAudioData(data: Data)
func nativeSetIsAudioSessionActive(isActive: Bool)
}
private final class OngoingCallThreadLocalContextHolder {
@ -381,6 +382,9 @@ extension OngoingCallThreadLocalContext: OngoingCallThreadLocalContextProtocol {
func addExternalAudioData(data: Data) {
}
func nativeSetIsAudioSessionActive(isActive: Bool) {
}
}
public final class OngoingCallVideoCapturer {
@ -573,6 +577,10 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt
func addExternalAudioData(data: Data) {
self.addExternalAudioData(data)
}
func nativeSetIsAudioSessionActive(isActive: Bool) {
self.setManualAudioSessionIsActive(isActive)
}
}
private extension OngoingCallContextState.State {
@ -726,6 +734,7 @@ public final class OngoingCallContext {
}
private let audioSessionDisposable = MetaDisposable()
private let audioSessionActiveDisposable = MetaDisposable()
private var networkTypeDisposable: Disposable?
public static var maxLayer: Int32 {
@ -886,7 +895,7 @@ public final class OngoingCallContext {
callSessionManager.sendSignalingData(internalId: internalId, data: data)
}
}
}, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec, audioInputDeviceId: "")
}, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec, audioInputDeviceId: "", useManualAudioSessionControl: true)
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in
@ -950,6 +959,16 @@ public final class OngoingCallContext {
self?.audioLevelPromise.set(.single(level))
}
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
@ -1010,6 +1029,7 @@ public final class OngoingCallContext {
}
self.audioSessionDisposable.dispose()
self.audioSessionActiveDisposable.dispose()
self.networkTypeDisposable?.dispose()
}
@ -1256,6 +1276,8 @@ private final class CallSignalingConnectionImpl: CallSignalingConnection {
}
func start() {
OngoingCallThreadLocalContextWebrtc.logMessage("CallSignaling: Connecting...")
self.connection.start(queue: self.queue.queue)
self.receivePacketHeader()
}
@ -1399,48 +1421,91 @@ private final class CallSignalingConnectionImpl: CallSignalingConnection {
}
private final class CallSignalingConnectionManager {
private final class ConnectionContext {
let connection: CallSignalingConnection
let host: String
let port: UInt16
init(connection: CallSignalingConnection, host: String, port: UInt16) {
self.connection = connection
self.host = host
self.port = port
}
}
private let queue: Queue
private let peerTag: Data
private let dataReceived: (Data) -> Void
private var isRunning: Bool = false
private var nextConnectionId: Int = 0
private var connections: [Int: CallSignalingConnection] = [:]
private var connections: [Int: ConnectionContext] = [:]
init(queue: Queue, peerTag: Data, servers: [OngoingCallConnectionDescriptionWebrtc], dataReceived: @escaping (Data) -> Void) {
self.queue = queue
self.peerTag = peerTag
self.dataReceived = dataReceived
for server in servers {
if server.hasTcp {
let id = self.nextConnectionId
self.nextConnectionId += 1
if #available(iOS 12.0, *) {
let connection = CallSignalingConnectionImpl(queue: queue, host: server.ip, port: UInt16(server.port), peerTag: peerTag, dataReceived: { data in
dataReceived(data)
}, isClosed: { [weak self] in
guard let strongSelf = self else {
return
}
let _ = strongSelf
})
connections[id] = connection
}
self.spawnConnection(host: server.ip, port: UInt16(server.port))
}
}
}
func start() {
if self.isRunning {
return
}
self.isRunning = true
for (_, connection) in self.connections {
connection.start()
connection.connection.start()
}
}
func stop() {
if !self.isRunning {
return
}
self.isRunning = false
for (_, connection) in self.connections {
connection.stop()
connection.connection.stop()
}
}
func send(payloadData: Data) {
for (_, connection) in self.connections {
connection.send(payloadData: payloadData)
connection.connection.send(payloadData: payloadData)
}
}
private func spawnConnection(host: String, port: UInt16) {
let id = self.nextConnectionId
self.nextConnectionId += 1
if #available(iOS 12.0, *) {
let dataReceived = self.dataReceived
let connection = CallSignalingConnectionImpl(queue: queue, host: host, port: port, peerTag: self.peerTag, dataReceived: { data in
dataReceived(data)
}, isClosed: { [weak self] in
guard let self else {
return
}
self.handleConnectionFailed(id: id)
})
self.connections[id] = ConnectionContext(connection: connection, host: host, port: port)
if self.isRunning {
connection.start()
}
}
}
private func handleConnectionFailed(id: Int) {
if let connection = self.connections.removeValue(forKey: id) {
connection.connection.stop()
self.spawnConnection(host: connection.host, port: connection.port)
}
}
}

View File

@ -206,7 +206,24 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) {
@property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t);
@property (nonatomic, copy) void (^ _Nullable audioLevelUpdated)(float);
- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing connections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)connections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P allowTCP:(BOOL)allowTCP enableStunMarking:(BOOL)enableStunMarking logPath:(NSString * _Nonnull)logPath statsLogPath:(NSString * _Nonnull)statsLogPath sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec audioInputDeviceId: (NSString * _Nonnull)audioInputDeviceId;
- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue
proxy:(VoipProxyServerWebrtc * _Nullable)proxy
networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving
derivedState:(NSData * _Nonnull)derivedState
key:(NSData * _Nonnull)key
isOutgoing:(bool)isOutgoing
connections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)connections maxLayer:(int32_t)maxLayer
allowP2P:(BOOL)allowP2P
allowTCP:(BOOL)allowTCP
enableStunMarking:(BOOL)enableStunMarking
logPath:(NSString * _Nonnull)logPath
statsLogPath:(NSString * _Nonnull)statsLogPath
sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer
preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec
audioInputDeviceId:(NSString * _Nonnull)audioInputDeviceId
useManualAudioSessionControl:(bool)useManualAudioSessionControl;
- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive;
- (void)beginTermination;
- (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion;
@ -360,6 +377,8 @@ typedef NS_ENUM(int32_t, OngoingGroupCallRequestedVideoQuality) {
- (void)stop;
- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive;
- (void)setConnectionMode:(OngoingCallConnectionMode)connectionMode keepBroadcastConnectedIfWasEnabled:(bool)keepBroadcastConnectedIfWasEnabled isUnifiedBroadcast:(bool)isUnifiedBroadcast;
- (void)emitJoinPayload:(void (^ _Nonnull)(NSString * _Nonnull, uint32_t))completion;

View File

@ -28,6 +28,9 @@
#include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h"
#include "platform/darwin/iOS/RTCAudioSession.h"
#include "platform/darwin/iOS/RTCAudioSessionConfiguration.h"
#endif
#import "group/GroupInstanceImpl.h"
@ -705,6 +708,8 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls:
id<OngoingCallThreadLocalContextQueueWebrtc> _queue;
int32_t _contextId;
bool _useManualAudioSessionControl;
OngoingCallNetworkTypeWebrtc _networkType;
NSTimeInterval _callReceiveTimeout;
NSTimeInterval _callRingTimeout;
@ -843,7 +848,22 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
}
}
- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing connections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)connections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P allowTCP:(BOOL)allowTCP enableStunMarking:(BOOL)enableStunMarking logPath:(NSString * _Nonnull)logPath statsLogPath:(NSString * _Nonnull)statsLogPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec audioInputDeviceId: (NSString * _Nonnull)audioInputDeviceId {
- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id<OngoingCallThreadLocalContextQueueWebrtc> _Nonnull)queue
proxy:(VoipProxyServerWebrtc * _Nullable)proxy
networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving
derivedState:(NSData * _Nonnull)derivedState
key:(NSData * _Nonnull)key
isOutgoing:(bool)isOutgoing
connections:(NSArray<OngoingCallConnectionDescriptionWebrtc *> * _Nonnull)connections maxLayer:(int32_t)maxLayer
allowP2P:(BOOL)allowP2P
allowTCP:(BOOL)allowTCP
enableStunMarking:(BOOL)enableStunMarking
logPath:(NSString * _Nonnull)logPath
statsLogPath:(NSString * _Nonnull)statsLogPath
sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer
preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec
audioInputDeviceId:(NSString * _Nonnull)audioInputDeviceId
useManualAudioSessionControl:(bool)useManualAudioSessionControl {
self = [super init];
if (self != nil) {
_version = version;
@ -852,6 +872,25 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
assert([[OngoingCallThreadLocalContextWebrtc versionsWithIncludeReference:true] containsObject:version]);
_useManualAudioSessionControl = useManualAudioSessionControl;
[RTCAudioSession sharedInstance].useManualAudio = true;
#ifdef WEBRTC_IOS
RTCAudioSessionConfiguration *sharedConfiguration = [RTCAudioSessionConfiguration webRTCConfiguration];
if (useManualAudioSessionControl) {
sharedConfiguration.mode = AVAudioSessionModeDefault;
} else {
sharedConfiguration.mode = AVAudioSessionModeVoiceChat;
}
sharedConfiguration.categoryOptions |= AVAudioSessionCategoryOptionMixWithOthers;
sharedConfiguration.outputNumberOfChannels = 1;
[RTCAudioSessionConfiguration setWebRTCConfiguration:sharedConfiguration];
/*[RTCAudioSession sharedInstance].useManualAudio = true;
[[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]];
[RTCAudioSession sharedInstance].isAudioEnabled = true;*/
#endif
_callReceiveTimeout = 20.0;
_callRingTimeout = 90.0;
_callConnectTimeout = 30.0;
@ -1094,6 +1133,17 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
- (void)beginTermination {
}
- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive {
if (_useManualAudioSessionControl) {
if (isAudioSessionActive) {
[[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]];
} else {
[[RTCAudioSession sharedInstance] audioSessionDidDeactivate:[AVAudioSession sharedInstance]];
}
[RTCAudioSession sharedInstance].isAudioEnabled = isAudioSessionActive;
}
}
+ (void)stopWithTerminationResult:(OngoingCallThreadLocalContextWebrtcTerminationResult *)terminationResult completion:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
if (completion) {
if (terminationResult) {
@ -1429,6 +1479,22 @@ private:
}
}
#ifdef WEBRTC_IOS
RTCAudioSessionConfiguration *sharedConfiguration = [RTCAudioSessionConfiguration webRTCConfiguration];
sharedConfiguration.mode = AVAudioSessionModeVoiceChat;
sharedConfiguration.categoryOptions |= AVAudioSessionCategoryOptionMixWithOthers;
if (disableAudioInput) {
sharedConfiguration.outputNumberOfChannels = 2;
} else {
sharedConfiguration.outputNumberOfChannels = 1;
}
[RTCAudioSessionConfiguration setWebRTCConfiguration:sharedConfiguration];
/*[RTCAudioSession sharedInstance].useManualAudio = true;
[[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]];
[RTCAudioSession sharedInstance].isAudioEnabled = true;*/
#endif
std::vector<tgcalls::VideoCodecName> videoCodecPreferences;
int minOutgoingVideoBitrateKbit = 500;
@ -1612,6 +1678,15 @@ private:
}
}
- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive {
if (isAudioSessionActive) {
[[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]];
} else {
[[RTCAudioSession sharedInstance] audioSessionDidDeactivate:[AVAudioSession sharedInstance]];
}
[RTCAudioSession sharedInstance].isAudioEnabled = isAudioSessionActive;
}
- (void)setConnectionMode:(OngoingCallConnectionMode)connectionMode keepBroadcastConnectedIfWasEnabled:(bool)keepBroadcastConnectedIfWasEnabled isUnifiedBroadcast:(bool)isUnifiedBroadcast {
if (_instance) {
tgcalls::GroupConnectionMode mappedConnectionMode;

@ -1 +1 @@
Subproject commit 53bb1711ae0b3810d34edb1c81982b18d70c5506
Subproject commit 0aa4b1277fd018e56bf194d72b5405e397c6918b