Merge branch 'beta'

# Conflicts:
#	submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift
#	submodules/TelegramVoip/Sources/GroupCallContext.swift
#	versions.json
This commit is contained in:
Isaac 2025-01-24 21:05:37 +04:00
commit ded946411c
4 changed files with 40 additions and 15 deletions

View File

@ -1 +1 @@
2500 2510

View File

@ -168,11 +168,14 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
private let mediaDataReaderParams: MediaDataReaderParams private let mediaDataReaderParams: MediaDataReaderParams
private let audioSessionManager: ManagedAudioSession private let audioSessionManager: ManagedAudioSession
private let onSeeked: (() -> Void)? private let onSeeked: (() -> Void)?
private weak var playerNode: MediaPlayerNode?
private let renderSynchronizer: AVSampleBufferRenderSynchronizer private let renderSynchronizer: AVSampleBufferRenderSynchronizer
private var videoRenderer: AVSampleBufferDisplayLayer private var videoRenderer: AVSampleBufferDisplayLayer
private var audioRenderer: AVSampleBufferAudioRenderer? private var audioRenderer: AVSampleBufferAudioRenderer?
private var didNotifySentVideoFrames: Bool = false
private var partsState = ChunkMediaPlayerPartsState(duration: nil, content: .parts([])) private var partsState = ChunkMediaPlayerPartsState(duration: nil, content: .parts([]))
private var loadedParts: [LoadedPart] = [] private var loadedParts: [LoadedPart] = []
private var loadedPartsMediaData: QueueLocalObject<LoadedPartsMediaData> private var loadedPartsMediaData: QueueLocalObject<LoadedPartsMediaData>
@ -245,6 +248,7 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
self.mediaDataReaderParams = params self.mediaDataReaderParams = params
self.audioSessionManager = audioSessionManager self.audioSessionManager = audioSessionManager
self.onSeeked = onSeeked self.onSeeked = onSeeked
self.playerNode = playerNode
self.loadedPartsMediaData = QueueLocalObject(queue: self.dataQueue, generate: { self.loadedPartsMediaData = QueueLocalObject(queue: self.dataQueue, generate: {
return LoadedPartsMediaData() return LoadedPartsMediaData()
@ -938,10 +942,11 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
videoTarget = self.videoRenderer videoTarget = self.videoRenderer
} }
let didNotifySentVideoFrames = self.didNotifySentVideoFrames
videoTarget.requestMediaDataWhenReady(on: self.dataQueue.queue, using: { [weak self] in videoTarget.requestMediaDataWhenReady(on: self.dataQueue.queue, using: { [weak self] in
if let loadedPartsMediaData = loadedPartsMediaData.unsafeGet() { if let loadedPartsMediaData = loadedPartsMediaData.unsafeGet() {
let bufferIsReadyForMoreData = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: videoTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: true) let bufferFillResult = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: videoTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: true)
if bufferIsReadyForMoreData { if bufferFillResult.bufferIsReadyForMoreData {
videoTarget.stopRequestingMediaData() videoTarget.stopRequestingMediaData()
Queue.mainQueue().async { Queue.mainQueue().async {
guard let self else { guard let self else {
@ -951,6 +956,21 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
self.updateInternalState() self.updateInternalState()
} }
} }
if !didNotifySentVideoFrames {
Queue.mainQueue().async {
guard let self else {
return
}
if self.didNotifySentVideoFrames {
return
}
self.didNotifySentVideoFrames = true
if #available(iOS 17.4, *) {
} else {
self.playerNode?.hasSentFramesToDisplay?()
}
}
}
} }
}) })
} }
@ -961,8 +981,8 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
let audioTarget = audioRenderer let audioTarget = audioRenderer
audioTarget.requestMediaDataWhenReady(on: self.dataQueue.queue, using: { [weak self] in audioTarget.requestMediaDataWhenReady(on: self.dataQueue.queue, using: { [weak self] in
if let loadedPartsMediaData = loadedPartsMediaData.unsafeGet() { if let loadedPartsMediaData = loadedPartsMediaData.unsafeGet() {
let bufferIsReadyForMoreData = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: audioTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: false) let bufferFillResult = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: audioTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: false)
if bufferIsReadyForMoreData { if bufferFillResult.bufferIsReadyForMoreData {
audioTarget.stopRequestingMediaData() audioTarget.stopRequestingMediaData()
Queue.mainQueue().async { Queue.mainQueue().async {
guard let self else { guard let self else {
@ -977,8 +997,9 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
} }
} }
private static func fillRendererBuffer(bufferTarget: AVQueuedSampleBufferRendering, loadedPartsMediaData: LoadedPartsMediaData, isVideo: Bool) -> Bool { private static func fillRendererBuffer(bufferTarget: AVQueuedSampleBufferRendering, loadedPartsMediaData: LoadedPartsMediaData, isVideo: Bool) -> (bufferIsReadyForMoreData: Bool, didEnqueue: Bool) {
var bufferIsReadyForMoreData = true var bufferIsReadyForMoreData = true
var didEnqueue = false
outer: while true { outer: while true {
if !bufferTarget.isReadyForMoreMediaData { if !bufferTarget.isReadyForMoreMediaData {
bufferIsReadyForMoreData = false bufferIsReadyForMoreData = false
@ -1077,6 +1098,7 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
print("Enqueue audio \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).value) next: \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).value + 1024)") print("Enqueue audio \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).value) next: \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).value + 1024)")
}*/ }*/
bufferTarget.enqueue(sampleBuffer) bufferTarget.enqueue(sampleBuffer)
didEnqueue = true
hasData = true hasData = true
continue outer continue outer
case .waitingForMoreData: case .waitingForMoreData:
@ -1090,7 +1112,7 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer {
} }
} }
return bufferIsReadyForMoreData return (bufferIsReadyForMoreData: bufferIsReadyForMoreData, didEnqueue: didEnqueue)
} }
} }

View File

@ -1871,7 +1871,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
strongSelf.onMutedSpeechActivityDetected?(value) strongSelf.onMutedSpeechActivityDetected?(value)
} }
}, encryptionKey: encryptionKey, isConference: self.isConference, sharedAudioDevice: self.sharedAudioDevice)) }, encryptionKey: encryptionKey, isConference: self.isConference, isStream: self.isStream, sharedAudioDevice: self.sharedAudioDevice))
} }
self.genericCallContext = genericCallContext self.genericCallContext = genericCallContext

View File

@ -497,6 +497,7 @@ public final class OngoingGroupCallContext {
onMutedSpeechActivityDetected: @escaping (Bool) -> Void, onMutedSpeechActivityDetected: @escaping (Bool) -> Void,
encryptionKey: Data?, encryptionKey: Data?,
isConference: Bool, isConference: Bool,
isStream: Bool,
sharedAudioDevice: OngoingCallContext.AudioDevice? sharedAudioDevice: OngoingCallContext.AudioDevice?
) { ) {
self.queue = queue self.queue = queue
@ -506,12 +507,14 @@ public final class OngoingGroupCallContext {
self.tempStatsLogFile = EngineTempBox.shared.tempFile(fileName: "CallStats.json") self.tempStatsLogFile = EngineTempBox.shared.tempFile(fileName: "CallStats.json")
let tempStatsLogPath = self.tempStatsLogFile.path let tempStatsLogPath = self.tempStatsLogFile.path
#if os(iOS) #if os(iOS)
if sharedAudioDevice == nil && !isStream {
self.audioDevice = sharedAudioDevice self.audioDevice = OngoingCallContext.AudioDevice.create(enableSystemMute: false)
} else {
self.audioDevice = sharedAudioDevice
}
let audioDevice = self.audioDevice let audioDevice = self.audioDevice
#endif #endif
var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)? var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)?
var audioLevelsUpdatedImpl: (([NSNumber]) -> Void)? var audioLevelsUpdatedImpl: (([NSNumber]) -> Void)?
var activityUpdatedImpl: (([UInt32]) -> Void)? var activityUpdatedImpl: (([UInt32]) -> Void)?
@ -1178,10 +1181,10 @@ public final class OngoingGroupCallContext {
} }
} }
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, enableSystemMute: Bool, preferX264: Bool, logPath: String, onMutedSpeechActivityDetected: @escaping (Bool) -> Void, encryptionKey: Data?, isConference: Bool, sharedAudioDevice: OngoingCallContext.AudioDevice?) { 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, enableSystemMute: Bool, preferX264: Bool, logPath: String, onMutedSpeechActivityDetected: @escaping (Bool) -> Void, encryptionKey: Data?, isConference: Bool, isStream: Bool, sharedAudioDevice: OngoingCallContext.AudioDevice?) {
let queue = self.queue let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: { self.impl = QueueLocalObject(queue: queue, generate: {
return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, audioSessionActive: audioSessionActive, video: video, requestMediaChannelDescriptions: requestMediaChannelDescriptions, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, videoContentType: videoContentType, enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, enableSystemMute: enableSystemMute, preferX264: preferX264, logPath: logPath, onMutedSpeechActivityDetected: onMutedSpeechActivityDetected, encryptionKey: encryptionKey, isConference: isConference, sharedAudioDevice: sharedAudioDevice) return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, audioSessionActive: audioSessionActive, video: video, requestMediaChannelDescriptions: requestMediaChannelDescriptions, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, videoContentType: videoContentType, enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, enableSystemMute: enableSystemMute, preferX264: preferX264, logPath: logPath, onMutedSpeechActivityDetected: onMutedSpeechActivityDetected, encryptionKey: encryptionKey, isConference: isConference, isStream: isStream, sharedAudioDevice: sharedAudioDevice)
}) })
} }