mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 03:40:18 +00:00
Video call updates
This commit is contained in:
parent
4c7ad2101d
commit
27ac68e341
@ -358,6 +358,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
private var disableActionsUntilTimestamp: Double = 0.0
|
private var disableActionsUntilTimestamp: Double = 0.0
|
||||||
|
|
||||||
|
private var displayedVersionOutdatedAlert: Bool = false
|
||||||
|
|
||||||
var isMuted: Bool = false {
|
var isMuted: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
self.buttonsNode.isMuted = self.isMuted
|
self.buttonsNode.isMuted = self.isMuted
|
||||||
@ -417,9 +419,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
self.containerTransformationNode.clipsToBounds = true
|
self.containerTransformationNode.clipsToBounds = true
|
||||||
|
|
||||||
self.containerNode = ASDisplayNode()
|
self.containerNode = ASDisplayNode()
|
||||||
if self.shouldStayHiddenUntilConnection {
|
|
||||||
self.containerNode.alpha = 0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
self.imageNode = TransformImageNode()
|
self.imageNode = TransformImageNode()
|
||||||
self.imageNode.contentAnimations = [.subsequentUpdates]
|
self.imageNode.contentAnimations = [.subsequentUpdates]
|
||||||
@ -564,7 +563,13 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
|
|
||||||
self.backButtonNode.addTarget(self, action: #selector(self.backPressed), forControlEvents: .touchUpInside)
|
self.backButtonNode.addTarget(self, action: #selector(self.backPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
if !shouldStayHiddenUntilConnection && call.isVideo && call.isOutgoing {
|
if shouldStayHiddenUntilConnection {
|
||||||
|
self.containerNode.alpha = 0.0
|
||||||
|
Queue.mainQueue().after(3.0, { [weak self] in
|
||||||
|
self?.containerNode.alpha = 1.0
|
||||||
|
self?.animateIn()
|
||||||
|
})
|
||||||
|
} else if call.isVideo && call.isOutgoing {
|
||||||
self.containerNode.alpha = 0.0
|
self.containerNode.alpha = 0.0
|
||||||
Queue.mainQueue().after(1.0, { [weak self] in
|
Queue.mainQueue().after(1.0, { [weak self] in
|
||||||
self?.containerNode.alpha = 1.0
|
self?.containerNode.alpha = 1.0
|
||||||
@ -881,8 +886,20 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
case .hungUp, .missed:
|
case .hungUp, .missed:
|
||||||
statusValue = .text(string: self.presentationData.strings.Call_StatusEnded, displayLogo: false)
|
statusValue = .text(string: self.presentationData.strings.Call_StatusEnded, displayLogo: false)
|
||||||
}
|
}
|
||||||
case .error:
|
case let .error(error):
|
||||||
statusValue = .text(string: self.presentationData.strings.Call_StatusFailed, displayLogo: false)
|
let text = self.presentationData.strings.Call_StatusFailed
|
||||||
|
switch error {
|
||||||
|
case .notSupportedByPeer:
|
||||||
|
if !self.displayedVersionOutdatedAlert, let peer = self.peer {
|
||||||
|
self.displayedVersionOutdatedAlert = true
|
||||||
|
|
||||||
|
self.present?(textAlertController(sharedContext: self.sharedContext, title: nil, text: self.presentationData.strings.Call_ParticipantVersionOutdatedError(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).0, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {
|
||||||
|
})]))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
statusValue = .text(string: text, displayLogo: false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
statusValue = .text(string: self.presentationData.strings.Call_StatusEnded, displayLogo: false)
|
statusValue = .text(string: self.presentationData.strings.Call_StatusEnded, displayLogo: false)
|
||||||
@ -1202,6 +1219,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
|
|
||||||
let previewVideoSide = interpolate(from: 350.0, to: 200.0, value: 1.0 - self.pictureInPictureTransitionFraction)
|
let previewVideoSide = interpolate(from: 350.0, to: 200.0, value: 1.0 - self.pictureInPictureTransitionFraction)
|
||||||
var previewVideoSize = layout.size.aspectFitted(CGSize(width: previewVideoSide, height: previewVideoSide))
|
var previewVideoSize = layout.size.aspectFitted(CGSize(width: previewVideoSide, height: previewVideoSide))
|
||||||
|
previewVideoSize = CGSize(width: 30.0, height: 45.0).aspectFitted(previewVideoSize)
|
||||||
if let minimizedVideoNode = minimizedVideoNode {
|
if let minimizedVideoNode = minimizedVideoNode {
|
||||||
switch minimizedVideoNode.currentOrientation {
|
switch minimizedVideoNode.currentOrientation {
|
||||||
case .rotation90, .rotation270:
|
case .rotation90, .rotation270:
|
||||||
@ -1377,6 +1395,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let expandedVideoNode = self.expandedVideoNode {
|
if let expandedVideoNode = self.expandedVideoNode {
|
||||||
|
transition.updateAlpha(node: expandedVideoNode, alpha: 1.0)
|
||||||
var expandedVideoTransition = transition
|
var expandedVideoTransition = transition
|
||||||
if expandedVideoNode.frame.isEmpty || self.disableAnimationForExpandedVideoOnce {
|
if expandedVideoNode.frame.isEmpty || self.disableAnimationForExpandedVideoOnce {
|
||||||
expandedVideoTransition = .immediate
|
expandedVideoTransition = .immediate
|
||||||
@ -1424,6 +1443,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
|
|
||||||
|
|
||||||
if let minimizedVideoNode = self.minimizedVideoNode {
|
if let minimizedVideoNode = self.minimizedVideoNode {
|
||||||
|
transition.updateAlpha(node: minimizedVideoNode, alpha: pipTransitionAlpha)
|
||||||
var minimizedVideoTransition = transition
|
var minimizedVideoTransition = transition
|
||||||
var didAppear = false
|
var didAppear = false
|
||||||
if minimizedVideoNode.frame.isEmpty {
|
if minimizedVideoNode.frame.isEmpty {
|
||||||
|
|||||||
@ -508,7 +508,7 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
} else {
|
} else {
|
||||||
if self.isVideo {
|
if self.isVideo {
|
||||||
mappedVideoState = .active
|
mappedVideoState = .active
|
||||||
} else if self.isVideoPossible {
|
} else if self.isVideoPossible && sessionState.isVideoPossible {
|
||||||
mappedVideoState = .inactive
|
mappedVideoState = .inactive
|
||||||
} else {
|
} else {
|
||||||
mappedVideoState = .notAvailable
|
mappedVideoState = .notAvailable
|
||||||
|
|||||||
@ -333,7 +333,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
} else {
|
} else {
|
||||||
for (account, _, state, _, _) in ringingStates {
|
for (account, _, state, _, _) in ringingStates {
|
||||||
if state.id != self.currentCall?.internalId {
|
if state.id != self.currentCall?.internalId {
|
||||||
account.callSessionManager.drop(internalId: state.id, reason: .missed, debugLog: .single(nil))
|
account.callSessionManager.drop(internalId: state.id, reason: .busy, debugLog: .single(nil))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -186,6 +186,7 @@ public struct CallSession {
|
|||||||
public let isOutgoing: Bool
|
public let isOutgoing: Bool
|
||||||
public let type: CallType
|
public let type: CallType
|
||||||
public let state: CallSessionState
|
public let state: CallSessionState
|
||||||
|
public let isVideoPossible: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CallSessionConnection: Equatable {
|
public enum CallSessionConnection: Equatable {
|
||||||
@ -277,7 +278,7 @@ private final class CallSessionContext {
|
|||||||
let peerId: PeerId
|
let peerId: PeerId
|
||||||
let isOutgoing: Bool
|
let isOutgoing: Bool
|
||||||
var type: CallSession.CallType
|
var type: CallSession.CallType
|
||||||
let isVideoPossible: Bool
|
var isVideoPossible: Bool
|
||||||
var state: CallSessionInternalState
|
var state: CallSessionInternalState
|
||||||
let subscribers = Bag<(CallSession) -> Void>()
|
let subscribers = Bag<(CallSession) -> Void>()
|
||||||
let signalingSubscribers = Bag<(Data) -> Void>()
|
let signalingSubscribers = Bag<(Data) -> Void>()
|
||||||
@ -412,7 +413,7 @@ private final class CallSessionManagerContext {
|
|||||||
let index = context.subscribers.add { next in
|
let index = context.subscribers.add { next in
|
||||||
subscriber.putNext(next)
|
subscriber.putNext(next)
|
||||||
}
|
}
|
||||||
subscriber.putNext(CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context)))
|
subscriber.putNext(CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible))
|
||||||
disposable.set(ActionDisposable {
|
disposable.set(ActionDisposable {
|
||||||
queue.async {
|
queue.async {
|
||||||
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
||||||
@ -473,7 +474,7 @@ private final class CallSessionManagerContext {
|
|||||||
|
|
||||||
private func contextUpdated(internalId: CallSessionInternalId) {
|
private func contextUpdated(internalId: CallSessionInternalId) {
|
||||||
if let context = self.contexts[internalId] {
|
if let context = self.contexts[internalId] {
|
||||||
let session = CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context))
|
let session = CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible)
|
||||||
for subscriber in context.subscribers.copyItems() {
|
for subscriber in context.subscribers.copyItems() {
|
||||||
subscriber(session)
|
subscriber(session)
|
||||||
}
|
}
|
||||||
@ -526,7 +527,9 @@ private final class CallSessionManagerContext {
|
|||||||
wasRinging = true
|
wasRinging = true
|
||||||
let internalReason: DropCallSessionReason
|
let internalReason: DropCallSessionReason
|
||||||
switch reason {
|
switch reason {
|
||||||
case .busy, .hangUp:
|
case .busy:
|
||||||
|
internalReason = .busy
|
||||||
|
case .hangUp:
|
||||||
internalReason = .hangUp(0)
|
internalReason = .hangUp(0)
|
||||||
case .disconnect:
|
case .disconnect:
|
||||||
internalReason = .disconnect
|
internalReason = .disconnect
|
||||||
@ -804,6 +807,9 @@ private final class CallSessionManagerContext {
|
|||||||
switch callProtocol {
|
switch callProtocol {
|
||||||
case let .phoneCallProtocol(_, _, maxLayer, versions):
|
case let .phoneCallProtocol(_, _, maxLayer, versions):
|
||||||
if !versions.isEmpty {
|
if !versions.isEmpty {
|
||||||
|
let isVideoPossible = self.videoVersions().contains(where: { versions.contains($0) })
|
||||||
|
context.isVideoPossible = isVideoPossible
|
||||||
|
|
||||||
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], allowsP2P: allowsP2P)
|
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: calculatedKeyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], allowsP2P: allowsP2P)
|
||||||
self.contextUpdated(internalId: internalId)
|
self.contextUpdated(internalId: internalId)
|
||||||
} else {
|
} else {
|
||||||
@ -820,6 +826,9 @@ private final class CallSessionManagerContext {
|
|||||||
switch callProtocol {
|
switch callProtocol {
|
||||||
case let .phoneCallProtocol(_, _, maxLayer, versions):
|
case let .phoneCallProtocol(_, _, maxLayer, versions):
|
||||||
if !versions.isEmpty {
|
if !versions.isEmpty {
|
||||||
|
let isVideoPossible = self.videoVersions().contains(where: { versions.contains($0) })
|
||||||
|
context.isVideoPossible = isVideoPossible
|
||||||
|
|
||||||
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], allowsP2P: allowsP2P)
|
context.state = .active(id: id, accessHash: accessHash, beginTimestamp: startDate, key: key, keyId: keyId, keyVisualHash: keyVisualHash, connections: parseConnectionSet(primary: connections.first!, alternative: Array(connections[1...])), maxLayer: maxLayer, version: versions[0], allowsP2P: allowsP2P)
|
||||||
self.contextUpdated(internalId: internalId)
|
self.contextUpdated(internalId: internalId)
|
||||||
} else {
|
} else {
|
||||||
@ -849,7 +858,7 @@ private final class CallSessionManagerContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let context = self.contexts[internalId] {
|
if let context = self.contexts[internalId] {
|
||||||
let callSession = CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context))
|
let callSession = CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible)
|
||||||
if let resultRingingStateValue = resultRingingStateValue {
|
if let resultRingingStateValue = resultRingingStateValue {
|
||||||
resultRingingState = (resultRingingStateValue, callSession)
|
resultRingingState = (resultRingingStateValue, callSession)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -207,7 +207,6 @@
|
|||||||
NSTimeInterval _callPacketTimeout;
|
NSTimeInterval _callPacketTimeout;
|
||||||
|
|
||||||
std::unique_ptr<tgcalls::Instance> _tgVoip;
|
std::unique_ptr<tgcalls::Instance> _tgVoip;
|
||||||
OngoingCallThreadLocalContextWebrtcTerminationResult *_terminationResult;
|
|
||||||
|
|
||||||
OngoingCallStateWebrtc _state;
|
OngoingCallStateWebrtc _state;
|
||||||
OngoingCallVideoStateWebrtc _videoState;
|
OngoingCallVideoStateWebrtc _videoState;
|
||||||
@ -541,29 +540,19 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stopInstanceIfNeeded {
|
|
||||||
if (!_tgVoip) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
tgcalls::FinalState finalState = _tgVoip->stop();
|
|
||||||
_tgVoip.reset();
|
|
||||||
_terminationResult = [[OngoingCallThreadLocalContextWebrtcTerminationResult alloc] initWithFinalState:finalState];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)beginTermination {
|
- (void)beginTermination {
|
||||||
[self stopInstanceIfNeeded];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
- (void)stopWithTerminationResult:(OngoingCallThreadLocalContextWebrtcTerminationResult *)terminationResult completion:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
||||||
[self stopInstanceIfNeeded];
|
_tgVoip.reset();
|
||||||
|
|
||||||
if (completion) {
|
if (completion) {
|
||||||
if (_terminationResult) {
|
if (terminationResult) {
|
||||||
NSString *debugLog = [NSString stringWithUTF8String:_terminationResult.finalState.debugLog.c_str()];
|
NSString *debugLog = [NSString stringWithUTF8String:terminationResult.finalState.debugLog.c_str()];
|
||||||
_lastDerivedState = [[NSData alloc] initWithBytes:_terminationResult.finalState.persistentState.value.data() length:_terminationResult.finalState.persistentState.value.size()];
|
_lastDerivedState = [[NSData alloc] initWithBytes:terminationResult.finalState.persistentState.value.data() length:terminationResult.finalState.persistentState.value.size()];
|
||||||
|
|
||||||
if (completion) {
|
if (completion) {
|
||||||
completion(debugLog, _terminationResult.finalState.trafficStats.bytesSentWifi, _terminationResult.finalState.trafficStats.bytesReceivedWifi, _terminationResult.finalState.trafficStats.bytesSentMobile, _terminationResult.finalState.trafficStats.bytesReceivedMobile);
|
completion(debugLog, terminationResult.finalState.trafficStats.bytesSentWifi, terminationResult.finalState.trafficStats.bytesReceivedWifi, terminationResult.finalState.trafficStats.bytesSentMobile, terminationResult.finalState.trafficStats.bytesReceivedMobile);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (completion) {
|
if (completion) {
|
||||||
@ -573,6 +562,33 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)stop:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion {
|
||||||
|
if (!_tgVoip) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (completion == nil) {
|
||||||
|
_tgVoip->stop([](tgcalls::FinalState finalState) {
|
||||||
|
});
|
||||||
|
_tgVoip.reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__weak OngoingCallThreadLocalContextWebrtc *weakSelf = self;
|
||||||
|
id<OngoingCallThreadLocalContextQueueWebrtc> queue = _queue;
|
||||||
|
_tgVoip->stop([weakSelf, queue, completion = [completion copy]](tgcalls::FinalState finalState) {
|
||||||
|
[queue dispatch:^{
|
||||||
|
__strong OngoingCallThreadLocalContextWebrtc *strongSelf = weakSelf;
|
||||||
|
if (!strongSelf) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OngoingCallThreadLocalContextWebrtcTerminationResult *terminationResult = [[OngoingCallThreadLocalContextWebrtcTerminationResult alloc] initWithFinalState:finalState];
|
||||||
|
|
||||||
|
[strongSelf stopWithTerminationResult:terminationResult completion:completion];
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
- (NSString *)debugInfo {
|
- (NSString *)debugInfo {
|
||||||
if (_tgVoip != nullptr) {
|
if (_tgVoip != nullptr) {
|
||||||
NSString *version = [self version];
|
NSString *version = [self version];
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit e0e9e3934601c53b542e4cca617bb4050a33792b
|
Subproject commit a7d9b717fdf7e8e441b47692dc5771684b2d7970
|
||||||
Loading…
x
Reference in New Issue
Block a user