diff --git a/submodules/AccountContext/Sources/PresentationCallManager.swift b/submodules/AccountContext/Sources/PresentationCallManager.swift index 1c921b3138..5c53624fbd 100644 --- a/submodules/AccountContext/Sources/PresentationCallManager.swift +++ b/submodules/AccountContext/Sources/PresentationCallManager.swift @@ -286,7 +286,7 @@ public protocol PresentationGroupCall: class { var state: Signal { get } var summaryState: Signal { get } var members: Signal { get } - var audioLevels: Signal<[(PeerId, Float, Bool)], NoError> { get } + var audioLevels: Signal<[(PeerId, UInt32, Float, Bool)], NoError> { get } var myAudioLevel: Signal { get } var isMuted: Signal { get } @@ -298,7 +298,7 @@ public protocol PresentationGroupCall: class { func setIsMuted(action: PresentationGroupCallMuteAction) func updateDefaultParticipantsAreMuted(isMuted: Bool) func setVolume(peerId: PeerId, volume: Double) - func setFullSizeVideo(peerId: PeerId) + func setFullSizeVideo(peerId: PeerId?) func setCurrentAudioOutput(_ output: AudioSessionOutput) func updateMuteState(peerId: PeerId, isMuted: Bool) @@ -307,7 +307,7 @@ public protocol PresentationGroupCall: class { func removedPeer(_ peerId: PeerId) var invitedPeers: Signal<[PeerId], NoError> { get } - var incomingVideoSources: Signal, NoError> { get } + var incomingVideoSources: Signal<[PeerId: UInt32], NoError> { get } func makeIncomingVideoView(source: UInt32, completion: @escaping (PresentationCallVideoView?) -> Void) } diff --git a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift index 39cce0f3b9..fc193c9a30 100644 --- a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift @@ -305,9 +305,9 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { var effectiveLevel: Float = 0.0 var audioLevels = audioLevels if !strongSelf.currentIsMuted { - audioLevels.append((PeerId(0), myAudioLevel, true)) + audioLevels.append((PeerId(0), 0, myAudioLevel, true)) } - effectiveLevel = audioLevels.map { $0.1 }.max() ?? 0.0 + effectiveLevel = audioLevels.map { $0.2 }.max() ?? 0.0 strongSelf.backgroundNode.audioLevel = effectiveLevel })) } diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index ca4fa9dc32..b0bed6e24c 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -239,19 +239,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } - private let audioLevelsPromise = Promise<[(PeerId, Float, Bool)]>() + private let audioLevelsPromise = Promise<[(PeerId, UInt32, Float, Bool)]>() init() { } - func update(levels: [(PeerId, Float, Bool)]) { + func update(levels: [(PeerId, UInt32, Float, Bool)]) { let timestamp = Int32(CFAbsoluteTimeGetCurrent()) let currentParticipants: [PeerId: Participant] = self.participants var validSpeakers: [PeerId: Participant] = [:] var silentParticipants = Set() var speakingParticipants = Set() - for (peerId, level, hasVoice) in levels { + for (peerId, _, level, hasVoice) in levels { if level > speakingLevelThreshold && hasVoice { validSpeakers[peerId] = Participant(timestamp: timestamp, level: level) speakingParticipants.insert(peerId) @@ -276,10 +276,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } - var audioLevels: [(PeerId, Float, Bool)] = [] - for (peerId, level, hasVoice) in levels { + var audioLevels: [(PeerId, UInt32, Float, Bool)] = [] + for (peerId, source, level, hasVoice) in levels { if level > 0.001 { - audioLevels.append((peerId, level, hasVoice)) + audioLevels.append((peerId, source, level, hasVoice)) } } @@ -292,7 +292,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { return self.speakingParticipantsPromise.get() |> distinctUntilChanged } - func getAudioLevels() -> Signal<[(PeerId, Float, Bool)], NoError> { + func getAudioLevels() -> Signal<[(PeerId, UInt32, Float, Bool)], NoError> { return self.audioLevelsPromise.get() } } @@ -361,7 +361,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { private let speakingParticipantsContext = SpeakingParticipantsContext() private var speakingParticipantsReportTimestamp: [PeerId: Double] = [:] - public var audioLevels: Signal<[(PeerId, Float, Bool)], NoError> { + public var audioLevels: Signal<[(PeerId, UInt32, Float, Bool)], NoError> { return self.speakingParticipantsContext.getAudioLevels() } @@ -456,8 +456,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { private var videoCapturer: OngoingCallVideoCapturer? - private let incomingVideoSourcePromise = Promise>(Set()) - public var incomingVideoSources: Signal, NoError> { + private let incomingVideoSourcePromise = Promise<[PeerId: UInt32]>([:]) + public var incomingVideoSources: Signal<[PeerId: UInt32], NoError> { return self.incomingVideoSourcePromise.get() } @@ -609,6 +609,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } else if case .joined = participantUpdate.participationStatusChange { addedParticipants.append((participantUpdate.ssrc, participantUpdate.jsonParams)) + } else if strongSelf.ssrcMapping[participantUpdate.ssrc] == nil { + addedParticipants.append((participantUpdate.ssrc, participantUpdate.jsonParams)) } } case let .call(isTerminated, _): @@ -801,7 +803,20 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { default: if case let .active(callInfo) = internalState { let callContext = OngoingGroupCallContext(video: self.videoCapturer) - self.incomingVideoSourcePromise.set(callContext.videoSources) + self.incomingVideoSourcePromise.set(callContext.videoSources + |> deliverOnMainQueue + |> map { [weak self] sources -> [PeerId: UInt32] in + guard let strongSelf = self else { + return [:] + } + var result: [PeerId: UInt32] = [:] + for source in sources { + if let peerId = strongSelf.ssrcMapping[source] { + result[peerId] = source + } + } + return result + }) self.callContext = callContext self.requestDisposable.set((callContext.joinPayload |> take(1) @@ -901,16 +916,19 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { guard let strongSelf = self else { return } - var result: [(PeerId, Float, Bool)] = [] + var result: [(PeerId, UInt32, Float, Bool)] = [] var myLevel: Float = 0.0 var myLevelHasVoice: Bool = false for (ssrcKey, level, hasVoice) in levels { - var peerId: PeerId? + let source: UInt32 + let peerId: PeerId? switch ssrcKey { case .local: peerId = strongSelf.accountContext.account.peerId + source = 0 case let .source(ssrc): peerId = strongSelf.ssrcMapping[ssrc] + source = ssrc } if let peerId = peerId { if case .local = ssrcKey { @@ -919,7 +937,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { myLevelHasVoice = hasVoice } } - result.append((peerId, level, hasVoice)) + result.append((peerId, source, level, hasVoice)) } } @@ -1262,12 +1280,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { } } - public func setFullSizeVideo(peerId: PeerId) { + public func setFullSizeVideo(peerId: PeerId?) { var resolvedSsrc: UInt32? - for (ssrc, id) in self.ssrcMapping { - if id == peerId { - resolvedSsrc = ssrc - break + if let peerId = peerId { + for (ssrc, id) in self.ssrcMapping { + if id == peerId { + resolvedSsrc = ssrc + break + } } } self.callContext?.setFullSizeVideoSsrc(ssrc: resolvedSsrc) diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 1e03d0cefd..07ea166886 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -119,20 +119,21 @@ private final class VoiceChatControllerTitleNode: ASDisplayNode { } final class GroupVideoNode: ASDisplayNode { + private let videoViewContainer: UIView private let videoView: PresentationCallVideoView private var validLayout: CGSize? + var tapped: (() -> Void)? + init(videoView: PresentationCallVideoView) { + self.videoViewContainer = UIView() self.videoView = videoView super.init() - self.backgroundColor = .black - self.clipsToBounds = true - self.cornerRadius = 8.0 - - self.view.addSubview(self.videoView.view) + self.videoViewContainer.addSubview(self.videoView.view) + self.view.addSubview(self.videoViewContainer) videoView.setOnFirstFrameReceived({ [weak self] _ in Queue.mainQueue().async { @@ -155,10 +156,19 @@ final class GroupVideoNode: ASDisplayNode { } } }) + + self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) + } + + @objc private func tapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.tapped?() + } } func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { self.validLayout = size + self.videoViewContainer.frame = CGRect(origin: CGPoint(), size: size) let orientation = self.videoView.getOrientation() var aspect = self.videoView.getAspect() @@ -168,28 +178,42 @@ final class GroupVideoNode: ASDisplayNode { let rotatedAspect: CGFloat let angle: CGFloat + let switchOrientation: Bool switch orientation { case .rotation0: angle = 0.0 - rotatedAspect = aspect + rotatedAspect = 1 / aspect + switchOrientation = false case .rotation90: angle = CGFloat.pi / 2.0 - rotatedAspect = 1 / aspect + rotatedAspect = aspect + switchOrientation = true case .rotation180: angle = CGFloat.pi - rotatedAspect = aspect + rotatedAspect = 1 / aspect + switchOrientation = false case .rotation270: angle = CGFloat.pi * 3.0 / 2.0 - rotatedAspect = 1 / aspect + rotatedAspect = aspect + switchOrientation = true } - let rotatedVideoSize = CGSize(width: 100.0, height: rotatedAspect * 100.0).aspectFilled(size) + var rotatedVideoSize = CGSize(width: 100.0, height: rotatedAspect * 100.0) + + if size.width < 100.0 { + rotatedVideoSize = rotatedVideoSize.aspectFilled(size) + } else { + rotatedVideoSize = rotatedVideoSize.aspectFitted(size) + } + + if switchOrientation { + rotatedVideoSize = CGSize(width: rotatedVideoSize.height, height: rotatedVideoSize.width) + } var rotatedVideoFrame = CGRect(origin: CGPoint(x: floor((size.width - rotatedVideoSize.width) / 2.0), y: floor((size.height - rotatedVideoSize.height) / 2.0)), size: rotatedVideoSize) rotatedVideoFrame.origin.x = floor(rotatedVideoFrame.origin.x) rotatedVideoFrame.origin.y = floor(rotatedVideoFrame.origin.y) rotatedVideoFrame.size.width = ceil(rotatedVideoFrame.size.width) rotatedVideoFrame.size.height = ceil(rotatedVideoFrame.size.height) - rotatedVideoFrame = rotatedVideoFrame.insetBy(dx: -1.0, dy: -1.0) self.videoView.view.center = rotatedVideoFrame.center self.videoView.view.bounds = CGRect(origin: CGPoint(), size: rotatedVideoFrame.size) @@ -198,6 +222,65 @@ final class GroupVideoNode: ASDisplayNode { } } +private final class MainVideoContainerNode: ASDisplayNode { + private let context: AccountContext + private let call: PresentationGroupCall + + private var currentVideoNode: GroupVideoNode? + private var currentPeer: (PeerId, UInt32)? + + private var validLayout: CGSize? + + init(context: AccountContext, call: PresentationGroupCall) { + self.context = context + self.call = call + + super.init() + + self.backgroundColor = .black + } + + func updatePeer(peer: (peerId: PeerId, source: UInt32)?) { + if self.currentPeer?.0 == peer?.0 && self.currentPeer?.1 == peer?.1 { + return + } + self.currentPeer = peer + if let (peerId, source) = peer { + self.call.makeIncomingVideoView(source: source, completion: { [weak self] videoView in + Queue.mainQueue().async { + 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) + } + } + }) + } else { + if let currentVideoNode = self.currentVideoNode { + currentVideoNode.removeFromSupernode() + self.currentVideoNode = nil + } + } + } + + func update(size: CGSize, transition: ContainedViewLayoutTransition) { + self.validLayout = size + + if let currentVideoNode = self.currentVideoNode { + transition.updateFrame(node: currentVideoNode, frame: CGRect(origin: CGPoint(), size: size)) + currentVideoNode.updateLayout(size: size, transition: .immediate) + } + } +} + public final class VoiceChatController: ViewController { private final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate { private struct ListTransition { @@ -256,9 +339,9 @@ public final class VoiceChatController: ViewController { } } - func updateAudioLevels(_ levels: [(PeerId, Float, Bool)], reset: Bool = false) { + func updateAudioLevels(_ levels: [(PeerId, UInt32, Float, Bool)], reset: Bool = false) { var updated = Set() - for (peerId, level, _) in levels { + for (peerId, _, level, _) in levels { if let pipe = self.audioLevels[peerId] { if reset { pipe.putNext(level) @@ -472,6 +555,7 @@ public final class VoiceChatController: ViewController { private let dimNode: ASDisplayNode private let contentContainer: ASDisplayNode private let backgroundNode: ASDisplayNode + private let mainVideoContainer: MainVideoContainerNode private let listNode: ListView private let topPanelNode: ASDisplayNode private let topPanelEdgeNode: ASDisplayNode @@ -544,7 +628,9 @@ public final class VoiceChatController: ViewController { private let voiceSourcesDisposable = MetaDisposable() private var requestedVideoSources = Set() - private var videoNodes: [(UInt32, GroupVideoNode)] = [] + private var videoNodes: [(PeerId, UInt32, GroupVideoNode)] = [] + + private var currentDominantSpeakerWithVideo: (PeerId, UInt32)? init(controller: VoiceChatController, sharedContext: SharedAccountContext, call: PresentationGroupCall) { self.controller = controller @@ -566,6 +652,8 @@ public final class VoiceChatController: ViewController { self.backgroundNode.backgroundColor = secondaryPanelBackgroundColor self.backgroundNode.clipsToBounds = false + self.mainVideoContainer = MainVideoContainerNode(context: call.accountContext, call: call) + self.listNode = ListView() self.listNode.verticalScrollIndicatorColor = UIColor(white: 1.0, alpha: 0.3) self.listNode.clipsToBounds = true @@ -988,7 +1076,7 @@ public final class VoiceChatController: ViewController { guard let strongSelf = self else { return nil } - for (listSsrc, videoNode) in strongSelf.videoNodes { + for (_, listSsrc, videoNode) in strongSelf.videoNodes { if listSsrc == ssrc { return videoNode } @@ -1014,6 +1102,7 @@ public final class VoiceChatController: ViewController { self.contentContainer.addSubnode(self.backgroundNode) self.contentContainer.addSubnode(self.listNode) + self.contentContainer.addSubnode(self.mainVideoContainer) self.contentContainer.addSubnode(self.topPanelNode) self.contentContainer.addSubnode(self.leftBorderNode) self.contentContainer.addSubnode(self.rightBorderNode) @@ -1161,6 +1250,28 @@ public final class VoiceChatController: ViewController { if strongSelf.effectiveMuteState != nil { levels = levels.filter { $0.0 != strongSelf.context.account.peerId } } + + var maxLevelWithVideo: (PeerId, UInt32, Float)? + for (peerId, source, level, hasSpeech) in levels { + if hasSpeech && source != 0 { + if let (_, _, currentLevel) = maxLevelWithVideo { + if currentLevel < level { + maxLevelWithVideo = (peerId, source, level) + } + } else { + maxLevelWithVideo = (peerId, source, level) + } + } + } + + if let (peerId, source, _) = maxLevelWithVideo { + 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.itemInteraction?.updateAudioLevels(levels) }) @@ -1296,17 +1407,19 @@ public final class VoiceChatController: ViewController { return } var validSources = Set() - for source in sources { + for (peerId, source) in sources { validSources.insert(source) if !strongSelf.requestedVideoSources.contains(source) { strongSelf.requestedVideoSources.insert(source) - strongSelf.call.makeIncomingVideoView(source: source, completion: { videoView in + strongSelf.call.makeIncomingVideoView(source: source, completion: { videoView in Queue.mainQueue().async { guard let strongSelf = self, let videoView = videoView else { return } - strongSelf.videoNodes.append((source, GroupVideoNode(videoView: videoView))) + let videoNode = GroupVideoNode(videoView: videoView) + strongSelf.videoNodes.append((peerId, source, videoNode)) + //strongSelf.addSubnode(videoNode) if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate) @@ -1331,12 +1444,15 @@ public final class VoiceChatController: ViewController { var updated = false for i in (0 ..< strongSelf.videoNodes.count).reversed() { - if !validSources.contains(strongSelf.videoNodes[i].0) { + if !validSources.contains(strongSelf.videoNodes[i].1) { + let ssrc = strongSelf.videoNodes[i].1 + strongSelf.videoNodes.remove(at: i) + loop: for j in 0 ..< strongSelf.currentEntries.count { let entry = strongSelf.currentEntries[j] switch entry { case let .peer(peerEntry): - if peerEntry.ssrc == strongSelf.videoNodes[i].0 { + if peerEntry.ssrc == ssrc { let presentationData = strongSelf.presentationData.withUpdated(theme: strongSelf.darkTheme) strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [ListViewUpdateItem(index: i, previousIndex: i, item: entry.item(context: strongSelf.context, presentationData: presentationData, interaction: strongSelf.itemInteraction!), directionHint: nil)], options: [.Synchronous], updateOpaqueState: nil) break loop @@ -1346,18 +1462,28 @@ public final class VoiceChatController: ViewController { } } - //strongSelf.videoNodes[i].1.removeFromSupernode() - strongSelf.videoNodes.remove(at: i) + //strongSelf.videoNodes[i].2.removeFromSupernode() updated = true } } + if let (_, source) = strongSelf.currentDominantSpeakerWithVideo { + if !validSources.contains(source) { + strongSelf.currentDominantSpeakerWithVideo = nil + strongSelf.call.setFullSizeVideo(peerId: nil) + strongSelf.mainVideoContainer.updatePeer(peer: nil) + } + } + if updated { if let (layout, navigationHeight) = strongSelf.validLayout { strongSelf.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .immediate) } } })) + + self.isFullscreen = true + self.isExpanded = true } deinit { @@ -1501,7 +1627,7 @@ public final class VoiceChatController: ViewController { self.call.setIsMuted(action: .muted(isPushToTalkActive: false)) } - self.itemInteraction?.updateAudioLevels([(self.context.account.peerId, 0.0, false)], reset: true) + self.itemInteraction?.updateAudioLevels([(self.context.account.peerId, 0, 0.0, false)], reset: true) if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.3, curve: .spring)) @@ -1618,6 +1744,10 @@ public final class VoiceChatController: ViewController { let panelOffset = max(layoutTopInset, rawPanelOffset) let topPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: panelOffset), size: CGSize(width: size.width, height: topPanelHeight)) + let videoContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY), size: CGSize(width: layout.size.width, height: 200.0)) + transition.updateFrameAdditive(node: self.mainVideoContainer, frame: videoContainerFrame) + self.mainVideoContainer.update(size: videoContainerFrame.size, transition: transition) + let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY), size: CGSize(width: size.width, height: layout.size.height)) let sideInset: CGFloat = 16.0 let leftBorderFrame = CGRect(origin: CGPoint(x: 0.0, y: topPanelFrame.maxY - 16.0), size: CGSize(width: sideInset, height: layout.size.height)) @@ -1878,7 +2008,7 @@ public final class VoiceChatController: ViewController { } let bottomPanelHeight = bottomAreaHeight + layout.intrinsicInsets.bottom - let listTopInset = layoutTopInset + topPanelHeight + let listTopInset = layoutTopInset + topPanelHeight + 200.0 let listSize = CGSize(width: size.width, height: layout.size.height - listTopInset - bottomPanelHeight) let topInset: CGFloat @@ -1961,7 +2091,7 @@ public final class VoiceChatController: ViewController { self.updateButtons(transition: transition) /*var currentVideoOrigin = CGPoint(x: 4.0, y: (layout.statusBarHeight ?? 0.0) + 4.0) - for (_, videoNode) in self.videoNodes { + for (_, _, videoNode) in self.videoNodes { let videoSize = CGSize(width: 300.0, height: 500.0) if currentVideoOrigin.x + videoSize.width > layout.size.width { currentVideoOrigin.x = 0.0 @@ -2447,6 +2577,14 @@ public final class VoiceChatController: ViewController { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let result = super.hitTest(point, with: event) + + if let result = result { + for (_, _, videoNode) in self.videoNodes { + if videoNode.view === result || result.isDescendant(of: videoNode.view) { + return result + } + } + } if result === self.topPanelNode.view { return self.view diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift index 1b97582734..95baa1220e 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift @@ -199,7 +199,6 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { self.offsetContainerNode = ASDisplayNode() self.avatarNode = AvatarNode(font: avatarFont) - self.avatarNode.isLayerBacked = !smartInvertColorsEnabled() self.avatarNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 40.0, height: 40.0)) self.titleNode = TextNode() @@ -673,22 +672,24 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { }) } - let videoSize = CGSize(width: 38.0, height: 38.0) + let videoSize = CGSize(width: avatarSize, height: avatarSize) let videoNode = item.getVideo() if let current = strongSelf.videoNode, current !== videoNode { current.removeFromSupernode() } - var actionOffset: CGFloat = 0.0 + let actionOffset: CGFloat = 0.0 strongSelf.videoNode = videoNode if let videoNode = videoNode { - videoNode.updateLayout(size: videoSize, transition: .immediate) - if videoNode.supernode !== strongSelf.offsetContainerNode { - strongSelf.offsetContainerNode.addSubnode(videoNode) - } - actionOffset = -videoSize.width - 6.0 - videoNode.frame = CGRect(origin: CGPoint(x: params.width - videoSize.width - 6.0 - params.rightInset, y: (layout.contentSize.height - videoSize.height) / 2.0), size: videoSize) + videoNode.updateLayout(size: videoSize, transition: .immediate) + if videoNode.supernode !== strongSelf.avatarNode { + videoNode.clipsToBounds = true + videoNode.cornerRadius = avatarSize / 2.0 + strongSelf.avatarNode.addSubnode(videoNode) + } + + videoNode.frame = CGRect(origin: CGPoint(), size: videoSize) } let animationSize = CGSize(width: 36.0, height: 36.0) diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 4a4f6d1f90..58c9ce70e8 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -1336,7 +1336,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; [queue dispatch:^{ __strong GroupCallThreadLocalContext *strongSelf = weakSelf; if (strongSelf && strongSelf->_instance) { - strongSelf->_instance->setIncomingVideoOutput(ssrc, sink); + strongSelf->_instance->addIncomingVideoOutput(ssrc, sink); } }]; @@ -1349,7 +1349,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; [queue dispatch:^{ __strong GroupCallThreadLocalContext *strongSelf = weakSelf; if (strongSelf && strongSelf->_instance) { - strongSelf->_instance->setIncomingVideoOutput(ssrc, sink); + strongSelf->_instance->addIncomingVideoOutput(ssrc, sink); } }]; diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 819eddf18f..bca416c0b7 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 819eddf18f0946e50181c42e8f3ac09fb5a25553 +Subproject commit bca416c0b76eac786f01b34e9d09e92df7863168