mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 11:23:48 +00:00
Video streaming improvements
This commit is contained in:
parent
0d424f1663
commit
87f9b5d861
@ -489,8 +489,12 @@ public final class MediaStreamComponent: CombinedComponent {
|
||||
private(set) var displayUI: Bool = true
|
||||
var dismissOffset: CGFloat = 0.0
|
||||
|
||||
var storedIsLandscape: Bool?
|
||||
|
||||
let isPictureInPictureSupported: Bool
|
||||
|
||||
private var scheduledDismissUITimer: SwiftSignalKit.Timer?
|
||||
|
||||
init(call: PresentationGroupCallImpl) {
|
||||
self.call = call
|
||||
|
||||
@ -551,6 +555,26 @@ public final class MediaStreamComponent: CombinedComponent {
|
||||
self.updated(transition: Transition(animation: .curve(duration: 0.4, curve: .easeInOut)))
|
||||
}
|
||||
|
||||
func cancelScheduledDismissUI() {
|
||||
self.scheduledDismissUITimer?.invalidate()
|
||||
self.scheduledDismissUITimer = nil
|
||||
}
|
||||
|
||||
func scheduleDismissUI() {
|
||||
if self.scheduledDismissUITimer == nil {
|
||||
self.scheduledDismissUITimer = SwiftSignalKit.Timer(timeout: 5.0, repeat: false, completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.scheduledDismissUITimer = nil
|
||||
if strongSelf.displayUI {
|
||||
strongSelf.toggleDisplayUI()
|
||||
}
|
||||
}, queue: .mainQueue())
|
||||
self.scheduledDismissUITimer?.start()
|
||||
}
|
||||
}
|
||||
|
||||
func updateDismissOffset(value: CGFloat, interactive: Bool) {
|
||||
self.dismissOffset = value
|
||||
if interactive {
|
||||
@ -575,7 +599,8 @@ public final class MediaStreamComponent: CombinedComponent {
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
|
||||
if !environment.isVisible {
|
||||
if environment.isVisible {
|
||||
} else {
|
||||
context.state.dismissOffset = 0.0
|
||||
}
|
||||
|
||||
@ -675,6 +700,14 @@ public final class MediaStreamComponent: CombinedComponent {
|
||||
)
|
||||
|
||||
let isLandscape = context.availableSize.width > context.availableSize.height
|
||||
if context.state.storedIsLandscape != isLandscape {
|
||||
context.state.storedIsLandscape = isLandscape
|
||||
if isLandscape {
|
||||
context.state.scheduleDismissUI()
|
||||
} else {
|
||||
context.state.cancelScheduledDismissUI()
|
||||
}
|
||||
}
|
||||
|
||||
var infoItem: AnyComponent<Empty>?
|
||||
if let originInfo = context.state.originInfo {
|
||||
@ -815,6 +848,10 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
|
||||
self.onViewDidAppear?()
|
||||
}
|
||||
|
||||
if let view = self.node.hostView.findTaggedView(tag: MediaStreamVideoComponent.View.Tag()) as? MediaStreamVideoComponent.View {
|
||||
view.expandFromPictureInPicture()
|
||||
}
|
||||
|
||||
self.view.layer.allowsGroupOpacity = true
|
||||
self.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { [weak self] _ in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -39,7 +39,10 @@ final class MediaStreamVideoComponent: Component {
|
||||
return State()
|
||||
}
|
||||
|
||||
public final class View: UIView, AVPictureInPictureControllerDelegate, AVPictureInPictureSampleBufferPlaybackDelegate {
|
||||
public final class View: UIView, AVPictureInPictureControllerDelegate, AVPictureInPictureSampleBufferPlaybackDelegate, ComponentTaggedView {
|
||||
public final class Tag {
|
||||
}
|
||||
|
||||
private let videoRenderingContext = VideoRenderingContext()
|
||||
private var videoView: VideoRenderingView?
|
||||
private let blurTintView: UIView
|
||||
@ -49,6 +52,7 @@ final class MediaStreamVideoComponent: Component {
|
||||
private var pictureInPictureController: AVPictureInPictureController?
|
||||
|
||||
private var component: MediaStreamVideoComponent?
|
||||
private var hadVideo: Bool = false
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.blurTintView = UIView()
|
||||
@ -66,6 +70,17 @@ final class MediaStreamVideoComponent: Component {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
public func matches(tag: Any) -> Bool {
|
||||
if let _ = tag as? Tag {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func expandFromPictureInPicture() {
|
||||
self.pictureInPictureController?.stopPictureInPicture()
|
||||
}
|
||||
|
||||
func update(component: MediaStreamVideoComponent, availableSize: CGSize, state: State, transition: Transition) -> CGSize {
|
||||
if component.hasVideo, self.videoView == nil {
|
||||
if let input = component.call.video(endpointId: "unified") {
|
||||
@ -80,11 +95,12 @@ final class MediaStreamVideoComponent: Component {
|
||||
|
||||
if #available(iOSApplicationExtension 15.0, iOS 15.0, *), AVPictureInPictureController.isPictureInPictureSupported(), let sampleBufferVideoView = videoView as? SampleBufferVideoRenderingView {
|
||||
let pictureInPictureController = AVPictureInPictureController(contentSource: AVPictureInPictureController.ContentSource(sampleBufferDisplayLayer: sampleBufferVideoView.sampleBufferLayer, playbackDelegate: self))
|
||||
self.pictureInPictureController = pictureInPictureController
|
||||
|
||||
pictureInPictureController.delegate = self
|
||||
pictureInPictureController.canStartPictureInPictureAutomaticallyFromInline = true
|
||||
pictureInPictureController.requiresLinearPlayback = true
|
||||
pictureInPictureController.delegate = self
|
||||
|
||||
self.pictureInPictureController = pictureInPictureController
|
||||
}
|
||||
|
||||
videoView.setOnOrientationUpdated { [weak state] _, _ in
|
||||
@ -95,6 +111,7 @@ final class MediaStreamVideoComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.hadVideo = true
|
||||
strongSelf.activityIndicatorView?.removeFromSuperview()
|
||||
strongSelf.activityIndicatorView = nil
|
||||
|
||||
@ -120,7 +137,9 @@ final class MediaStreamVideoComponent: Component {
|
||||
videoBlurView.updateIsEnabled(true)
|
||||
transition.withAnimation(.none).setFrame(view: videoBlurView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - blurredVideoSize.width) / 2.0), y: floor((availableSize.height - blurredVideoSize.height) / 2.0)), size: blurredVideoSize), completion: nil)
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if !self.hadVideo {
|
||||
var activityIndicatorTransition = transition
|
||||
let activityIndicatorView: ComponentHostView<Empty>
|
||||
if let current = self.activityIndicatorView {
|
||||
|
@ -78,12 +78,12 @@ open class ViewControllerComponentContainer: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private final class Node: ViewControllerTracingNode {
|
||||
final class Node: ViewControllerTracingNode {
|
||||
private var presentationData: PresentationData
|
||||
private weak var controller: ViewControllerComponentContainer?
|
||||
|
||||
private let component: AnyComponent<ViewControllerComponentContainer.Environment>
|
||||
private let hostView: ComponentHostView<ViewControllerComponentContainer.Environment>
|
||||
let hostView: ComponentHostView<ViewControllerComponentContainer.Environment>
|
||||
|
||||
private var currentIsVisible: Bool = false
|
||||
private var currentLayout: ContainerViewLayout?
|
||||
@ -137,7 +137,7 @@ open class ViewControllerComponentContainer: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private var node: Node {
|
||||
var node: Node {
|
||||
return self.displayNode as! Node
|
||||
}
|
||||
|
||||
|
@ -1684,7 +1684,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
strongSelf.processMyAudioLevel(level: mappedLevel, hasVoice: myLevelHasVoice)
|
||||
strongSelf.isSpeakingPromise.set(orignalMyLevelHasVoice)
|
||||
|
||||
if !missingSsrcs.isEmpty {
|
||||
if !missingSsrcs.isEmpty && !strongSelf.isStream {
|
||||
strongSelf.participantsContext?.ensureHaveParticipants(ssrcs: missingSsrcs)
|
||||
}
|
||||
}))
|
||||
@ -2235,6 +2235,14 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
|
||||
private func beginTone(tone: PresentationCallTone) {
|
||||
if self.isStream {
|
||||
switch tone {
|
||||
case .groupJoined, .groupLeft:
|
||||
return
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
var completed: (() -> Void)?
|
||||
let toneRenderer = PresentationCallToneRenderer(tone: tone, completed: {
|
||||
completed?()
|
||||
|
Loading…
x
Reference in New Issue
Block a user