Update video

This commit is contained in:
Ali 2020-06-23 12:52:51 +04:00
parent d538c89674
commit 5fa82a72ea
15 changed files with 1899 additions and 1812 deletions

View File

@ -5627,3 +5627,5 @@ Any member of this group will be able to see messages in the channel.";
"PrivacySettings.AutoArchiveTitle" = "NEW CHATS FROM UNKNOWN USERS"; "PrivacySettings.AutoArchiveTitle" = "NEW CHATS FROM UNKNOWN USERS";
"PrivacySettings.AutoArchive" = "Archive and Mute"; "PrivacySettings.AutoArchive" = "Archive and Mute";
"PrivacySettings.AutoArchiveInfo" = "Automatically archive and mute new chats, groups and channels from non-contacts."; "PrivacySettings.AutoArchiveInfo" = "Automatically archive and mute new chats, groups and channels from non-contacts.";
"Call.RemoteVideoPaused" = "%@'s video paused";

View File

@ -189,7 +189,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
messageText = invoice.title messageText = invoice.title
case let action as TelegramMediaAction: case let action as TelegramMediaAction:
switch action.action { switch action.action {
case let .phoneCall(_, discardReason, _, _): case let .phoneCall(_, discardReason, _, isVideo):
hideAuthor = !isPeerGroup hideAuthor = !isPeerGroup
let incoming = message.flags.contains(.Incoming) let incoming = message.flags.contains(.Incoming)
if let discardReason = discardReason { if let discardReason = discardReason {
@ -205,11 +205,19 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
if messageText.isEmpty { if messageText.isEmpty {
if incoming { if incoming {
if isVideo {
messageText = strings.Notification_VideoCallIncoming
} else {
messageText = strings.Notification_CallIncoming messageText = strings.Notification_CallIncoming
}
} else {
if isVideo {
messageText = strings.Notification_VideoCallOutgoing
} else { } else {
messageText = strings.Notification_CallOutgoing messageText = strings.Notification_CallOutgoing
} }
} }
}
default: default:
hideAuthor = true hideAuthor = true
if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId) { if let text = plainServiceMessageString(strings: strings, nameDisplayOrder: nameDisplayOrder, message: message, accountPeerId: accountPeerId) {

View File

@ -11,7 +11,7 @@ enum CallControllerButtonType {
case accept case accept
case speaker case speaker
case bluetooth case bluetooth
case video case switchCamera
} }
private let buttonSize = CGSize(width: 75.0, height: 75.0) private let buttonSize = CGSize(width: 75.0, height: 75.0)
@ -124,8 +124,8 @@ final class CallControllerButtonNode: HighlightTrackingButtonNode {
regularImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: .clear) regularImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: .clear)
highlightedImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: emptyHighlightedFill) highlightedImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: emptyHighlightedFill)
filledImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: nil, fillColor: invertedFill, knockout: true) filledImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: nil, fillColor: invertedFill, knockout: true)
case .video: case .switchCamera:
let patternImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconVideo"), color: .white) let patternImage = generateTintedImage(image: UIImage(bundleImageName: "Call/CallSwitchCameraButton"), color: .white)
regularImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: .clear) regularImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: .clear)
highlightedImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: emptyHighlightedFill) highlightedImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: emptyHighlightedFill)
filledImage = generateEmptyButtonImage(icon: patternImage, strokeColor: nil, fillColor: invertedFill, knockout: true) filledImage = generateEmptyButtonImage(icon: patternImage, strokeColor: nil, fillColor: invertedFill, knockout: true)
@ -215,8 +215,8 @@ final class CallControllerButtonNode: HighlightTrackingButtonNode {
regularImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: .clear) regularImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: .clear)
highlightedImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: emptyHighlightedFill) highlightedImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: emptyStroke, fillColor: emptyHighlightedFill)
filledImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: nil, fillColor: invertedFill, knockout: true) filledImage = generateEmptyButtonImage(icon: UIImage(bundleImageName: "Call/CallBluetoothButton"), strokeColor: nil, fillColor: invertedFill, knockout: true)
case .video: case .switchCamera:
let patternImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconVideo"), color: .white) let patternImage = generateTintedImage(image: UIImage(bundleImageName: "Call/CallSwitchCameraButton"), color: .white)
regularImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: .clear) regularImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: .clear)
highlightedImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: emptyHighlightedFill) highlightedImage = generateEmptyButtonImage(icon: patternImage, strokeColor: emptyStroke, fillColor: emptyHighlightedFill)
filledImage = generateEmptyButtonImage(icon: patternImage, strokeColor: nil, fillColor: invertedFill, knockout: true) filledImage = generateEmptyButtonImage(icon: patternImage, strokeColor: nil, fillColor: invertedFill, knockout: true)

View File

@ -32,6 +32,7 @@ final class CallControllerButtonsNode: ASDisplayNode {
private let muteButton: CallControllerButtonNode private let muteButton: CallControllerButtonNode
private let endButton: CallControllerButtonNode private let endButton: CallControllerButtonNode
private let speakerButton: CallControllerButtonNode private let speakerButton: CallControllerButtonNode
private let swichCameraButton: CallControllerButtonNode
private var mode: CallControllerButtonsMode? private var mode: CallControllerButtonsMode?
@ -48,6 +49,7 @@ final class CallControllerButtonsNode: ASDisplayNode {
var end: (() -> Void)? var end: (() -> Void)?
var speaker: (() -> Void)? var speaker: (() -> Void)?
var toggleVideo: (() -> Void)? var toggleVideo: (() -> Void)?
var rotateCamera: (() -> Void)?
init(strings: PresentationStrings) { init(strings: PresentationStrings) {
self.acceptButton = CallControllerButtonNode(type: .accept, label: strings.Call_Accept) self.acceptButton = CallControllerButtonNode(type: .accept, label: strings.Call_Accept)
@ -61,6 +63,8 @@ final class CallControllerButtonsNode: ASDisplayNode {
self.endButton.alpha = 0.0 self.endButton.alpha = 0.0
self.speakerButton = CallControllerButtonNode(type: .speaker, label: nil) self.speakerButton = CallControllerButtonNode(type: .speaker, label: nil)
self.speakerButton.alpha = 0.0 self.speakerButton.alpha = 0.0
self.swichCameraButton = CallControllerButtonNode(type: .switchCamera, label: nil)
self.swichCameraButton.alpha = 0.0
super.init() super.init()
@ -69,12 +73,14 @@ final class CallControllerButtonsNode: ASDisplayNode {
self.addSubnode(self.muteButton) self.addSubnode(self.muteButton)
self.addSubnode(self.endButton) self.addSubnode(self.endButton)
self.addSubnode(self.speakerButton) self.addSubnode(self.speakerButton)
self.addSubnode(self.swichCameraButton)
self.acceptButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside) self.acceptButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
self.declineButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside) self.declineButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
self.muteButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside) self.muteButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
self.endButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside) self.endButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
self.speakerButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside) self.speakerButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
self.swichCameraButton.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
} }
func updateLayout(constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) { func updateLayout(constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) {
@ -112,8 +118,12 @@ final class CallControllerButtonsNode: ASDisplayNode {
let twoButtonsWidth = 2.0 * buttonSize.width + 1.0 * twoButtonSpacing let twoButtonsWidth = 2.0 * buttonSize.width + 1.0 * twoButtonSpacing
var origin = CGPoint(x: floor((width - threeButtonsWidth) / 2.0), y: 0.0) var origin = CGPoint(x: floor((width - threeButtonsWidth) / 2.0), y: 0.0)
for button in [self.muteButton, self.endButton, self.speakerButton] { for button in [self.muteButton, self.endButton, self.speakerButton] {
transition.updateFrame(node: button, frame: CGRect(origin: origin, size: buttonSize)) transition.updateFrame(node: button, frame: CGRect(origin: origin, size: buttonSize))
if button === self.speakerButton {
transition.updateFrame(node: self.swichCameraButton, frame: CGRect(origin: origin, size: buttonSize))
}
origin.x += buttonSize.width + threeButtonSpacing origin.x += buttonSize.width + threeButtonSpacing
} }
@ -129,16 +139,44 @@ final class CallControllerButtonsNode: ASDisplayNode {
for button in [self.declineButton, self.acceptButton] { for button in [self.declineButton, self.acceptButton] {
button.alpha = 1.0 button.alpha = 1.0
} }
for button in [self.muteButton, self.endButton, self.speakerButton] { for button in [self.muteButton, self.endButton, self.speakerButton, self.swichCameraButton] {
button.alpha = 0.0 button.alpha = 0.0
} }
case let .active(speakerMode, videoState): case let .active(speakerMode, videoState):
for button in [self.muteButton, self.speakerButton] { for button in [self.muteButton] {
if animated && button.alpha.isZero { if animated && button.alpha.isZero {
button.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) button.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
} }
button.alpha = 1.0 button.alpha = 1.0
} }
switch videoState {
case .active, .available:
for button in [self.speakerButton] {
if animated && !button.alpha.isZero {
button.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
}
button.alpha = 0.0
}
for button in [self.swichCameraButton] {
if animated && button.alpha.isZero {
button.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
button.alpha = 1.0
}
case .notAvailable:
for button in [self.swichCameraButton] {
if animated && !button.alpha.isZero {
button.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
}
button.alpha = 0.0
}
for button in [self.speakerButton] {
if animated && button.alpha.isZero {
button.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
button.alpha = 1.0
}
}
var animatingAcceptButton = false var animatingAcceptButton = false
if self.endButton.alpha.isZero { if self.endButton.alpha.isZero {
if animated { if animated {
@ -160,22 +198,6 @@ final class CallControllerButtonsNode: ASDisplayNode {
self.endButton.alpha = 1.0 self.endButton.alpha = 1.0
} }
/*switch videoState {
case .notAvailable:
self.videoButton.alpha = 0.0
case let .available(isEnabled):
self.videoButton.isUserInteractionEnabled = isEnabled
if animated {
self.videoButton.alpha = isEnabled ? 1.0 : 0.5
self.videoButton.layer.animateAlpha(from: 0.0, to: self.videoButton.alpha, duration: 0.2)
} else {
self.videoButton.alpha = isEnabled ? 1.0 : 0.5
}
case .active:
self.videoButton.isUserInteractionEnabled = true
self.videoButton.alpha = 0.0
}*/
if !self.declineButton.alpha.isZero { if !self.declineButton.alpha.isZero {
if animated { if animated {
self.declineButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.declineButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
@ -211,9 +233,9 @@ final class CallControllerButtonsNode: ASDisplayNode {
self.speaker?() self.speaker?()
} else if button === self.acceptButton { } else if button === self.acceptButton {
self.accept?() self.accept?()
}/* else if button === self.videoButton { } else if button === self.swichCameraButton {
self.toggleVideo?() self.rotateCamera?()
}*/ }
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
@ -223,9 +245,12 @@ final class CallControllerButtonsNode: ASDisplayNode {
self.muteButton, self.muteButton,
self.endButton, self.endButton,
self.speakerButton, self.speakerButton,
//self.videoButton self.swichCameraButton
] ]
for button in buttons { for button in buttons {
if button.isHidden || button.alpha.isZero {
continue
}
if let result = button.view.hitTest(self.view.convert(point, to: button.view), with: event) { if let result = button.view.hitTest(self.view.convert(point, to: button.view), with: event) {
return result return result
} }

View File

@ -107,6 +107,7 @@ final class CallControllerNode: ASDisplayNode {
private let backButtonArrowNode: ASImageNode private let backButtonArrowNode: ASImageNode
private let backButtonNode: HighlightableButtonNode private let backButtonNode: HighlightableButtonNode
private let statusNode: CallControllerStatusNode private let statusNode: CallControllerStatusNode
private let videoPausedNode: ImmediateTextNode
private let buttonsNode: CallControllerButtonsNode private let buttonsNode: CallControllerButtonsNode
private var keyPreviewNode: CallControllerKeyPreviewNode? private var keyPreviewNode: CallControllerKeyPreviewNode?
@ -167,6 +168,10 @@ final class CallControllerNode: ASDisplayNode {
self.backButtonNode = HighlightableButtonNode() self.backButtonNode = HighlightableButtonNode()
self.statusNode = CallControllerStatusNode() self.statusNode = CallControllerStatusNode()
self.videoPausedNode = ImmediateTextNode()
self.videoPausedNode.alpha = 0.0
self.buttonsNode = CallControllerButtonsNode(strings: self.presentationData.strings) self.buttonsNode = CallControllerButtonsNode(strings: self.presentationData.strings)
self.keyButtonNode = HighlightableButtonNode() self.keyButtonNode = HighlightableButtonNode()
@ -201,6 +206,7 @@ final class CallControllerNode: ASDisplayNode {
self.containerNode.addSubnode(self.imageNode) self.containerNode.addSubnode(self.imageNode)
self.containerNode.addSubnode(self.dimNode) self.containerNode.addSubnode(self.dimNode)
self.containerNode.addSubnode(self.statusNode) self.containerNode.addSubnode(self.statusNode)
self.containerNode.addSubnode(self.videoPausedNode)
self.containerNode.addSubnode(self.buttonsNode) self.containerNode.addSubnode(self.buttonsNode)
self.containerNode.addSubnode(self.keyButtonNode) self.containerNode.addSubnode(self.keyButtonNode)
self.containerNode.addSubnode(self.backButtonArrowNode) self.containerNode.addSubnode(self.backButtonArrowNode)
@ -226,6 +232,10 @@ final class CallControllerNode: ASDisplayNode {
self?.toggleVideo?() self?.toggleVideo?()
} }
self.buttonsNode.rotateCamera = { [weak self] in
self?.call.switchVideoCamera()
}
self.keyButtonNode.addTarget(self, action: #selector(self.keyPressed), forControlEvents: .touchUpInside) self.keyButtonNode.addTarget(self, action: #selector(self.keyPressed), forControlEvents: .touchUpInside)
self.backButtonNode.addTarget(self, action: #selector(self.backPressed), forControlEvents: .touchUpInside) self.backButtonNode.addTarget(self, action: #selector(self.backPressed), forControlEvents: .touchUpInside)
@ -262,6 +272,8 @@ final class CallControllerNode: ASDisplayNode {
} }
} }
self.videoPausedNode.attributedText = NSAttributedString(string: self.presentationData.strings.Call_RemoteVideoPaused(peer.compactDisplayTitle).0, font: Font.regular(17.0), textColor: .white)
if let (layout, navigationBarHeight) = self.validLayout { if let (layout, navigationBarHeight) = self.validLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
} }
@ -372,6 +384,15 @@ final class CallControllerNode: ASDisplayNode {
isActive = true isActive = true
} }
incomingVideoNode.updateIsBlurred(isBlurred: !isActive) incomingVideoNode.updateIsBlurred(isBlurred: !isActive)
if isActive != self.videoPausedNode.alpha.isZero {
if isActive {
self.videoPausedNode.alpha = 0.0
self.videoPausedNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
} else {
self.videoPausedNode.alpha = 1.0
self.videoPausedNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
}
}
} }
switch callState.state { switch callState.state {
@ -605,6 +626,9 @@ final class CallControllerNode: ASDisplayNode {
let statusHeight = self.statusNode.updateLayout(constrainedWidth: layout.size.width, transition: transition) let statusHeight = self.statusNode.updateLayout(constrainedWidth: layout.size.width, transition: transition)
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusOffset), size: CGSize(width: layout.size.width, height: statusHeight))) transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusOffset), size: CGSize(width: layout.size.width, height: statusHeight)))
let videoPausedSize = self.videoPausedNode.updateLayout(CGSize(width: layout.size.width - 16.0, height: 100.0))
transition.updateFrame(node: self.videoPausedNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - videoPausedSize.width) / 2.0), y: floor((layout.size.height - videoPausedSize.height) / 2.0)), size: videoPausedSize))
self.buttonsNode.updateLayout(constrainedWidth: layout.size.width, transition: transition) self.buttonsNode.updateLayout(constrainedWidth: layout.size.width, transition: transition)
let buttonsOriginY: CGFloat = layout.size.height - (buttonsOffset - 40.0) - buttonsHeight - layout.intrinsicInsets.bottom let buttonsOriginY: CGFloat = layout.size.height - (buttonsOffset - 40.0) - buttonsHeight - layout.intrinsicInsets.bottom
transition.updateFrame(node: self.buttonsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY), size: CGSize(width: layout.size.width, height: buttonsHeight))) transition.updateFrame(node: self.buttonsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY), size: CGSize(width: layout.size.width, height: buttonsHeight)))

View File

@ -473,13 +473,13 @@ public final class PresentationCallImpl: PresentationCall {
} }
case .accepting: case .accepting:
self.callWasActive = true self.callWasActive = true
presentationState = PresentationCallState(state: .connecting(nil), videoState: .notAvailable, remoteVideoState: mappedRemoteVideoState) presentationState = PresentationCallState(state: .connecting(nil), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState)
case .dropping: case .dropping:
presentationState = PresentationCallState(state: .terminating, videoState: .notAvailable, remoteVideoState: mappedRemoteVideoState) presentationState = PresentationCallState(state: .terminating, videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState)
case let .terminated(id, reason, options): case let .terminated(id, reason, options):
presentationState = PresentationCallState(state: .terminated(id, reason, self.callWasActive && (options.contains(.reportRating) || self.shouldPresentCallRating)), videoState: .notAvailable, remoteVideoState: mappedRemoteVideoState) presentationState = PresentationCallState(state: .terminated(id, reason, self.callWasActive && (options.contains(.reportRating) || self.shouldPresentCallRating)), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState)
case let .requesting(ringing): case let .requesting(ringing):
presentationState = PresentationCallState(state: .requesting(ringing), videoState: .notAvailable, remoteVideoState: mappedRemoteVideoState) presentationState = PresentationCallState(state: .requesting(ringing), videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState)
case let .active(_, _, keyVisualHash, _, _, _, _): case let .active(_, _, keyVisualHash, _, _, _, _):
self.callWasActive = true self.callWasActive = true
if let callContextState = callContextState { if let callContextState = callContextState {

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Video.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Video.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -106,7 +106,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode {
case .call: case .call:
imageName = "Peer Info/ButtonCall" imageName = "Peer Info/ButtonCall"
case .videoCall: case .videoCall:
imageName = "Chat/Input/Text/IconVideo" imageName = "Peer Info/ButtonVideo"
case .mute: case .mute:
imageName = "Peer Info/ButtonMute" imageName = "Peer Info/ButtonMute"
case .unmute: case .unmute:

View File

@ -538,7 +538,7 @@ public final class OngoingCallContext {
port: Int32(clamping: server.port), port: Int32(clamping: server.port),
username: username, username: username,
password: password, password: password,
isTurn: false isTurn: true
)) ))
} }
} }

View File

@ -120,6 +120,7 @@ static webrtc::ObjCVideoTrackSource *getObjCVideoSource(const rtc::scoped_refptr
} }
- (void)stopCapture { - (void)stopCapture {
_isActiveUpdated = nil;
[self stopCaptureWithCompletionHandler:nil]; [self stopCaptureWithCompletionHandler:nil];
} }