diff --git a/submodules/MediaPlayer/Sources/ChunkMediaPlayerV2.swift b/submodules/MediaPlayer/Sources/ChunkMediaPlayerV2.swift index ba102d8775..7cf0bfdf0b 100644 --- a/submodules/MediaPlayer/Sources/ChunkMediaPlayerV2.swift +++ b/submodules/MediaPlayer/Sources/ChunkMediaPlayerV2.swift @@ -168,11 +168,14 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { private let mediaDataReaderParams: MediaDataReaderParams private let audioSessionManager: ManagedAudioSession private let onSeeked: (() -> Void)? + private weak var playerNode: MediaPlayerNode? private let renderSynchronizer: AVSampleBufferRenderSynchronizer private var videoRenderer: AVSampleBufferDisplayLayer private var audioRenderer: AVSampleBufferAudioRenderer? + private var didNotifySentVideoFrames: Bool = false + private var partsState = ChunkMediaPlayerPartsState(duration: nil, content: .parts([])) private var loadedParts: [LoadedPart] = [] private var loadedPartsMediaData: QueueLocalObject @@ -244,6 +247,7 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { self.mediaDataReaderParams = params self.audioSessionManager = audioSessionManager self.onSeeked = onSeeked + self.playerNode = playerNode self.loadedPartsMediaData = QueueLocalObject(queue: self.dataQueue, generate: { return LoadedPartsMediaData() @@ -918,10 +922,11 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { videoTarget = self.videoRenderer } + let didNotifySentVideoFrames = self.didNotifySentVideoFrames videoTarget.requestMediaDataWhenReady(on: self.dataQueue.queue, using: { [weak self] in if let loadedPartsMediaData = loadedPartsMediaData.unsafeGet() { - let bufferIsReadyForMoreData = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: videoTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: true) - if bufferIsReadyForMoreData { + let bufferFillResult = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: videoTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: true) + if bufferFillResult.bufferIsReadyForMoreData { videoTarget.stopRequestingMediaData() Queue.mainQueue().async { guard let self else { @@ -931,6 +936,21 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { 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?() + } + } + } } }) } @@ -941,8 +961,8 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { let audioTarget = audioRenderer audioTarget.requestMediaDataWhenReady(on: self.dataQueue.queue, using: { [weak self] in if let loadedPartsMediaData = loadedPartsMediaData.unsafeGet() { - let bufferIsReadyForMoreData = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: audioTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: false) - if bufferIsReadyForMoreData { + let bufferFillResult = ChunkMediaPlayerV2.fillRendererBuffer(bufferTarget: audioTarget, loadedPartsMediaData: loadedPartsMediaData, isVideo: false) + if bufferFillResult.bufferIsReadyForMoreData { audioTarget.stopRequestingMediaData() Queue.mainQueue().async { guard let self else { @@ -957,8 +977,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 didEnqueue = false outer: while true { if !bufferTarget.isReadyForMoreMediaData { bufferIsReadyForMoreData = false @@ -1054,6 +1075,7 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { print("Enqueue audio \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).value) next: \(CMSampleBufferGetPresentationTimeStamp(sampleBuffer).value + 1024)") }*/ bufferTarget.enqueue(sampleBuffer) + didEnqueue = true hasData = true continue outer case .waitingForMoreData: @@ -1067,7 +1089,7 @@ public final class ChunkMediaPlayerV2: ChunkMediaPlayer { } } - return bufferIsReadyForMoreData + return (bufferIsReadyForMoreData: bufferIsReadyForMoreData, didEnqueue: didEnqueue) } } diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index de0c83eb2b..64c5e8a895 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1743,7 +1743,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } 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 @@ -3112,7 +3112,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.hasScreencast = true - let screencastCallContext = OngoingGroupCallContext(audioSessionActive: .single(true), video: self.screencastCapturer, requestMediaChannelDescriptions: { _, _ in EmptyDisposable }, rejoinNeeded: { }, outgoingAudioBitrateKbit: nil, videoContentType: .screencast, enableNoiseSuppression: false, disableAudioInput: true, enableSystemMute: false, preferX264: false, logPath: "", onMutedSpeechActivityDetected: { _ in }, encryptionKey: nil, isConference: self.isConference, sharedAudioDevice: nil) + let screencastCallContext = OngoingGroupCallContext(audioSessionActive: .single(true), video: self.screencastCapturer, requestMediaChannelDescriptions: { _, _ in EmptyDisposable }, rejoinNeeded: { }, outgoingAudioBitrateKbit: nil, videoContentType: .screencast, enableNoiseSuppression: false, disableAudioInput: true, enableSystemMute: false, preferX264: false, logPath: "", onMutedSpeechActivityDetected: { _ in }, encryptionKey: nil, isConference: self.isConference, isStream: false, sharedAudioDevice: nil) self.screencastCallContext = screencastCallContext self.screencastJoinDisposable.set((screencastCallContext.joinPayload diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index b0af5d23a2..128bcba6f1 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -498,6 +498,7 @@ public final class OngoingGroupCallContext { onMutedSpeechActivityDetected: @escaping (Bool) -> Void, encryptionKey: Data?, isConference: Bool, + isStream: Bool, sharedAudioDevice: OngoingCallContext.AudioDevice? ) { self.queue = queue @@ -508,7 +509,7 @@ public final class OngoingGroupCallContext { let tempStatsLogPath = self.tempStatsLogFile.path #if os(iOS) - if sharedAudioDevice == nil { + if sharedAudioDevice == nil && !isStream { self.audioDevice = OngoingCallContext.AudioDevice.create(enableSystemMute: false) } else { self.audioDevice = sharedAudioDevice @@ -1128,10 +1129,10 @@ public final class OngoingGroupCallContext { } } - public init(inputDeviceId: String = "", outputDeviceId: String = "", audioSessionActive: Signal, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @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, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @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 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) }) } diff --git a/versions.json b/versions.json index cbe48333d2..3b870588a3 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "11.6.2", + "app": "11.6.3", "xcode": "16.0", "bazel": "7.3.1:981f82a470bad1349322b6f51c9c6ffa0aa291dab1014fac411543c12e661dff", "macos": "15.0"