mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Conference calls
This commit is contained in:
parent
0bb33c215a
commit
1f517e187a
@ -401,6 +401,22 @@ public extension GroupCallParticipantsContext.Participant {
|
||||
}
|
||||
}
|
||||
|
||||
public struct PresentationGroupCallInvitedPeer: Equatable {
|
||||
public enum State {
|
||||
case requesting
|
||||
case ringing
|
||||
case connecting
|
||||
}
|
||||
|
||||
public var id: EnginePeer.Id
|
||||
public var state: State?
|
||||
|
||||
public init(id: EnginePeer.Id, state: State?) {
|
||||
self.id = id
|
||||
self.state = state
|
||||
}
|
||||
}
|
||||
|
||||
public protocol PresentationGroupCall: AnyObject {
|
||||
var account: Account { get }
|
||||
var accountContext: AccountContext { get }
|
||||
@ -468,7 +484,7 @@ public protocol PresentationGroupCall: AnyObject {
|
||||
|
||||
func invitePeer(_ peerId: EnginePeer.Id) -> Bool
|
||||
func removedPeer(_ peerId: EnginePeer.Id)
|
||||
var invitedPeers: Signal<[EnginePeer.Id], NoError> { get }
|
||||
var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> { get }
|
||||
|
||||
var inviteLinks: Signal<GroupCallInviteLinks?, NoError> { get }
|
||||
|
||||
|
@ -470,7 +470,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
}
|
||||
case .busy:
|
||||
mappedReason = .busy
|
||||
case .hungUp:
|
||||
case .hungUp, .switchedToConference:
|
||||
if self.callStartTimestamp != nil {
|
||||
mappedReason = .hangUp
|
||||
} else {
|
||||
@ -687,12 +687,12 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
|
||||
func animateOutToGroupChat(completion: @escaping () -> Void) -> CallController.AnimateOutToGroupChat {
|
||||
self.callScreen.animateOutToGroupChat(completion: completion)
|
||||
|
||||
let takenIncomingVideoLayer = self.callScreen.takeIncomingVideoLayer()
|
||||
let takeSource = self.callScreen.takeIncomingVideoLayer()
|
||||
return CallController.AnimateOutToGroupChat(
|
||||
containerView: self.containerView,
|
||||
incomingPeerId: self.call.peerId,
|
||||
incomingVideoLayer: takenIncomingVideoLayer?.0,
|
||||
incomingVideoPlaceholder: takenIncomingVideoLayer?.1
|
||||
incomingPeerId: (takeSource?.1 ?? true) ? self.call.peerId : self.call.context.account.peerId,
|
||||
incomingVideoLayer: takeSource?.0.0,
|
||||
incomingVideoPlaceholder: takeSource?.0.1
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ final class LegacyCallControllerNode: ASDisplayNode, CallControllerNodeProtocol
|
||||
switch type {
|
||||
case .busy:
|
||||
statusValue = .text(self.presentationData.strings.Call_StatusBusy)
|
||||
case .hungUp, .missed:
|
||||
case .hungUp, .missed, .switchedToConference:
|
||||
statusValue = .text(self.presentationData.strings.Call_StatusEnded)
|
||||
}
|
||||
case .error:
|
||||
|
@ -909,7 +909,7 @@ public final class PresentationCallImpl: PresentationCall {
|
||||
self.conferenceCallImpl = conferenceCall
|
||||
conferenceCall.upgradedConferenceCall = self
|
||||
|
||||
conferenceCall.setInvitedPeers(self.pendingInviteToConferencePeerIds)
|
||||
conferenceCall.setConferenceInvitedPeers(self.pendingInviteToConferencePeerIds)
|
||||
for peerId in self.pendingInviteToConferencePeerIds {
|
||||
let _ = conferenceCall.invitePeer(peerId)
|
||||
}
|
||||
@ -990,8 +990,6 @@ public final class PresentationCallImpl: PresentationCall {
|
||||
return
|
||||
}
|
||||
|
||||
self.ongoingContext?.stop(debugLogValue: Promise())
|
||||
self.ongoingContext = nil
|
||||
self.ongoingContextStateDisposable?.dispose()
|
||||
|
||||
self.conferenceStateValue = .ready
|
||||
@ -1197,6 +1195,8 @@ public final class PresentationCallImpl: PresentationCall {
|
||||
tone = .busy
|
||||
case .hungUp, .missed:
|
||||
tone = .ended
|
||||
case .switchedToConference:
|
||||
tone = nil
|
||||
}
|
||||
case .error:
|
||||
tone = .failed
|
||||
|
@ -731,7 +731,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
guard let groupCall = conferenceSource.conferenceCall else {
|
||||
return
|
||||
}
|
||||
(conferenceSource as! PresentationCallImpl).resetAsMovedToConference()
|
||||
(groupCall as! PresentationGroupCallImpl).moveConferenceCall(source: conferenceSource)
|
||||
self.updateCurrentGroupCall(.group(groupCall))
|
||||
})
|
||||
|
||||
|
@ -601,6 +601,10 @@ private final class ScreencastEmbeddedIPCContext: ScreencastIPCContext {
|
||||
}
|
||||
|
||||
private final class PendingConferenceInvitationContext {
|
||||
enum State {
|
||||
case ringing
|
||||
}
|
||||
|
||||
private let callSessionManager: CallSessionManager
|
||||
private var requestDisposable: Disposable?
|
||||
private var stateDisposable: Disposable?
|
||||
@ -608,7 +612,7 @@ private final class PendingConferenceInvitationContext {
|
||||
|
||||
private var didNotifyEnded: Bool = false
|
||||
|
||||
init(callSessionManager: CallSessionManager, groupCall: GroupCallReference, encryptionKey: Data, peerId: PeerId, onEnded: @escaping () -> Void) {
|
||||
init(callSessionManager: CallSessionManager, groupCall: GroupCallReference, encryptionKey: Data, peerId: PeerId, onStateUpdated: @escaping (State) -> Void, onEnded: @escaping (Bool) -> Void) {
|
||||
self.callSessionManager = callSessionManager
|
||||
|
||||
self.requestDisposable = (callSessionManager.request(peerId: peerId, isVideo: false, enableVideo: true, conferenceCall: (groupCall, encryptionKey))
|
||||
@ -624,10 +628,14 @@ private final class PendingConferenceInvitationContext {
|
||||
return
|
||||
}
|
||||
switch state.state {
|
||||
case .dropping, .terminated:
|
||||
case let .requesting(ringing, _):
|
||||
if ringing {
|
||||
onStateUpdated(.ringing)
|
||||
}
|
||||
case let .dropping(reason), let .terminated(_, reason, _):
|
||||
if !self.didNotifyEnded {
|
||||
self.didNotifyEnded = true
|
||||
onEnded()
|
||||
onEnded(reason == .ended(.switchedToConference))
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -972,15 +980,15 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
return self.membersPromise.get()
|
||||
}
|
||||
|
||||
private var invitedPeersValue: [EnginePeer.Id] = [] {
|
||||
private var invitedPeersValue: [PresentationGroupCallInvitedPeer] = [] {
|
||||
didSet {
|
||||
if self.invitedPeersValue != oldValue {
|
||||
self.inivitedPeersPromise.set(self.invitedPeersValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
private let inivitedPeersPromise = ValuePromise<[EnginePeer.Id]>([])
|
||||
public var invitedPeers: Signal<[EnginePeer.Id], NoError> {
|
||||
private let inivitedPeersPromise = ValuePromise<[PresentationGroupCallInvitedPeer]>([])
|
||||
public var invitedPeers: Signal<[PresentationGroupCallInvitedPeer], NoError> {
|
||||
return self.inivitedPeersPromise.get()
|
||||
}
|
||||
|
||||
@ -1062,14 +1070,13 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
return self.conferenceSourceId
|
||||
}
|
||||
|
||||
var internal_isRemoteConnected = Promise<Bool>()
|
||||
private var internal_isRemoteConnectedDisposable: Disposable?
|
||||
|
||||
public var onMutedSpeechActivityDetected: ((Bool) -> Void)?
|
||||
|
||||
let debugLog = Promise<String?>()
|
||||
|
||||
public weak var upgradedConferenceCall: PresentationCallImpl?
|
||||
public var pendingDisconnedUpgradedConferenceCall: PresentationCallImpl?
|
||||
private var pendingDisconnedUpgradedConferenceCallTimer: Foundation.Timer?
|
||||
private var conferenceInvitationContexts: [PeerId: PendingConferenceInvitationContext] = [:]
|
||||
|
||||
init(
|
||||
@ -1428,14 +1435,10 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
|
||||
self.audioOutputStateDisposable?.dispose()
|
||||
|
||||
self.removedChannelMembersDisposable?.dispose()
|
||||
|
||||
self.peerUpdatesSubscription?.dispose()
|
||||
|
||||
self.screencastStateDisposable?.dispose()
|
||||
|
||||
self.internal_isRemoteConnectedDisposable?.dispose()
|
||||
self.pendingDisconnedUpgradedConferenceCallTimer?.invalidate()
|
||||
}
|
||||
|
||||
private func switchToTemporaryParticipantsContext(sourceContext: GroupCallParticipantsContext?, oldMyPeerId: PeerId) {
|
||||
@ -1529,7 +1532,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
topParticipants.append(participant)
|
||||
}
|
||||
|
||||
if let index = updatedInvitedPeers.firstIndex(of: participant.peer.id) {
|
||||
if let index = updatedInvitedPeers.firstIndex(where: { $0.id == participant.peer.id }) {
|
||||
updatedInvitedPeers.remove(at: index)
|
||||
didUpdateInvitedPeers = true
|
||||
}
|
||||
@ -1986,6 +1989,8 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
lastTimestamp = CFAbsoluteTimeGetCurrent()
|
||||
self.hasActiveIncomingDataValue = true
|
||||
|
||||
self.activateIncomingAudioIfNeeded()
|
||||
})
|
||||
|
||||
self.hasActiveIncomingDataTimer?.invalidate()
|
||||
@ -2002,15 +2007,6 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
})
|
||||
|
||||
self.signalBarsPromise.set(callContext.signalBars)
|
||||
|
||||
self.internal_isRemoteConnectedDisposable = (self.internal_isRemoteConnected.get()
|
||||
|> distinctUntilChanged
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak callContext] isRemoteConnected in
|
||||
guard let callContext else {
|
||||
return
|
||||
}
|
||||
callContext.addRemoteConnectedEvent(isRemoteConntected: isRemoteConnected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -2645,7 +2641,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
|
||||
if let index = updatedInvitedPeers.firstIndex(of: participant.peer.id) {
|
||||
if let index = updatedInvitedPeers.firstIndex(where: { $0.id == participant.peer.id }) {
|
||||
updatedInvitedPeers.remove(at: index)
|
||||
didUpdateInvitedPeers = true
|
||||
}
|
||||
@ -2741,6 +2737,12 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
|
||||
private func activateIncomingAudioIfNeeded() {
|
||||
if let genericCallContext = self.genericCallContext, case let .call(groupCall) = genericCallContext {
|
||||
groupCall.activateIncomingAudio()
|
||||
}
|
||||
}
|
||||
|
||||
private func requestMediaChannelDescriptions(ssrcs: Set<UInt32>, completion: @escaping ([OngoingGroupCallContext.MediaChannelDescription]) -> Void) -> Disposable {
|
||||
func extractMediaChannelDescriptions(remainingSsrcs: inout Set<UInt32>, participants: [GroupCallParticipantsContext.Participant], into result: inout [OngoingGroupCallContext.MediaChannelDescription]) {
|
||||
for participant in participants {
|
||||
@ -3643,42 +3645,68 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
if conferenceInvitationContexts[peerId] != nil {
|
||||
return false
|
||||
}
|
||||
var onEnded: (() -> Void)?
|
||||
var onStateUpdated: ((PendingConferenceInvitationContext.State) -> Void)?
|
||||
var onEnded: ((Bool) -> Void)?
|
||||
var didEndAlready = false
|
||||
let invitationContext = PendingConferenceInvitationContext(
|
||||
callSessionManager: self.accountContext.account.callSessionManager,
|
||||
groupCall: GroupCallReference(id: initialCall.id, accessHash: initialCall.accessHash),
|
||||
encryptionKey: encryptionKey.key,
|
||||
peerId: peerId,
|
||||
onEnded: {
|
||||
onStateUpdated: { state in
|
||||
onStateUpdated?(state)
|
||||
},
|
||||
onEnded: { success in
|
||||
didEndAlready = true
|
||||
onEnded?()
|
||||
onEnded?(success)
|
||||
}
|
||||
)
|
||||
if !didEndAlready {
|
||||
conferenceInvitationContexts[peerId] = invitationContext
|
||||
if !self.invitedPeersValue.contains(peerId) {
|
||||
self.invitedPeersValue.append(peerId)
|
||||
if !self.invitedPeersValue.contains(where: { $0.id == peerId }) {
|
||||
self.invitedPeersValue.append(PresentationGroupCallInvitedPeer(id: peerId, state: .requesting))
|
||||
}
|
||||
onEnded = { [weak self, weak invitationContext] in
|
||||
onStateUpdated = { [weak self] state in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let index = self.invitedPeersValue.firstIndex(where: { $0.id == peerId }) {
|
||||
var invitedPeer = self.invitedPeersValue[index]
|
||||
switch state {
|
||||
case .ringing:
|
||||
invitedPeer.state = .ringing
|
||||
}
|
||||
self.invitedPeersValue[index] = invitedPeer
|
||||
}
|
||||
}
|
||||
onEnded = { [weak self, weak invitationContext] success in
|
||||
guard let self, let invitationContext else {
|
||||
return
|
||||
}
|
||||
if self.conferenceInvitationContexts[peerId] === invitationContext {
|
||||
self.conferenceInvitationContexts.removeValue(forKey: peerId)
|
||||
self.invitedPeersValue.removeAll(where: { $0 == peerId })
|
||||
|
||||
if success {
|
||||
if let index = self.invitedPeersValue.firstIndex(where: { $0.id == peerId }) {
|
||||
var invitedPeer = self.invitedPeersValue[index]
|
||||
invitedPeer.state = .connecting
|
||||
self.invitedPeersValue[index] = invitedPeer
|
||||
}
|
||||
} else {
|
||||
self.invitedPeersValue.removeAll(where: { $0.id == peerId })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
} else {
|
||||
guard let callInfo = self.internalState.callInfo, !self.invitedPeersValue.contains(peerId) else {
|
||||
guard let callInfo = self.internalState.callInfo, !self.invitedPeersValue.contains(where: { $0.id == peerId }) else {
|
||||
return false
|
||||
}
|
||||
|
||||
var updatedInvitedPeers = self.invitedPeersValue
|
||||
updatedInvitedPeers.insert(peerId, at: 0)
|
||||
updatedInvitedPeers.insert(PresentationGroupCallInvitedPeer(id: peerId, state: nil), at: 0)
|
||||
self.invitedPeersValue = updatedInvitedPeers
|
||||
|
||||
let _ = self.accountContext.engine.calls.inviteToGroupCall(callId: callInfo.id, accessHash: callInfo.accessHash, peerId: peerId).start()
|
||||
@ -3687,13 +3715,15 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
}
|
||||
|
||||
func setInvitedPeers(_ peerIds: [PeerId]) {
|
||||
self.invitedPeersValue = peerIds
|
||||
func setConferenceInvitedPeers(_ peerIds: [PeerId]) {
|
||||
self.invitedPeersValue = peerIds.map {
|
||||
PresentationGroupCallInvitedPeer(id: $0, state: .requesting)
|
||||
}
|
||||
}
|
||||
|
||||
public func removedPeer(_ peerId: PeerId) {
|
||||
var updatedInvitedPeers = self.invitedPeersValue
|
||||
updatedInvitedPeers.removeAll(where: { $0 == peerId})
|
||||
updatedInvitedPeers.removeAll(where: { $0.id == peerId})
|
||||
self.invitedPeersValue = updatedInvitedPeers
|
||||
}
|
||||
|
||||
@ -3859,6 +3889,26 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
|
||||
}
|
||||
|> runOn(.mainQueue())
|
||||
}
|
||||
|
||||
func moveConferenceCall(source: PresentationCall) {
|
||||
guard let source = source as? PresentationCallImpl else {
|
||||
return
|
||||
}
|
||||
|
||||
self.pendingDisconnedUpgradedConferenceCall?.resetAsMovedToConference()
|
||||
self.pendingDisconnedUpgradedConferenceCall = source
|
||||
|
||||
self.pendingDisconnedUpgradedConferenceCallTimer?.invalidate()
|
||||
self.pendingDisconnedUpgradedConferenceCallTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false, block: { [weak self] _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let pendingDisconnedUpgradedConferenceCall = self.pendingDisconnedUpgradedConferenceCall {
|
||||
self.pendingDisconnedUpgradedConferenceCall = nil
|
||||
pendingDisconnedUpgradedConferenceCall.resetAsMovedToConference()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private protocol ScreencastContext: AnyObject {
|
||||
|
@ -428,6 +428,15 @@ final class VideoChatParticipantVideoComponent: Component {
|
||||
alphaTransition.setAlpha(view: titleView, alpha: controlsAlpha)
|
||||
}
|
||||
|
||||
var previousVideoDescription: GroupCallParticipantsContext.Participant.VideoDescription?
|
||||
if let previousComponent {
|
||||
if previousComponent.isMyPeer && previousComponent.isPresentation {
|
||||
previousVideoDescription = nil
|
||||
} else {
|
||||
previousVideoDescription = previousComponent.maxVideoQuality == 0 ? nil : (previousComponent.isPresentation ? previousComponent.participant.presentationDescription : previousComponent.participant.videoDescription)
|
||||
}
|
||||
}
|
||||
|
||||
let videoDescription: GroupCallParticipantsContext.Participant.VideoDescription?
|
||||
if component.isMyPeer && component.isPresentation {
|
||||
videoDescription = nil
|
||||
@ -506,8 +515,13 @@ final class VideoChatParticipantVideoComponent: Component {
|
||||
}
|
||||
|
||||
let videoLayer: PrivateCallVideoLayer
|
||||
var resetVideoSource = false
|
||||
if let current = self.videoLayer {
|
||||
videoLayer = current
|
||||
|
||||
if let previousVideoDescription, previousVideoDescription.endpointId != videoDescription.endpointId {
|
||||
resetVideoSource = true
|
||||
}
|
||||
} else {
|
||||
videoLayer = PrivateCallVideoLayer()
|
||||
self.videoLayer = videoLayer
|
||||
@ -517,6 +531,10 @@ final class VideoChatParticipantVideoComponent: Component {
|
||||
|
||||
videoLayer.blurredLayer.opacity = 0.0
|
||||
|
||||
resetVideoSource = true
|
||||
}
|
||||
|
||||
if resetVideoSource {
|
||||
if let input = component.call.video(endpointId: videoDescription.endpointId) {
|
||||
let videoSource = AdaptedCallVideoSource(videoStreamSignal: input)
|
||||
self.videoSource = videoSource
|
||||
|
@ -128,7 +128,7 @@ final class VideoChatParticipantsComponent: Component {
|
||||
|
||||
let call: VideoChatCall
|
||||
let participants: Participants?
|
||||
let invitedPeers: [EnginePeer]
|
||||
let invitedPeers: [VideoChatScreenComponent.InvitedPeer]
|
||||
let speakingParticipants: Set<EnginePeer.Id>
|
||||
let expandedVideoState: ExpandedVideoState?
|
||||
let maxVideoQuality: Int
|
||||
@ -148,7 +148,7 @@ final class VideoChatParticipantsComponent: Component {
|
||||
init(
|
||||
call: VideoChatCall,
|
||||
participants: Participants?,
|
||||
invitedPeers: [EnginePeer],
|
||||
invitedPeers: [VideoChatScreenComponent.InvitedPeer],
|
||||
speakingParticipants: Set<EnginePeer.Id>,
|
||||
expandedVideoState: ExpandedVideoState?,
|
||||
maxVideoQuality: Int,
|
||||
@ -1259,10 +1259,20 @@ final class VideoChatParticipantsComponent: Component {
|
||||
)
|
||||
} else {
|
||||
let invitedPeer = component.invitedPeers[i - self.listParticipants.count]
|
||||
participantPeerId = invitedPeer.id
|
||||
participantPeerId = invitedPeer.peer.id
|
||||
|
||||
let subtitle: PeerListItemComponent.Subtitle
|
||||
subtitle = PeerListItemComponent.Subtitle(text: component.strings.VoiceChat_StatusInvited, color: .neutral)
|
||||
//TODO:localize
|
||||
switch invitedPeer.state {
|
||||
case .none:
|
||||
subtitle = PeerListItemComponent.Subtitle(text: component.strings.VoiceChat_StatusInvited, color: .neutral)
|
||||
case .connecting:
|
||||
subtitle = PeerListItemComponent.Subtitle(text: "connecting...", color: .neutral)
|
||||
case .requesting:
|
||||
subtitle = PeerListItemComponent.Subtitle(text: "requesting...", color: .neutral)
|
||||
case .ringing:
|
||||
subtitle = PeerListItemComponent.Subtitle(text: "ringing...", color: .neutral)
|
||||
}
|
||||
|
||||
peerItemComponent = PeerListItemComponent(
|
||||
context: component.call.accountContext,
|
||||
@ -1270,15 +1280,15 @@ final class VideoChatParticipantsComponent: Component {
|
||||
strings: component.strings,
|
||||
style: .generic,
|
||||
sideInset: 0.0,
|
||||
title: invitedPeer.displayTitle(strings: component.strings, displayOrder: .firstLast),
|
||||
title: invitedPeer.peer.displayTitle(strings: component.strings, displayOrder: .firstLast),
|
||||
avatarComponent: AnyComponent(VideoChatParticipantAvatarComponent(
|
||||
call: component.call,
|
||||
peer: invitedPeer,
|
||||
peer: invitedPeer.peer,
|
||||
myPeerId: component.participants?.myPeerId ?? component.call.accountContext.account.peerId,
|
||||
isSpeaking: false,
|
||||
theme: component.theme
|
||||
)),
|
||||
peer: invitedPeer,
|
||||
peer: invitedPeer.peer,
|
||||
subtitle: subtitle,
|
||||
subtitleAccessory: .none,
|
||||
presence: nil,
|
||||
|
@ -190,6 +190,16 @@ final class VideoChatScreenComponent: Component {
|
||||
self.scrollView = scrollView
|
||||
}
|
||||
}
|
||||
|
||||
struct InvitedPeer: Equatable {
|
||||
var peer: EnginePeer
|
||||
var state: PresentationGroupCallInvitedPeer.State?
|
||||
|
||||
init(peer: EnginePeer, state: PresentationGroupCallInvitedPeer.State?) {
|
||||
self.peer = peer
|
||||
self.state = state
|
||||
}
|
||||
}
|
||||
|
||||
final class View: UIView, UIGestureRecognizerDelegate {
|
||||
let containerView: UIView
|
||||
@ -242,7 +252,7 @@ final class VideoChatScreenComponent: Component {
|
||||
var members: PresentationGroupCallMembers?
|
||||
var membersDisposable: Disposable?
|
||||
|
||||
var invitedPeers: [EnginePeer] = []
|
||||
var invitedPeers: [InvitedPeer] = []
|
||||
var invitedPeersDisposable: Disposable?
|
||||
|
||||
var speakingParticipantPeers: [EnginePeer] = []
|
||||
@ -323,8 +333,13 @@ final class VideoChatScreenComponent: Component {
|
||||
}
|
||||
|
||||
var expandedPeer: (id: EnginePeer.Id, isPresentation: Bool)?
|
||||
if let animateOutData, animateOutData.incomingVideoLayer != nil {
|
||||
if let members = self.members, let participant = members.participants.first(where: { $0.peer.id == animateOutData.incomingPeerId }) {
|
||||
if let animateOutData, animateOutData.incomingVideoLayer != nil, let members = self.members {
|
||||
if let participant = members.participants.first(where: { $0.peer.id == animateOutData.incomingPeerId }) {
|
||||
if let _ = participant.videoDescription {
|
||||
expandedPeer = (participant.peer.id, false)
|
||||
self.expandedParticipantsVideoState = VideoChatParticipantsComponent.ExpandedVideoState(mainParticipant: VideoChatParticipantsComponent.VideoParticipantKey(id: participant.peer.id, isPresentation: false), isMainParticipantPinned: false, isUIHidden: true)
|
||||
}
|
||||
} else if let participant = members.participants.first(where: { $0.peer.id == sourceCallController.call.context.account.peerId }) {
|
||||
if let _ = participant.videoDescription {
|
||||
expandedPeer = (participant.peer.id, false)
|
||||
self.expandedParticipantsVideoState = VideoChatParticipantsComponent.ExpandedVideoState(mainParticipant: VideoChatParticipantsComponent.VideoParticipantKey(id: participant.peer.id, isPresentation: false), isMainParticipantPinned: false, isUIHidden: true)
|
||||
@ -969,7 +984,7 @@ final class VideoChatScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
static func groupCallStateForConferenceSource(conferenceSource: PresentationCall) -> Signal<(state: PresentationGroupCallState, invitedPeers: [EnginePeer]), NoError> {
|
||||
static func groupCallStateForConferenceSource(conferenceSource: PresentationCall) -> Signal<(state: PresentationGroupCallState, invitedPeers: [InvitedPeer]), NoError> {
|
||||
let invitedPeers = conferenceSource.context.engine.data.subscribe(
|
||||
EngineDataList((conferenceSource as! PresentationCallImpl).pendingInviteToConferencePeerIds.map { TelegramEngine.EngineData.Item.Peer.Peer(id: $0) })
|
||||
)
|
||||
@ -982,7 +997,7 @@ final class VideoChatScreenComponent: Component {
|
||||
conferenceSource.isMuted,
|
||||
invitedPeers
|
||||
)
|
||||
|> mapToSignal { state, isMuted, invitedPeers -> Signal<(state: PresentationGroupCallState, invitedPeers: [EnginePeer]), NoError> in
|
||||
|> mapToSignal { state, isMuted, invitedPeers -> Signal<(state: PresentationGroupCallState, invitedPeers: [VideoChatScreenComponent.InvitedPeer]), NoError> in
|
||||
let mappedNetworkState: PresentationGroupCallState.NetworkState
|
||||
switch state.state {
|
||||
case .active:
|
||||
@ -1007,7 +1022,12 @@ final class VideoChatScreenComponent: Component {
|
||||
isVideoWatchersLimitReached: false
|
||||
)
|
||||
|
||||
return .single((callState, invitedPeers.compactMap({ $0 })))
|
||||
return .single((callState, invitedPeers.compactMap({ peer -> VideoChatScreenComponent.InvitedPeer? in
|
||||
guard let peer else {
|
||||
return nil
|
||||
}
|
||||
return VideoChatScreenComponent.InvitedPeer(peer: peer, state: .requesting)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1023,10 +1043,18 @@ final class VideoChatScreenComponent: Component {
|
||||
var participants: [GroupCallParticipantsContext.Participant] = []
|
||||
let (myPeer, remotePeer) = peers
|
||||
if let myPeer {
|
||||
var myVideoDescription: GroupCallParticipantsContext.Participant.VideoDescription?
|
||||
switch state.videoState {
|
||||
case .active:
|
||||
myVideoDescription = GroupCallParticipantsContext.Participant.VideoDescription(endpointId: "temp-local", ssrcGroups: [], audioSsrc: nil, isPaused: false)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
participants.append(GroupCallParticipantsContext.Participant(
|
||||
peer: myPeer._asPeer(),
|
||||
ssrc: nil,
|
||||
videoDescription: nil,
|
||||
videoDescription: myVideoDescription,
|
||||
presentationDescription: nil,
|
||||
joinTimestamp: 0,
|
||||
raiseHandRating: nil,
|
||||
@ -1040,10 +1068,18 @@ final class VideoChatScreenComponent: Component {
|
||||
))
|
||||
}
|
||||
if let remotePeer {
|
||||
var remoteVideoDescription: GroupCallParticipantsContext.Participant.VideoDescription?
|
||||
switch state.remoteVideoState {
|
||||
case .active:
|
||||
remoteVideoDescription = GroupCallParticipantsContext.Participant.VideoDescription(endpointId: "temp-remote", ssrcGroups: [], audioSsrc: nil, isPaused: false)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
participants.append(GroupCallParticipantsContext.Participant(
|
||||
peer: remotePeer._asPeer(),
|
||||
ssrc: nil,
|
||||
videoDescription: nil,
|
||||
videoDescription: remoteVideoDescription,
|
||||
presentationDescription: nil,
|
||||
joinTimestamp: 0,
|
||||
raiseHandRating: nil,
|
||||
@ -1087,7 +1123,7 @@ final class VideoChatScreenComponent: Component {
|
||||
self.members = component.initialData.members
|
||||
self.invitedPeers = component.initialData.invitedPeers
|
||||
if let members = self.members {
|
||||
self.invitedPeers.removeAll(where: { invitedPeer in members.participants.contains(where: { $0.peer.id == invitedPeer.id }) })
|
||||
self.invitedPeers.removeAll(where: { invitedPeer in members.participants.contains(where: { $0.peer.id == invitedPeer.peer.id }) })
|
||||
}
|
||||
self.callState = component.initialData.callState
|
||||
}
|
||||
@ -1128,7 +1164,7 @@ final class VideoChatScreenComponent: Component {
|
||||
|
||||
self.members = members
|
||||
if let members {
|
||||
self.invitedPeers.removeAll(where: { invitedPeer in members.participants.contains(where: { $0.peer.id == invitedPeer.id }) })
|
||||
self.invitedPeers.removeAll(where: { invitedPeer in members.participants.contains(where: { $0.peer.id == invitedPeer.peer.id }) })
|
||||
}
|
||||
|
||||
if let members, let expandedParticipantsVideoState = self.expandedParticipantsVideoState, !expandedParticipantsVideoState.isUIHidden {
|
||||
@ -1234,10 +1270,16 @@ final class VideoChatScreenComponent: Component {
|
||||
self.invitedPeersDisposable = (groupCall.invitedPeers
|
||||
|> mapToSignal { invitedPeers in
|
||||
return accountContext.engine.data.get(
|
||||
EngineDataList(invitedPeers.map({ TelegramEngine.EngineData.Item.Peer.Peer(id: $0) }))
|
||||
EngineDataMap(invitedPeers.map({ TelegramEngine.EngineData.Item.Peer.Peer(id: $0.id) }))
|
||||
)
|
||||
|> map { peers in
|
||||
return peers.compactMap { $0 }
|
||||
|> map { peers -> [InvitedPeer] in
|
||||
var result: [InvitedPeer] = []
|
||||
for invitedPeer in invitedPeers {
|
||||
if let maybePeer = peers[invitedPeer.id], let peer = maybePeer {
|
||||
result.append(InvitedPeer(peer: peer, state: invitedPeer.state))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] invitedPeers in
|
||||
@ -1247,7 +1289,7 @@ final class VideoChatScreenComponent: Component {
|
||||
|
||||
var invitedPeers = invitedPeers
|
||||
if let members {
|
||||
invitedPeers.removeAll(where: { invitedPeer in members.participants.contains(where: { $0.peer.id == invitedPeer.id }) })
|
||||
invitedPeers.removeAll(where: { invitedPeer in members.participants.contains(where: { $0.peer.id == invitedPeer.peer.id }) })
|
||||
}
|
||||
|
||||
if self.invitedPeers != invitedPeers {
|
||||
@ -2461,13 +2503,13 @@ final class VideoChatScreenV2Impl: ViewControllerComponentContainer, VoiceChatCo
|
||||
let peer: EnginePeer?
|
||||
let members: PresentationGroupCallMembers?
|
||||
let callState: PresentationGroupCallState
|
||||
let invitedPeers: [EnginePeer]
|
||||
let invitedPeers: [VideoChatScreenComponent.InvitedPeer]
|
||||
|
||||
init(
|
||||
peer: EnginePeer?,
|
||||
members: PresentationGroupCallMembers?,
|
||||
callState: PresentationGroupCallState,
|
||||
invitedPeers: [EnginePeer]
|
||||
invitedPeers: [VideoChatScreenComponent.InvitedPeer]
|
||||
) {
|
||||
self.peer = peer
|
||||
self.members = members
|
||||
@ -2633,7 +2675,7 @@ final class VideoChatScreenV2Impl: ViewControllerComponentContainer, VoiceChatCo
|
||||
let accountContext = groupCall.accountContext
|
||||
let invitedPeers = groupCall.invitedPeers |> take(1) |> mapToSignal { invitedPeers in
|
||||
return accountContext.engine.data.get(
|
||||
EngineDataList(invitedPeers.map({ TelegramEngine.EngineData.Item.Peer.Peer(id: $0) }))
|
||||
EngineDataList(invitedPeers.map(\.id).map({ TelegramEngine.EngineData.Item.Peer.Peer(id: $0) }))
|
||||
)
|
||||
}
|
||||
return combineLatest(
|
||||
@ -2647,7 +2689,12 @@ final class VideoChatScreenV2Impl: ViewControllerComponentContainer, VoiceChatCo
|
||||
peer: peer,
|
||||
members: members,
|
||||
callState: callState,
|
||||
invitedPeers: invitedPeers.compactMap { $0 }
|
||||
invitedPeers: invitedPeers.compactMap { peer -> VideoChatScreenComponent.InvitedPeer? in
|
||||
guard let peer else {
|
||||
return nil
|
||||
}
|
||||
return VideoChatScreenComponent.InvitedPeer(peer: peer, state: nil)
|
||||
}
|
||||
)
|
||||
}
|
||||
case let .conferenceSource(conferenceSource):
|
||||
|
@ -1891,7 +1891,8 @@ final class VoiceChatControllerImpl: ViewController, VoiceChatController {
|
||||
self.updateDecorationsColors()
|
||||
|
||||
let invitedPeers: Signal<[EnginePeer], NoError> = self.call.invitedPeers
|
||||
|> mapToSignal { ids -> Signal<[EnginePeer], NoError> in
|
||||
|> mapToSignal { peers -> Signal<[EnginePeer], NoError> in
|
||||
let ids = peers.map(\.id)
|
||||
return context.engine.data.get(EngineDataList(
|
||||
ids.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||
))
|
||||
|
@ -19,6 +19,7 @@ public enum CallSessionEndedType {
|
||||
case hungUp
|
||||
case busy
|
||||
case missed
|
||||
case switchedToConference
|
||||
}
|
||||
|
||||
public enum CallSessionTerminationReason: Equatable {
|
||||
@ -709,7 +710,7 @@ private final class CallSessionManagerContext {
|
||||
case .missed:
|
||||
mappedReason = .ended(.missed)
|
||||
case .switchToConference:
|
||||
mappedReason = .ended(.hungUp)
|
||||
mappedReason = .ended(.switchedToConference)
|
||||
}
|
||||
context.state = .dropping(reason: mappedReason, disposable: (dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, isVideo: isVideo, reason: reason)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] reportRating, sendDebugLogs in
|
||||
@ -763,7 +764,7 @@ private final class CallSessionManagerContext {
|
||||
|
||||
if let (id, accessHash) = dropData {
|
||||
self.contextIdByStableId.removeValue(forKey: id)
|
||||
context.state = .dropping(reason: .ended(.hungUp), disposable: (dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, isVideo: isVideo, reason: .switchToConference(encryptedGroupKey: encryptedGroupKey))
|
||||
context.state = .dropping(reason: .ended(.switchedToConference), disposable: (dropCallSession(network: self.network, addUpdates: self.addUpdates, stableId: id, accessHash: accessHash, isVideo: isVideo, reason: .switchToConference(encryptedGroupKey: encryptedGroupKey))
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] reportRating, sendDebugLogs in
|
||||
if let strongSelf = self {
|
||||
if let context = strongSelf.contexts[internalId] {
|
||||
@ -962,11 +963,15 @@ private final class CallSessionManagerContext {
|
||||
case .phoneCallDiscardReasonDisconnect:
|
||||
parsedReason = .error(.disconnected)
|
||||
case .phoneCallDiscardReasonHangup:
|
||||
parsedReason = .ended(.hungUp)
|
||||
if context.pendingConference != nil {
|
||||
parsedReason = .ended(.switchedToConference)
|
||||
} else {
|
||||
parsedReason = .ended(.hungUp)
|
||||
}
|
||||
case .phoneCallDiscardReasonMissed:
|
||||
parsedReason = .ended(.missed)
|
||||
case .phoneCallDiscardReasonAllowGroupCall:
|
||||
parsedReason = .ended(.hungUp)
|
||||
parsedReason = .ended(.switchedToConference)
|
||||
}
|
||||
} else {
|
||||
parsedReason = .ended(.hungUp)
|
||||
|
@ -503,21 +503,27 @@ public final class PrivateCallScreen: OverlayMaskContainerView, AVPictureInPictu
|
||||
self.update(transition: .easeInOut(duration: 0.25))
|
||||
}
|
||||
|
||||
public func takeIncomingVideoLayer() -> (CALayer, VideoSource.Output?)? {
|
||||
var remoteVideoContainerKey: VideoContainerView.Key?
|
||||
public func takeIncomingVideoLayer() -> ((CALayer, VideoSource.Output?), Bool)? {
|
||||
var activeVideoSources: [(VideoContainerView.Key, Bool)] = []
|
||||
if self.swapLocalAndRemoteVideo {
|
||||
if let _ = self.activeLocalVideoSource {
|
||||
activeVideoSources.append((.background, false))
|
||||
}
|
||||
if let _ = self.activeRemoteVideoSource {
|
||||
remoteVideoContainerKey = .foreground
|
||||
activeVideoSources.append((.foreground, true))
|
||||
}
|
||||
} else {
|
||||
if let _ = self.activeRemoteVideoSource {
|
||||
remoteVideoContainerKey = .background
|
||||
activeVideoSources.append((.background, true))
|
||||
}
|
||||
if let _ = self.activeLocalVideoSource {
|
||||
activeVideoSources.append((.foreground, false))
|
||||
}
|
||||
}
|
||||
|
||||
if let remoteVideoContainerKey, let videoContainerView = self.videoContainerViews.first(where: { $0.key == remoteVideoContainerKey }) {
|
||||
if let videoSource = activeVideoSources.first, let videoContainerView = self.videoContainerViews.first(where: { $0.key == videoSource.0 }) {
|
||||
videoContainerView.videoContainerLayerTaken = true
|
||||
return (videoContainerView.videoContainerLayer, videoContainerView.currentVideoOutput)
|
||||
return ((videoContainerView.videoContainerLayer, videoContainerView.currentVideoOutput), videoSource.1)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1087,10 +1087,8 @@ public final class OngoingGroupCallContext {
|
||||
|
||||
}
|
||||
|
||||
func addRemoteConnectedEvent(isRemoteConntected: Bool) {
|
||||
#if os(iOS)
|
||||
self.context.addRemoteConnectedEvent(isRemoteConntected)
|
||||
#endif
|
||||
func activateIncomingAudio() {
|
||||
self.context.activateIncomingAudio()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1314,9 +1312,9 @@ public final class OngoingGroupCallContext {
|
||||
}
|
||||
}
|
||||
|
||||
public func addRemoteConnectedEvent(isRemoteConntected: Bool) {
|
||||
public func activateIncomingAudio() {
|
||||
self.impl.with { impl in
|
||||
impl.addRemoteConnectedEvent(isRemoteConntected: isRemoteConntected)
|
||||
impl.activateIncomingAudio()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ isConference:(bool)isConference;
|
||||
|
||||
- (void)getStats:(void (^ _Nonnull)(OngoingGroupCallStats * _Nonnull))completion;
|
||||
|
||||
- (void)addRemoteConnectedEvent:(bool)isRemoteConnected;
|
||||
- (void)activateIncomingAudio;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -66,6 +66,29 @@
|
||||
|
||||
namespace tgcalls {
|
||||
|
||||
class WrappedChildAudioDeviceModuleControl {
|
||||
public:
|
||||
WrappedChildAudioDeviceModuleControl() {
|
||||
}
|
||||
|
||||
virtual ~WrappedChildAudioDeviceModuleControl() {
|
||||
_mutex.Lock();
|
||||
_mutex.Unlock();
|
||||
}
|
||||
|
||||
public:
|
||||
void setActive() {
|
||||
_mutex.Lock();
|
||||
|
||||
|
||||
|
||||
_mutex.Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
webrtc::Mutex _mutex;
|
||||
};
|
||||
|
||||
class SharedAudioDeviceModule {
|
||||
public:
|
||||
virtual ~SharedAudioDeviceModule() = default;
|
||||
@ -93,12 +116,15 @@ public:
|
||||
}
|
||||
|
||||
void UpdateAudioCallback(webrtc::AudioTransport *previousAudioCallback, webrtc::AudioTransport *audioCallback) {
|
||||
if (audioCallback == nil) {
|
||||
if (_currentAudioTransport == previousAudioCallback) {
|
||||
_currentAudioTransport = nil;
|
||||
if (audioCallback) {
|
||||
_audioTransports.push_back(audioCallback);
|
||||
} else if (previousAudioCallback) {
|
||||
for (size_t i = 0; i < _audioTransports.size(); i++) {
|
||||
if (_audioTransports[i] == previousAudioCallback) {
|
||||
_audioTransports.erase(_audioTransports.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_currentAudioTransport = audioCallback;
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,19 +435,26 @@ public:
|
||||
bool keyPressed,
|
||||
uint32_t& newMicLevel
|
||||
) override {
|
||||
if (_currentAudioTransport) {
|
||||
return _currentAudioTransport->RecordedDataIsAvailable(
|
||||
audioSamples,
|
||||
nSamples,
|
||||
nBytesPerSample,
|
||||
nChannels,
|
||||
samplesPerSec,
|
||||
totalDelayMS,
|
||||
clockDrift,
|
||||
currentMicLevel,
|
||||
keyPressed,
|
||||
newMicLevel
|
||||
);
|
||||
if (!_audioTransports.empty()) {
|
||||
for (size_t i = 0; i < _audioTransports.size(); i++) {
|
||||
auto result = _audioTransports[_audioTransports.size() - 1]->RecordedDataIsAvailable(
|
||||
audioSamples,
|
||||
nSamples,
|
||||
nBytesPerSample,
|
||||
nChannels,
|
||||
samplesPerSec,
|
||||
totalDelayMS,
|
||||
clockDrift,
|
||||
currentMicLevel,
|
||||
keyPressed,
|
||||
newMicLevel
|
||||
);
|
||||
if (i == _audioTransports.size() - 1) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -440,20 +473,26 @@ public:
|
||||
uint32_t& newMicLevel,
|
||||
absl::optional<int64_t> estimatedCaptureTimeNS
|
||||
) override {
|
||||
if (_currentAudioTransport) {
|
||||
return _currentAudioTransport->RecordedDataIsAvailable(
|
||||
audioSamples,
|
||||
nSamples,
|
||||
nBytesPerSample,
|
||||
nChannels,
|
||||
samplesPerSec,
|
||||
totalDelayMS,
|
||||
clockDrift,
|
||||
currentMicLevel,
|
||||
keyPressed,
|
||||
newMicLevel,
|
||||
estimatedCaptureTimeNS
|
||||
);
|
||||
if (!_audioTransports.empty()) {
|
||||
for (size_t i = 0; i < _audioTransports.size(); i++) {
|
||||
auto result = _audioTransports[_audioTransports.size() - 1]->RecordedDataIsAvailable(
|
||||
audioSamples,
|
||||
nSamples,
|
||||
nBytesPerSample,
|
||||
nChannels,
|
||||
samplesPerSec,
|
||||
totalDelayMS,
|
||||
clockDrift,
|
||||
currentMicLevel,
|
||||
keyPressed,
|
||||
newMicLevel,
|
||||
estimatedCaptureTimeNS
|
||||
);
|
||||
if (i == _audioTransports.size() - 1) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
@ -470,8 +509,8 @@ public:
|
||||
int64_t* elapsed_time_ms,
|
||||
int64_t* ntp_time_ms
|
||||
) override {
|
||||
if (_currentAudioTransport) {
|
||||
return _currentAudioTransport->NeedMorePlayData(
|
||||
if (!_audioTransports.empty()) {
|
||||
return _audioTransports[_audioTransports.size() - 1]->NeedMorePlayData(
|
||||
nSamples,
|
||||
nBytesPerSample,
|
||||
nChannels,
|
||||
@ -496,8 +535,8 @@ public:
|
||||
int64_t* elapsed_time_ms,
|
||||
int64_t* ntp_time_ms
|
||||
) override {
|
||||
if (_currentAudioTransport) {
|
||||
_currentAudioTransport->PullRenderData(
|
||||
if (!_audioTransports.empty()) {
|
||||
_audioTransports[_audioTransports.size() - 1]->PullRenderData(
|
||||
bits_per_sample,
|
||||
sample_rate,
|
||||
number_of_channels,
|
||||
@ -540,7 +579,7 @@ public:
|
||||
|
||||
private:
|
||||
bool _isStarted = false;
|
||||
webrtc::AudioTransport *_currentAudioTransport = nullptr;
|
||||
std::vector<webrtc::AudioTransport *> _audioTransports;
|
||||
};
|
||||
|
||||
class WrappedChildAudioDeviceModule : public tgcalls::DefaultWrappedAudioDeviceModule {
|
||||
@ -556,13 +595,28 @@ public:
|
||||
auto previousAudioCallback = _audioCallback;
|
||||
_audioCallback = audioCallback;
|
||||
|
||||
((WrappedAudioDeviceModuleIOS *)WrappedInstance().get())->UpdateAudioCallback(previousAudioCallback, audioCallback);
|
||||
if (_isActive) {
|
||||
((WrappedAudioDeviceModuleIOS *)WrappedInstance().get())->UpdateAudioCallback(previousAudioCallback, audioCallback);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
void setIsActive() {
|
||||
if (_isActive) {
|
||||
return;
|
||||
}
|
||||
_isActive = true;
|
||||
|
||||
if (_audioCallback) {
|
||||
((WrappedAudioDeviceModuleIOS *)WrappedInstance().get())->UpdateAudioCallback(nullptr, _audioCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
webrtc::AudioTransport *_audioCallback = nullptr;
|
||||
bool _isActive = false;
|
||||
};
|
||||
|
||||
class SharedAudioDeviceModuleImpl: public tgcalls::SharedAudioDeviceModule {
|
||||
@ -1785,7 +1839,9 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL;
|
||||
},
|
||||
.createWrappedAudioDeviceModule = [audioDeviceModule](webrtc::TaskQueueFactory *taskQueueFactory) -> rtc::scoped_refptr<tgcalls::WrappedAudioDeviceModule> {
|
||||
if (audioDeviceModule) {
|
||||
return audioDeviceModule->getSyncAssumingSameThread()->makeChildAudioDeviceModule();
|
||||
auto result = audioDeviceModule->getSyncAssumingSameThread()->makeChildAudioDeviceModule();
|
||||
((WrappedChildAudioDeviceModule *)result.get())->setIsActive();
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2493,7 +2549,9 @@ isConference:(bool)isConference {
|
||||
},
|
||||
.createWrappedAudioDeviceModule = [audioDeviceModule](webrtc::TaskQueueFactory *taskQueueFactory) -> rtc::scoped_refptr<tgcalls::WrappedAudioDeviceModule> {
|
||||
if (audioDeviceModule) {
|
||||
return audioDeviceModule->getSyncAssumingSameThread()->makeChildAudioDeviceModule();
|
||||
auto result = audioDeviceModule->getSyncAssumingSameThread()->makeChildAudioDeviceModule();
|
||||
((WrappedChildAudioDeviceModule *)result.get())->setIsActive();
|
||||
return result;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2835,10 +2893,7 @@ isConference:(bool)isConference {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addRemoteConnectedEvent:(bool)isRemoteConnected {
|
||||
if (_instance) {
|
||||
_instance->internal_addCustomNetworkEvent(isRemoteConnected);
|
||||
}
|
||||
- (void)activateIncomingAudio {
|
||||
}
|
||||
|
||||
@end
|
||||
|
Loading…
x
Reference in New Issue
Block a user