mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 14:20:20 +00:00
[WIP] Call UI
This commit is contained in:
@@ -17,6 +17,7 @@ import ImageBlur
|
||||
import TelegramVoip
|
||||
import MetalEngine
|
||||
import DeviceAccess
|
||||
import LibYuvBinding
|
||||
|
||||
final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeProtocol {
|
||||
private let sharedContext: SharedAccountContext
|
||||
@@ -45,6 +46,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
var callEnded: ((Bool) -> Void)?
|
||||
var dismissedInteractively: (() -> Void)?
|
||||
var dismissAllTooltips: (() -> Void)?
|
||||
var restoreUIForPictureInPicture: ((@escaping (Bool) -> Void) -> Void)?
|
||||
|
||||
private var emojiKey: (data: Data, resolvedKey: [String])?
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat)?
|
||||
@@ -117,6 +119,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
return
|
||||
}
|
||||
self.back?()
|
||||
self.callScreen.beginPictureInPictureIfPossible()
|
||||
}
|
||||
self.callScreen.closeAction = { [weak self] in
|
||||
guard let self else {
|
||||
@@ -124,6 +127,13 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
}
|
||||
self.dismissedInteractively?()
|
||||
}
|
||||
self.callScreen.restoreUIForPictureInPicture = { [weak self] completion in
|
||||
guard let self else {
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
self.restoreUIForPictureInPicture?(completion)
|
||||
}
|
||||
|
||||
self.callScreenState = PrivateCallScreen.State(
|
||||
lifecycleState: .connecting,
|
||||
@@ -312,6 +322,9 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
case let .active(startTime, signalQuality, keyData):
|
||||
self.callStartTimestamp = startTime
|
||||
|
||||
var signalQuality = signalQuality
|
||||
signalQuality = 4
|
||||
|
||||
let _ = keyData
|
||||
mappedLifecycleState = .active(PrivateCallScreen.State.ActiveState(
|
||||
startTime: startTime + kCFAbsoluteTimeIntervalSince1970,
|
||||
@@ -322,7 +335,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
let _ = keyData
|
||||
mappedLifecycleState = .active(PrivateCallScreen.State.ActiveState(
|
||||
startTime: startTime + kCFAbsoluteTimeIntervalSince1970,
|
||||
signalInfo: PrivateCallScreen.State.SignalInfo(quality: 0.0),
|
||||
signalInfo: PrivateCallScreen.State.SignalInfo(quality: 1.0),
|
||||
emojiKey: self.resolvedEmojiKey(data: keyData)
|
||||
))
|
||||
case .terminating, .terminated:
|
||||
@@ -518,6 +531,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
self.callScreen.update(
|
||||
size: layout.size,
|
||||
insets: layout.insets(options: [.statusBar]),
|
||||
interfaceOrientation: layout.metrics.orientation ?? .portrait,
|
||||
screenCornerRadius: layout.deviceMetrics.screenCornerRadius,
|
||||
state: callScreenState,
|
||||
transition: Transition(transition)
|
||||
@@ -526,7 +540,100 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
}
|
||||
}
|
||||
|
||||
private func copyI420BufferToNV12Buffer(buffer: OngoingGroupCallContext.VideoFrameData.I420Buffer, pixelBuffer: CVPixelBuffer) -> Bool {
|
||||
guard CVPixelBufferGetPixelFormatType(pixelBuffer) == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange else {
|
||||
return false
|
||||
}
|
||||
guard CVPixelBufferGetWidthOfPlane(pixelBuffer, 0) == buffer.width else {
|
||||
return false
|
||||
}
|
||||
guard CVPixelBufferGetHeightOfPlane(pixelBuffer, 0) == buffer.height else {
|
||||
return false
|
||||
}
|
||||
|
||||
let cvRet = CVPixelBufferLockBaseAddress(pixelBuffer, [])
|
||||
if cvRet != kCVReturnSuccess {
|
||||
return false
|
||||
}
|
||||
defer {
|
||||
CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
|
||||
}
|
||||
|
||||
guard let dstY = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0) else {
|
||||
return false
|
||||
}
|
||||
let dstStrideY = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0)
|
||||
|
||||
guard let dstUV = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1) else {
|
||||
return false
|
||||
}
|
||||
let dstStrideUV = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 1)
|
||||
|
||||
buffer.y.withUnsafeBytes { srcYBuffer in
|
||||
guard let srcY = srcYBuffer.baseAddress else {
|
||||
return
|
||||
}
|
||||
buffer.u.withUnsafeBytes { srcUBuffer in
|
||||
guard let srcU = srcUBuffer.baseAddress else {
|
||||
return
|
||||
}
|
||||
buffer.v.withUnsafeBytes { srcVBuffer in
|
||||
guard let srcV = srcVBuffer.baseAddress else {
|
||||
return
|
||||
}
|
||||
libyuv_I420ToNV12(
|
||||
srcY.assumingMemoryBound(to: UInt8.self),
|
||||
Int32(buffer.strideY),
|
||||
srcU.assumingMemoryBound(to: UInt8.self),
|
||||
Int32(buffer.strideU),
|
||||
srcV.assumingMemoryBound(to: UInt8.self),
|
||||
Int32(buffer.strideV),
|
||||
dstY.assumingMemoryBound(to: UInt8.self),
|
||||
Int32(dstStrideY),
|
||||
dstUV.assumingMemoryBound(to: UInt8.self),
|
||||
Int32(dstStrideUV),
|
||||
Int32(buffer.width),
|
||||
Int32(buffer.height)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private final class AdaptedCallVideoSource: VideoSource {
|
||||
final class I420DataBuffer: Output.DataBuffer {
|
||||
private let buffer: OngoingGroupCallContext.VideoFrameData.I420Buffer
|
||||
|
||||
override var pixelBuffer: CVPixelBuffer? {
|
||||
let ioSurfaceProperties = NSMutableDictionary()
|
||||
let options = NSMutableDictionary()
|
||||
options.setObject(ioSurfaceProperties, forKey: kCVPixelBufferIOSurfacePropertiesKey as NSString)
|
||||
|
||||
var pixelBuffer: CVPixelBuffer?
|
||||
CVPixelBufferCreate(
|
||||
kCFAllocatorDefault,
|
||||
self.buffer.width,
|
||||
self.buffer.height,
|
||||
kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
|
||||
options,
|
||||
&pixelBuffer
|
||||
)
|
||||
if let pixelBuffer, copyI420BufferToNV12Buffer(buffer: buffer, pixelBuffer: pixelBuffer) {
|
||||
return pixelBuffer
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
init(buffer: OngoingGroupCallContext.VideoFrameData.I420Buffer) {
|
||||
self.buffer = buffer
|
||||
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
private static let queue = Queue(name: "AdaptedCallVideoSource")
|
||||
private var onUpdatedListeners = Bag<() -> Void>()
|
||||
private(set) var currentOutput: Output?
|
||||
@@ -555,6 +662,8 @@ private final class AdaptedCallVideoSource: VideoSource {
|
||||
rotationAngle = Float.pi * 3.0 / 2.0
|
||||
}
|
||||
|
||||
let followsDeviceOrientation = videoFrameData.deviceRelativeOrientation != nil
|
||||
|
||||
var mirrorDirection: Output.MirrorDirection = []
|
||||
|
||||
var sourceId: Int = 0
|
||||
@@ -616,12 +725,45 @@ private final class AdaptedCallVideoSource: VideoSource {
|
||||
|
||||
output = Output(
|
||||
resolution: CGSize(width: CGFloat(yTexture.width), height: CGFloat(yTexture.height)),
|
||||
y: yTexture,
|
||||
uv: uvTexture,
|
||||
textureLayout: .biPlanar(Output.BiPlanarTextureLayout(
|
||||
y: yTexture,
|
||||
uv: uvTexture
|
||||
)),
|
||||
dataBuffer: Output.NativeDataBuffer(pixelBuffer: nativeBuffer.pixelBuffer),
|
||||
rotationAngle: rotationAngle,
|
||||
followsDeviceOrientation: followsDeviceOrientation,
|
||||
mirrorDirection: mirrorDirection,
|
||||
sourceId: sourceId
|
||||
)
|
||||
case let .i420(i420Buffer):
|
||||
let width = i420Buffer.width
|
||||
let height = i420Buffer.height
|
||||
|
||||
let _ = width
|
||||
let _ = height
|
||||
return
|
||||
|
||||
/*var cvMetalTextureY: CVMetalTexture?
|
||||
var status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, nativeBuffer.pixelBuffer, nil, .r8Unorm, width, height, 0, &cvMetalTextureY)
|
||||
guard status == kCVReturnSuccess, let yTexture = CVMetalTextureGetTexture(cvMetalTextureY!) else {
|
||||
return
|
||||
}
|
||||
var cvMetalTextureUV: CVMetalTexture?
|
||||
status = CVMetalTextureCacheCreateTextureFromImage(nil, textureCache, nativeBuffer.pixelBuffer, nil, .rg8Unorm, width / 2, height / 2, 1, &cvMetalTextureUV)
|
||||
guard status == kCVReturnSuccess, let uvTexture = CVMetalTextureGetTexture(cvMetalTextureUV!) else {
|
||||
return
|
||||
}
|
||||
|
||||
output = Output(
|
||||
resolution: CGSize(width: CGFloat(yTexture.width), height: CGFloat(yTexture.height)),
|
||||
y: yTexture,
|
||||
uv: uvTexture,
|
||||
dataBuffer: Output.NativeDataBuffer(pixelBuffer: nativeBuffer.pixelBuffer),
|
||||
rotationAngle: rotationAngle,
|
||||
followsDeviceOrientation: followsDeviceOrientation,
|
||||
mirrorDirection: mirrorDirection,
|
||||
sourceId: sourceId
|
||||
)*/
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user