diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 979b3565aa..eceae9d0c4 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -571,8 +571,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.statePromise = ValuePromise(self.stateValue) self.temporaryJoinTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - - self.videoCapturer = OngoingCallVideoCapturer(keepLandscape: false) + + if accountContext.sharedContext.immediateExperimentalUISettings.demoVideoChats { + self.videoCapturer = OngoingCallVideoCapturer(keepLandscape: false) + } self.isVideo = self.videoCapturer != nil var didReceiveAudioOutputs = false @@ -1061,7 +1063,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { strongSelf.requestCall(movingFromBroadcastToRtc: false) } } - }, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit) + }, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, enableVideo: self.isVideo) self.incomingVideoSourcePromise.set(callContext.videoSources |> deliverOnMainQueue |> map { [weak self] sources -> [PeerId: UInt32] in diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 5a7305189c..c2e82c85e2 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -268,6 +268,7 @@ private final class MainVideoContainerNode: ASDisplayNode { private let call: PresentationGroupCall private var currentVideoNode: GroupVideoNode? + private var candidateVideoNode: GroupVideoNode? private var currentPeer: (PeerId, UInt32)? private var validLayout: CGSize? @@ -281,7 +282,7 @@ private final class MainVideoContainerNode: ASDisplayNode { self.backgroundColor = .black } - func updatePeer(peer: (peerId: PeerId, source: UInt32)?) { + func updatePeer(peer: (peerId: PeerId, source: UInt32)?, waitForFullSize: Bool) { if self.currentPeer?.0 == peer?.0 && self.currentPeer?.1 == peer?.1 { return } @@ -292,15 +293,40 @@ private final class MainVideoContainerNode: ASDisplayNode { guard let strongSelf = self, let videoView = videoView else { return } - let videoNode = GroupVideoNode(videoView: videoView) - if let currentVideoNode = strongSelf.currentVideoNode { - currentVideoNode.removeFromSupernode() - strongSelf.currentVideoNode = nil - } - strongSelf.currentVideoNode = videoNode - strongSelf.addSubnode(videoNode) - if let size = strongSelf.validLayout { - strongSelf.update(size: size, transition: .immediate) + + if waitForFullSize { + let candidateVideoNode = GroupVideoNode(videoView: videoView) + strongSelf.candidateVideoNode = candidateVideoNode + + Queue.mainQueue().after(0.3, { [weak candidateVideoNode] in + guard let strongSelf = self, let videoNode = candidateVideoNode, videoNode === strongSelf.candidateVideoNode else { + return + } + + if let currentVideoNode = strongSelf.currentVideoNode { + currentVideoNode.removeFromSupernode() + strongSelf.currentVideoNode = nil + } + strongSelf.currentVideoNode = videoNode + strongSelf.addSubnode(videoNode) + if let size = strongSelf.validLayout { + strongSelf.update(size: size, transition: .immediate) + } + }) + } else { + strongSelf.candidateVideoNode = nil + + let videoNode = GroupVideoNode(videoView: videoView) + + if let currentVideoNode = strongSelf.currentVideoNode { + currentVideoNode.removeFromSupernode() + strongSelf.currentVideoNode = nil + } + strongSelf.currentVideoNode = videoNode + strongSelf.addSubnode(videoNode) + if let size = strongSelf.validLayout { + strongSelf.update(size: size, transition: .immediate) + } } } }) @@ -874,11 +900,11 @@ public final class VoiceChatController: ViewController { if strongSelf.currentDominantSpeakerWithVideo?.0 != peerId || strongSelf.currentDominantSpeakerWithVideo?.1 != source { strongSelf.currentDominantSpeakerWithVideo = (peerId, source) strongSelf.call.setFullSizeVideo(peerId: peerId) - strongSelf.mainVideoContainer?.updatePeer(peer: (peerId: peerId, source: source)) + strongSelf.mainVideoContainer?.updatePeer(peer: (peerId: peerId, source: source), waitForFullSize: false) } else { strongSelf.currentDominantSpeakerWithVideo = nil strongSelf.call.setFullSizeVideo(peerId: nil) - strongSelf.mainVideoContainer?.updatePeer(peer: nil) + strongSelf.mainVideoContainer?.updatePeer(peer: nil, waitForFullSize: false) } } } @@ -1557,7 +1583,7 @@ public final class VoiceChatController: ViewController { if strongSelf.currentDominantSpeakerWithVideo?.0 != peerId || strongSelf.currentDominantSpeakerWithVideo?.1 != source { strongSelf.currentDominantSpeakerWithVideo = (peerId, source) strongSelf.call.setFullSizeVideo(peerId: peerId) - strongSelf.mainVideoContainer?.updatePeer(peer: (peerId: peerId, source: source)) + strongSelf.mainVideoContainer?.updatePeer(peer: (peerId: peerId, source: source), waitForFullSize: true) } } @@ -1709,7 +1735,7 @@ public final class VoiceChatController: ViewController { if !validSources.contains(source) { strongSelf.currentDominantSpeakerWithVideo = nil strongSelf.call.setFullSizeVideo(peerId: nil) - strongSelf.mainVideoContainer?.updatePeer(peer: nil) + strongSelf.mainVideoContainer?.updatePeer(peer: nil, waitForFullSize: false) } } @@ -2493,7 +2519,7 @@ public final class VoiceChatController: ViewController { let topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: panelOffset), size: CGSize(width: size.width, height: topPanelHeight)) if let mainVideoContainer = self.mainVideoContainer { - let videoContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY), size: CGSize(width: layout.size.width, height: 200.0)) + let videoContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY), size: CGSize(width: layout.size.width, height: min(300.0, layout.size.width))) transition.updateFrameAdditive(node: mainVideoContainer, frame: videoContainerFrame) mainVideoContainer.update(size: videoContainerFrame.size, transition: transition) } @@ -2764,7 +2790,7 @@ public final class VoiceChatController: ViewController { let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom var listTopInset = layoutTopInset + topPanelHeight if self.mainVideoContainer != nil { - listTopInset += 200.0 + listTopInset += min(300.0, layout.size.width) } let listSize = CGSize(width: size.width, height: layout.size.height - listTopInset - bottomPanelHeight) diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index 12415778c4..f41298e6b5 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -179,7 +179,7 @@ public final class OngoingGroupCallContext { private var broadcastPartsSource: BroadcastPartSource? - init(queue: Queue, inputDeviceId: String, outputDeviceId: String, video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?) { + init(queue: Queue, inputDeviceId: String, outputDeviceId: String, video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, enableVideo: Bool) { self.queue = queue var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)? @@ -221,7 +221,8 @@ public final class OngoingGroupCallContext { return OngoingGroupCallBroadcastPartTaskImpl(disposable: disposable) }, - outgoingAudioBitrateKbit: outgoingAudioBitrateKbit ?? 32 + outgoingAudioBitrateKbit: outgoingAudioBitrateKbit ?? 32, + enableVideo: enableVideo ) let queue = self.queue @@ -509,10 +510,10 @@ public final class OngoingGroupCallContext { } } - public init(inputDeviceId: String = "", outputDeviceId: String = "", video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?) { + public init(inputDeviceId: String = "", outputDeviceId: String = "", video: OngoingCallVideoCapturer?, participantDescriptionsRequired: @escaping (Set) -> Void, audioStreamData: AudioStreamData?, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, enableVideo: Bool) { let queue = self.queue self.impl = QueueLocalObject(queue: queue, generate: { - return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, video: video, participantDescriptionsRequired: participantDescriptionsRequired, audioStreamData: audioStreamData, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit) + return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, video: video, participantDescriptionsRequired: participantDescriptionsRequired, audioStreamData: audioStreamData, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, enableVideo: enableVideo) }) } diff --git a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h index 3472be33e4..d81ac6e1df 100644 --- a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h +++ b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h @@ -196,7 +196,7 @@ typedef NS_ENUM(int32_t, OngoingGroupCallBroadcastPartStatus) { @interface GroupCallThreadLocalContext : NSObject -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id _Nonnull (^ _Nonnull)(int64_t, int64_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart outgoingAudioBitrateKbit:(int32_t)outgoingAudioBitrateKbit; +- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id _Nonnull (^ _Nonnull)(int64_t, int64_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart outgoingAudioBitrateKbit:(int32_t)outgoingAudioBitrateKbit enableVideo:(bool)enableVideo; - (void)stop; diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 4ec70090b8..1973c5ec0a 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -854,7 +854,7 @@ private: @implementation GroupCallThreadLocalContext -- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id _Nonnull (^ _Nonnull)(int64_t, int64_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart outgoingAudioBitrateKbit:(int32_t)outgoingAudioBitrateKbit { +- (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue networkStateUpdated:(void (^ _Nonnull)(GroupCallNetworkState))networkStateUpdated audioLevelsUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))audioLevelsUpdated inputDeviceId:(NSString * _Nonnull)inputDeviceId outputDeviceId:(NSString * _Nonnull)outputDeviceId videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer incomingVideoSourcesUpdated:(void (^ _Nonnull)(NSArray * _Nonnull))incomingVideoSourcesUpdated participantDescriptionsRequired:(void (^ _Nonnull)(NSArray * _Nonnull))participantDescriptionsRequired requestBroadcastPart:(id _Nonnull (^ _Nonnull)(int64_t, int64_t, void (^ _Nonnull)(OngoingGroupCallBroadcastPart * _Nullable)))requestBroadcastPart outgoingAudioBitrateKbit:(int32_t)outgoingAudioBitrateKbit enableVideo:(bool)enableVideo { self = [super init]; if (self != nil) { _queue = queue; @@ -938,7 +938,8 @@ private: }); return std::make_shared(task); }, - .outgoingAudioBitrateKbit = outgoingAudioBitrateKbit + .outgoingAudioBitrateKbit = outgoingAudioBitrateKbit, + .enableVideo = enableVideo })); } return self; @@ -1233,6 +1234,22 @@ static void processJoinPayload(tgcalls::GroupJoinPayload &payload, void (^ _Nonn } parsedParticipants.push_back(parsedParticipant); } + + NSDictionary *video = dict[@"video"]; + if ([video isKindOfClass:[NSDictionary class]]) { + NSArray *serverSources = video[@"server_sources"]; + if ([serverSources isKindOfClass:[NSArray class]]) { + for (NSNumber *sourceNumber in serverSources) { + if ([sourceNumber isKindOfClass:[NSNumber class]]) { + int32_t signedSource = [sourceNumber intValue]; + result.serverVideoBandwidthProbingSsrc = *(int32_t *)&signedSource; + } else if ([sourceNumber isKindOfClass:[NSString class]]) { + uint32_t source = (uint32_t)[sourceNumber longLongValue]; + result.serverVideoBandwidthProbingSsrc = source; + } + } + } + } if (_instance) { _instance->setJoinResponsePayload(result, std::move(parsedParticipants)); diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index e1f6cdaf2c..68ade13752 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit e1f6cdaf2cefc1a760d74c1de76568a7557c63be +Subproject commit 68ade13752f14fecf0b32bc08e8e47164ef52ddc