mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Conference
This commit is contained in:
parent
15e138e492
commit
5f01a83214
@ -15,216 +15,6 @@ import AccountContext
|
|||||||
import DeviceProximity
|
import DeviceProximity
|
||||||
import PhoneNumberFormat
|
import PhoneNumberFormat
|
||||||
|
|
||||||
public final class SharedCallAudioContext {
|
|
||||||
let audioDevice: OngoingCallContext.AudioDevice?
|
|
||||||
let callKitIntegration: CallKitIntegration?
|
|
||||||
|
|
||||||
private let defaultToSpeaker: Bool
|
|
||||||
|
|
||||||
private var audioSessionDisposable: Disposable?
|
|
||||||
private var audioSessionShouldBeActiveDisposable: Disposable?
|
|
||||||
private var isAudioSessionActiveDisposable: Disposable?
|
|
||||||
private var audioOutputStateDisposable: Disposable?
|
|
||||||
|
|
||||||
private(set) var audioSessionControl: ManagedAudioSessionControl?
|
|
||||||
|
|
||||||
private let isAudioSessionActivePromise = Promise<Bool>(false)
|
|
||||||
private var isAudioSessionActive: Signal<Bool, NoError> {
|
|
||||||
return self.isAudioSessionActivePromise.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
private let audioOutputStatePromise = Promise<([AudioSessionOutput], AudioSessionOutput?)>(([], nil))
|
|
||||||
private var audioOutputStateValue: ([AudioSessionOutput], AudioSessionOutput?) = ([], nil)
|
|
||||||
public private(set) var currentAudioOutputValue: AudioSessionOutput = .builtin
|
|
||||||
private var didSetCurrentAudioOutputValue: Bool = false
|
|
||||||
var audioOutputState: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> {
|
|
||||||
return self.audioOutputStatePromise.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
private let audioSessionShouldBeActive = Promise<Bool>(true)
|
|
||||||
private var initialSetupTimer: Foundation.Timer?
|
|
||||||
|
|
||||||
init(audioSession: ManagedAudioSession, callKitIntegration: CallKitIntegration?, defaultToSpeaker: Bool = false) {
|
|
||||||
self.callKitIntegration = callKitIntegration
|
|
||||||
self.audioDevice = OngoingCallContext.AudioDevice.create(enableSystemMute: false)
|
|
||||||
self.defaultToSpeaker = defaultToSpeaker
|
|
||||||
|
|
||||||
if defaultToSpeaker {
|
|
||||||
self.didSetCurrentAudioOutputValue = true
|
|
||||||
self.currentAudioOutputValue = .speaker
|
|
||||||
}
|
|
||||||
|
|
||||||
var didReceiveAudioOutputs = false
|
|
||||||
self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, manualActivate: { [weak self] control in
|
|
||||||
Queue.mainQueue().async {
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let previousControl = self.audioSessionControl
|
|
||||||
self.audioSessionControl = control
|
|
||||||
|
|
||||||
if previousControl == nil, let audioSessionControl = self.audioSessionControl {
|
|
||||||
if let callKitIntegration = self.callKitIntegration {
|
|
||||||
if self.didSetCurrentAudioOutputValue {
|
|
||||||
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue))
|
|
||||||
audioSessionControl.setup(synchronous: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
let audioSessionActive: Signal<Bool, NoError>
|
|
||||||
if let callKitIntegration = self.callKitIntegration {
|
|
||||||
audioSessionActive = callKitIntegration.audioSessionActive
|
|
||||||
} else {
|
|
||||||
audioSessionControl.activate({ _ in })
|
|
||||||
audioSessionActive = .single(true)
|
|
||||||
}
|
|
||||||
self.isAudioSessionActivePromise.set(audioSessionActive)
|
|
||||||
|
|
||||||
self.initialSetupTimer?.invalidate()
|
|
||||||
self.initialSetupTimer = Foundation.Timer(timeInterval: 0.5, repeats: false, block: { [weak self] _ in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.defaultToSpeaker, let audioSessionControl = self.audioSessionControl {
|
|
||||||
self.currentAudioOutputValue = .speaker
|
|
||||||
self.didSetCurrentAudioOutputValue = true
|
|
||||||
|
|
||||||
if let callKitIntegration = self.callKitIntegration {
|
|
||||||
if self.didSetCurrentAudioOutputValue {
|
|
||||||
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue))
|
|
||||||
audioSessionControl.setup(synchronous: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, deactivate: { [weak self] _ in
|
|
||||||
return Signal { subscriber in
|
|
||||||
Queue.mainQueue().async {
|
|
||||||
if let self {
|
|
||||||
self.isAudioSessionActivePromise.set(.single(false))
|
|
||||||
self.audioSessionControl = nil
|
|
||||||
}
|
|
||||||
subscriber.putCompletion()
|
|
||||||
}
|
|
||||||
return EmptyDisposable
|
|
||||||
}
|
|
||||||
}, availableOutputsChanged: { [weak self] availableOutputs, currentOutput in
|
|
||||||
Queue.mainQueue().async {
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.audioOutputStateValue = (availableOutputs, currentOutput)
|
|
||||||
if let currentOutput = currentOutput {
|
|
||||||
self.currentAudioOutputValue = currentOutput
|
|
||||||
self.didSetCurrentAudioOutputValue = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var signal: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> = .single((availableOutputs, currentOutput))
|
|
||||||
if !didReceiveAudioOutputs {
|
|
||||||
didReceiveAudioOutputs = true
|
|
||||||
if currentOutput == .speaker {
|
|
||||||
signal = .single((availableOutputs, .builtin))
|
|
||||||
|> then(
|
|
||||||
signal
|
|
||||||
|> delay(1.0, queue: Queue.mainQueue())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.audioOutputStatePromise.set(signal)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.audioSessionShouldBeActive.set(.single(true))
|
|
||||||
self.audioSessionShouldBeActiveDisposable = (self.audioSessionShouldBeActive.get()
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if value {
|
|
||||||
if let audioSessionControl = self.audioSessionControl {
|
|
||||||
let audioSessionActive: Signal<Bool, NoError>
|
|
||||||
if let callKitIntegration = self.callKitIntegration {
|
|
||||||
audioSessionActive = callKitIntegration.audioSessionActive
|
|
||||||
} else {
|
|
||||||
audioSessionControl.activate({ _ in })
|
|
||||||
audioSessionActive = .single(true)
|
|
||||||
}
|
|
||||||
self.isAudioSessionActivePromise.set(audioSessionActive)
|
|
||||||
} else {
|
|
||||||
self.isAudioSessionActivePromise.set(.single(false))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.isAudioSessionActivePromise.set(.single(false))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.isAudioSessionActiveDisposable = (self.isAudioSessionActive
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.audioDevice?.setIsAudioSessionActive(value)
|
|
||||||
})
|
|
||||||
|
|
||||||
self.audioOutputStateDisposable = (self.audioOutputStatePromise.get()
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.audioOutputStateValue = value
|
|
||||||
if let currentOutput = value.1 {
|
|
||||||
self.currentAudioOutputValue = currentOutput
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
self.audioSessionDisposable?.dispose()
|
|
||||||
self.audioSessionShouldBeActiveDisposable?.dispose()
|
|
||||||
self.isAudioSessionActiveDisposable?.dispose()
|
|
||||||
self.audioOutputStateDisposable?.dispose()
|
|
||||||
self.initialSetupTimer?.invalidate()
|
|
||||||
}
|
|
||||||
|
|
||||||
func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
|
||||||
self.initialSetupTimer?.invalidate()
|
|
||||||
self.initialSetupTimer = nil
|
|
||||||
|
|
||||||
guard self.currentAudioOutputValue != output else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.currentAudioOutputValue = output
|
|
||||||
self.didSetCurrentAudioOutputValue = true
|
|
||||||
|
|
||||||
self.audioOutputStatePromise.set(.single((self.audioOutputStateValue.0, output))
|
|
||||||
|> then(
|
|
||||||
.single(self.audioOutputStateValue)
|
|
||||||
|> delay(1.0, queue: Queue.mainQueue())
|
|
||||||
))
|
|
||||||
|
|
||||||
if let audioSessionControl = self.audioSessionControl {
|
|
||||||
if let callKitIntegration = self.callKitIntegration {
|
|
||||||
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
|
|
||||||
} else {
|
|
||||||
audioSessionControl.setOutputMode(.custom(output))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func switchToSpeakerIfBuiltin() {
|
|
||||||
if case .builtin = self.currentAudioOutputValue {
|
|
||||||
self.setCurrentAudioOutput(.speaker)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class PresentationCallImpl: PresentationCall {
|
public final class PresentationCallImpl: PresentationCall {
|
||||||
public let context: AccountContext
|
public let context: AccountContext
|
||||||
private let audioSession: ManagedAudioSession
|
private let audioSession: ManagedAudioSession
|
||||||
@ -556,7 +346,7 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
if let data = context.currentAppConfiguration.with({ $0 }).data, let _ = data["ios_killswitch_disable_call_device"] {
|
if let data = context.currentAppConfiguration.with({ $0 }).data, let _ = data["ios_killswitch_disable_call_device"] {
|
||||||
self.sharedAudioContext = nil
|
self.sharedAudioContext = nil
|
||||||
} else {
|
} else {
|
||||||
self.sharedAudioContext = SharedCallAudioContext(audioSession: audioSession, callKitIntegration: callKitIntegration, defaultToSpeaker: startWithVideo || initialState?.type == .video)
|
self.sharedAudioContext = SharedCallAudioContext.get(audioSession: audioSession, callKitIntegration: callKitIntegration, defaultToSpeaker: startWithVideo || initialState?.type == .video)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let _ = self.sharedAudioContext {
|
if let _ = self.sharedAudioContext {
|
||||||
|
@ -891,12 +891,18 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
|||||||
var sharedAudioContext = sharedAudioContext
|
var sharedAudioContext = sharedAudioContext
|
||||||
if sharedAudioContext == nil {
|
if sharedAudioContext == nil {
|
||||||
var useSharedAudio = !isStream
|
var useSharedAudio = !isStream
|
||||||
if let data = self.accountContext.currentAppConfiguration.with({ $0 }).data, data["ios_killswitch_group_shared_audio"] != nil {
|
var canReuseCurrent = true
|
||||||
useSharedAudio = false
|
if let data = self.accountContext.currentAppConfiguration.with({ $0 }).data {
|
||||||
|
if data["ios_killswitch_group_shared_audio"] != nil {
|
||||||
|
useSharedAudio = false
|
||||||
|
}
|
||||||
|
if data["ios_killswitch_group_shared_audio_reuse"] != nil {
|
||||||
|
canReuseCurrent = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if useSharedAudio {
|
if useSharedAudio {
|
||||||
let sharedAudioContextValue = SharedCallAudioContext(audioSession: audioSession, callKitIntegration: callKitIntegration, defaultToSpeaker: true)
|
let sharedAudioContextValue = SharedCallAudioContext.get(audioSession: audioSession, callKitIntegration: callKitIntegration, defaultToSpeaker: true, reuseCurrent: canReuseCurrent && callKitIntegration == nil)
|
||||||
sharedAudioContext = sharedAudioContextValue
|
sharedAudioContext = sharedAudioContextValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
231
submodules/TelegramCallsUI/Sources/SharedCallAudioContext.swift
Normal file
231
submodules/TelegramCallsUI/Sources/SharedCallAudioContext.swift
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftSignalKit
|
||||||
|
import TelegramVoip
|
||||||
|
import TelegramAudio
|
||||||
|
|
||||||
|
public final class SharedCallAudioContext {
|
||||||
|
private static weak var current: SharedCallAudioContext?
|
||||||
|
|
||||||
|
let audioDevice: OngoingCallContext.AudioDevice?
|
||||||
|
let callKitIntegration: CallKitIntegration?
|
||||||
|
|
||||||
|
private let defaultToSpeaker: Bool
|
||||||
|
|
||||||
|
private var audioSessionDisposable: Disposable?
|
||||||
|
private var audioSessionShouldBeActiveDisposable: Disposable?
|
||||||
|
private var isAudioSessionActiveDisposable: Disposable?
|
||||||
|
private var audioOutputStateDisposable: Disposable?
|
||||||
|
|
||||||
|
private(set) var audioSessionControl: ManagedAudioSessionControl?
|
||||||
|
|
||||||
|
private let isAudioSessionActivePromise = Promise<Bool>(false)
|
||||||
|
private var isAudioSessionActive: Signal<Bool, NoError> {
|
||||||
|
return self.isAudioSessionActivePromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
private let audioOutputStatePromise = Promise<([AudioSessionOutput], AudioSessionOutput?)>(([], nil))
|
||||||
|
private var audioOutputStateValue: ([AudioSessionOutput], AudioSessionOutput?) = ([], nil)
|
||||||
|
public private(set) var currentAudioOutputValue: AudioSessionOutput = .builtin
|
||||||
|
private var didSetCurrentAudioOutputValue: Bool = false
|
||||||
|
var audioOutputState: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> {
|
||||||
|
return self.audioOutputStatePromise.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
private let audioSessionShouldBeActive = Promise<Bool>(true)
|
||||||
|
private var initialSetupTimer: Foundation.Timer?
|
||||||
|
|
||||||
|
static func get(audioSession: ManagedAudioSession, callKitIntegration: CallKitIntegration?, defaultToSpeaker: Bool = false, reuseCurrent: Bool = false) -> SharedCallAudioContext {
|
||||||
|
if let current = self.current, reuseCurrent {
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
let context = SharedCallAudioContext(audioSession: audioSession, callKitIntegration: callKitIntegration, defaultToSpeaker: defaultToSpeaker)
|
||||||
|
self.current = context
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|
||||||
|
private init(audioSession: ManagedAudioSession, callKitIntegration: CallKitIntegration?, defaultToSpeaker: Bool = false) {
|
||||||
|
self.callKitIntegration = callKitIntegration
|
||||||
|
self.audioDevice = OngoingCallContext.AudioDevice.create(enableSystemMute: false)
|
||||||
|
|
||||||
|
var defaultToSpeaker = defaultToSpeaker
|
||||||
|
if audioSession.getIsHeadsetPluggedIn() {
|
||||||
|
defaultToSpeaker = false
|
||||||
|
}
|
||||||
|
|
||||||
|
self.defaultToSpeaker = defaultToSpeaker
|
||||||
|
|
||||||
|
if defaultToSpeaker {
|
||||||
|
self.didSetCurrentAudioOutputValue = true
|
||||||
|
self.currentAudioOutputValue = .speaker
|
||||||
|
}
|
||||||
|
|
||||||
|
var didReceiveAudioOutputs = false
|
||||||
|
self.audioSessionDisposable = audioSession.push(audioSessionType: .voiceCall, manualActivate: { [weak self] control in
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let previousControl = self.audioSessionControl
|
||||||
|
self.audioSessionControl = control
|
||||||
|
|
||||||
|
if previousControl == nil, let audioSessionControl = self.audioSessionControl {
|
||||||
|
if let callKitIntegration = self.callKitIntegration {
|
||||||
|
if self.didSetCurrentAudioOutputValue {
|
||||||
|
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue))
|
||||||
|
audioSessionControl.setup(synchronous: true)
|
||||||
|
}
|
||||||
|
|
||||||
|
let audioSessionActive: Signal<Bool, NoError>
|
||||||
|
if let callKitIntegration = self.callKitIntegration {
|
||||||
|
audioSessionActive = callKitIntegration.audioSessionActive
|
||||||
|
} else {
|
||||||
|
audioSessionControl.activate({ _ in })
|
||||||
|
audioSessionActive = .single(true)
|
||||||
|
}
|
||||||
|
self.isAudioSessionActivePromise.set(audioSessionActive)
|
||||||
|
|
||||||
|
self.initialSetupTimer?.invalidate()
|
||||||
|
self.initialSetupTimer = Foundation.Timer(timeInterval: 0.5, repeats: false, block: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.defaultToSpeaker, let audioSessionControl = self.audioSessionControl {
|
||||||
|
self.currentAudioOutputValue = .speaker
|
||||||
|
self.didSetCurrentAudioOutputValue = true
|
||||||
|
|
||||||
|
if let callKitIntegration = self.callKitIntegration {
|
||||||
|
if self.didSetCurrentAudioOutputValue {
|
||||||
|
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue))
|
||||||
|
audioSessionControl.setup(synchronous: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, deactivate: { [weak self] _ in
|
||||||
|
return Signal { subscriber in
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
if let self {
|
||||||
|
self.isAudioSessionActivePromise.set(.single(false))
|
||||||
|
self.audioSessionControl = nil
|
||||||
|
}
|
||||||
|
subscriber.putCompletion()
|
||||||
|
}
|
||||||
|
return EmptyDisposable
|
||||||
|
}
|
||||||
|
}, availableOutputsChanged: { [weak self] availableOutputs, currentOutput in
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.audioOutputStateValue = (availableOutputs, currentOutput)
|
||||||
|
if let currentOutput = currentOutput {
|
||||||
|
self.currentAudioOutputValue = currentOutput
|
||||||
|
self.didSetCurrentAudioOutputValue = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var signal: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> = .single((availableOutputs, currentOutput))
|
||||||
|
if !didReceiveAudioOutputs {
|
||||||
|
didReceiveAudioOutputs = true
|
||||||
|
if currentOutput == .speaker {
|
||||||
|
signal = .single((availableOutputs, .builtin))
|
||||||
|
|> then(
|
||||||
|
signal
|
||||||
|
|> delay(1.0, queue: Queue.mainQueue())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.audioOutputStatePromise.set(signal)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.audioSessionShouldBeActive.set(.single(true))
|
||||||
|
self.audioSessionShouldBeActiveDisposable = (self.audioSessionShouldBeActive.get()
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if value {
|
||||||
|
if let audioSessionControl = self.audioSessionControl {
|
||||||
|
let audioSessionActive: Signal<Bool, NoError>
|
||||||
|
if let callKitIntegration = self.callKitIntegration {
|
||||||
|
audioSessionActive = callKitIntegration.audioSessionActive
|
||||||
|
} else {
|
||||||
|
audioSessionControl.activate({ _ in })
|
||||||
|
audioSessionActive = .single(true)
|
||||||
|
}
|
||||||
|
self.isAudioSessionActivePromise.set(audioSessionActive)
|
||||||
|
} else {
|
||||||
|
self.isAudioSessionActivePromise.set(.single(false))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.isAudioSessionActivePromise.set(.single(false))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.isAudioSessionActiveDisposable = (self.isAudioSessionActive
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.audioDevice?.setIsAudioSessionActive(value)
|
||||||
|
})
|
||||||
|
|
||||||
|
self.audioOutputStateDisposable = (self.audioOutputStatePromise.get()
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.audioOutputStateValue = value
|
||||||
|
if let currentOutput = value.1 {
|
||||||
|
self.currentAudioOutputValue = currentOutput
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.audioSessionDisposable?.dispose()
|
||||||
|
self.audioSessionShouldBeActiveDisposable?.dispose()
|
||||||
|
self.isAudioSessionActiveDisposable?.dispose()
|
||||||
|
self.audioOutputStateDisposable?.dispose()
|
||||||
|
self.initialSetupTimer?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCurrentAudioOutput(_ output: AudioSessionOutput) {
|
||||||
|
self.initialSetupTimer?.invalidate()
|
||||||
|
self.initialSetupTimer = nil
|
||||||
|
|
||||||
|
guard self.currentAudioOutputValue != output else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.currentAudioOutputValue = output
|
||||||
|
self.didSetCurrentAudioOutputValue = true
|
||||||
|
|
||||||
|
self.audioOutputStatePromise.set(.single((self.audioOutputStateValue.0, output))
|
||||||
|
|> then(
|
||||||
|
.single(self.audioOutputStateValue)
|
||||||
|
|> delay(1.0, queue: Queue.mainQueue())
|
||||||
|
))
|
||||||
|
|
||||||
|
if let audioSessionControl = self.audioSessionControl {
|
||||||
|
if let callKitIntegration = self.callKitIntegration {
|
||||||
|
callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue))
|
||||||
|
} else {
|
||||||
|
audioSessionControl.setOutputMode(.custom(output))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func switchToSpeakerIfBuiltin() {
|
||||||
|
if case .builtin = self.currentAudioOutputValue {
|
||||||
|
self.setCurrentAudioOutput(.speaker)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -262,7 +262,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
|||||||
case let .chats(chatsNode):
|
case let .chats(chatsNode):
|
||||||
count = chatsNode.currentState.selectedPeerIds.count
|
count = chatsNode.currentState.selectedPeerIds.count
|
||||||
}
|
}
|
||||||
if isCall && count == 0 {
|
if isCall && count <= 1 {
|
||||||
self.titleView.title = CounterControllerTitle(title: self.params.title ?? self.presentationData.strings.Compose_NewGroupTitle, counter: nil)
|
self.titleView.title = CounterControllerTitle(title: self.params.title ?? self.presentationData.strings.Compose_NewGroupTitle, counter: nil)
|
||||||
} else {
|
} else {
|
||||||
var count = count
|
var count = count
|
||||||
|
@ -657,6 +657,17 @@ public:
|
|||||||
|
|
||||||
if (!WrappedInstance()->Playing()) {
|
if (!WrappedInstance()->Playing()) {
|
||||||
WrappedInstance()->InitPlayout();
|
WrappedInstance()->InitPlayout();
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
if (!WrappedInstance()->PlayoutIsInitialized()) {
|
||||||
|
sleep(1);
|
||||||
|
WrappedInstance()->InitPlayout();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!WrappedInstance()->PlayoutIsInitialized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
WrappedInstance()->StartPlayout();
|
WrappedInstance()->StartPlayout();
|
||||||
WrappedInstance()->InitRecording();
|
WrappedInstance()->InitRecording();
|
||||||
WrappedInstance()->StartRecording();
|
WrappedInstance()->StartRecording();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user