Skip to content

Commit fa91f5f

Browse files
eddardliulynxzhang
authored andcommitted
Fix a series of test bugs and add intelligent customer service
1 parent c377b4e commit fa91f5f

1,500 files changed

Lines changed: 792428 additions & 261 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// ChatCallEventSubscriber.swift
3+
// TUICallKit
4+
//
5+
import AtomicXCore
6+
import Foundation
7+
8+
public final class ChatCallEventSubscriber: NSObject {
9+
public static let shared = ChatCallEventSubscriber()
10+
11+
private static let startCallEventName = Notification.Name("tuicallkit.startCall")
12+
private static let startJoinEventName = Notification.Name("tuicallkit.startJoin")
13+
private static let keyParticipantIDs = "participantIds"
14+
private static let keyMediaType = "mediaType"
15+
private static let keyChatGroupID = "chatGroupId"
16+
private static let keyTimeout = "timeout"
17+
private static let keyCallID = "callId"
18+
19+
private var isSubscribed = false
20+
21+
private override init() {
22+
super.init()
23+
}
24+
25+
public func ensureSubscribed() {
26+
guard !isSubscribed else { return }
27+
isSubscribed = true
28+
NotificationCenter.default.addObserver(self,
29+
selector: #selector(handleStartCallEvent(_:)),
30+
name: Self.startCallEventName,
31+
object: nil)
32+
NotificationCenter.default.addObserver(self,
33+
selector: #selector(handleStartJoinEvent(_:)),
34+
name: Self.startJoinEventName,
35+
object: nil)
36+
}
37+
38+
@objc private func handleStartCallEvent(_ notification: Notification) {
39+
guard let userInfo = notification.userInfo,
40+
let participantIDs = userInfo[Self.keyParticipantIDs] as? [String],
41+
!participantIDs.isEmpty else { return }
42+
let mediaType: CallMediaType = (userInfo[Self.keyMediaType] as? String) == "video" ? .video : .audio
43+
let chatGroupID = userInfo[Self.keyChatGroupID] as? String ?? ""
44+
let timeout = userInfo[Self.keyTimeout] as? Int ?? 30
45+
46+
var callParams = CallParams()
47+
callParams.chatGroupId = chatGroupID
48+
callParams.timeout = timeout
49+
TUICallKit.createInstance().calls(userIdList: participantIDs, mediaType: mediaType, params: callParams, completion: nil)
50+
}
51+
52+
53+
@objc private func handleStartJoinEvent(_ notification: Notification) {
54+
guard let callID = notification.userInfo?[Self.keyCallID] as? String, !callID.isEmpty else { return }
55+
TUICallKit.createInstance().join(callId: callID, completion: nil)
56+
}
57+
}

‎call/TUICallKit_Swift/Bridge/Chat/Deprecated/SwiftLoad.swift‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ extension NSObject {
1515
NotificationCenter.default.addObserver(self, selector: #selector(initSdkSuccess(_:)),
1616
name: Notification.Name.TUIInitSdkSuccess,
1717
object: nil)
18-
18+
19+
ChatCallEventSubscriber.shared.ensureSubscribed()
20+
1921
TUICore.registerService(TUICore_TUICallingService, object: TUICallKitService.instance)
2022

2123
TUICore.registerService(TUICore_TUIAudioMessageRecordService, object: TUIAudioMessageRecordService.instance)

‎call/TUICallKit_Swift/TUICallKit.swift‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class TUICallKit: NSObject {
1515
*/
1616
@objc
1717
public static func createInstance() -> TUICallKit {
18+
ChatCallEventSubscriber.shared.ensureSubscribed()
1819
return TUICallKitImpl.shared
1920
}
2021

‎call/TUICallKit_Swift/TUICallKitImpl.swift‎

Lines changed: 31 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import UIKit
1111
import AtomicX
1212
import AtomicXCore
1313
import Combine
14-
import AtomicX
1514

1615
#if canImport(TXLiteAVSDK_TRTC)
1716
import TXLiteAVSDK_TRTC
@@ -25,7 +24,6 @@ import RTCRoomEngine
2524
class TUICallKitImpl: TUICallKit {
2625
static let shared = TUICallKitImpl()
2726
private var cancellables = Set<AnyCancellable>()
28-
private var hasSetDefaultDeviceState = false
2927

3028
let globalState = GlobalState()
3129
let viewState = ViewState()
@@ -55,7 +53,7 @@ class TUICallKitImpl: TUICallKit {
5553
completion?(.failure(ErrorInfo(code: Int(ERROR_PARAM_INVALID), message: "Invalid screen orientation value")))
5654
return
5755
}
58-
globalState.orientation = Orientation(rawValue: orientation) ?? .portrait
56+
globalState.orientation = targetOrientation
5957
completion?(.success(()))
6058
}
6159

@@ -257,18 +255,6 @@ extension TUICallKitImpl {
257255
.store(in: &cancellables)
258256
}
259257

260-
private func handleCallParticipantStatusChanged(_ newStatus: CallParticipantStatus) {
261-
switch newStatus {
262-
case .accept:
263-
if !hasSetDefaultDeviceState {
264-
setDefaultDeviceState()
265-
hasSetDefaultDeviceState = true
266-
}
267-
default:
268-
break
269-
}
270-
}
271-
272258
func unSubscribeCallState() {
273259
cancellables.removeAll()
274260
}
@@ -326,6 +312,19 @@ extension TUICallKitImpl {
326312
}
327313
}
328314

315+
private func handleCallParticipantStatusChanged(_ newStatus: CallParticipantStatus) {
316+
if newStatus == .accept {
317+
let mediaType = CallStore.shared.state.value.activeCall.mediaType
318+
CallManager.shared.openLocalMicrophone()
319+
if mediaType == .audio {
320+
CallManager.shared.setAudioRoute(.earpiece)
321+
} else if mediaType == .video {
322+
CallManager.shared.setAudioRoute(.speakerphone)
323+
CallManager.shared.openLocalCameraIfPermitted()
324+
}
325+
}
326+
}
327+
329328
@objc func setupCallEngine() {
330329
LoginStore.shared.login(sdkAppID: TUILogin.getSdkAppID(), userID: TUILogin.getUserID() ?? "", userSig: TUILogin.getUserSig() ?? "", completion: nil)
331330
TUICallEngine.createInstance().`init`(TUILogin.getSdkAppID(), userId: TUILogin.getUserID() ?? "", userSig: TUILogin.getUserSig() ?? "") { [weak self] in
@@ -452,7 +451,7 @@ extension TUICallKitImpl {
452451
guard let self = self else { return }
453452
if !callId.isEmpty {
454453
if isCaller() && globalState.enableAITranscriber {
455-
startRealtimeTranscriber(callID: callId)
454+
AITranscriberStore.create(roomID: callId).startRealtimeTranscriber(config: TranscriberSettings.config, completion: nil)
456455
}
457456
}
458457
}
@@ -461,50 +460,55 @@ extension TUICallKitImpl {
461460

462461
func handleCallEvent(_ event: CallEvent) {
463462
switch event {
464-
case .onCallStarted(_, _):
465-
if !hasSetDefaultDeviceState {
466-
setDefaultDeviceState()
467-
hasSetDefaultDeviceState = true
463+
case let .onCallStarted(callId: _, mediaType: mediaType):
464+
CallManager.shared.openLocalMicrophone()
465+
if mediaType == .audio {
466+
CallManager.shared.setAudioRoute(.earpiece)
467+
} else if mediaType == .video {
468+
CallManager.shared.setAudioRoute(.speakerphone)
469+
CallManager.shared.openLocalCameraIfPermitted()
468470
}
469471
showCallKitViewController(isCaller: true)
472+
470473
case let .onCallReceived(callId, mediaType, _):
471474
KeyMetrics.countUV(eventId: .received, callId: callId)
472475
if mediaType == .video {
473476
CallManager.shared.openLocalCameraIfPermitted()
474477
}
475478
showCallKitViewController(isCaller: false)
476479

477-
case let .onCallEnded(callId: _, mediaType: _, reason: reason, userId: userId):
480+
case let .onCallEnded(callId: callId, mediaType: _, reason: reason, userId: userId):
481+
AITranscriberStore.create(roomID: callId).stopRealtimeTranscriber()
478482
TranscriberSettings.reset()
479-
hasSetDefaultDeviceState = false
480483
TEBeautyView.releaseSharedInstance()
481484
handleCallEndedWithResidence(reason: reason, userId: userId)
485+
DeviceStore.shared.reset()
482486
default:
483487
break
484488
}
485489
}
486-
490+
487491
func handleCallEndedWithResidence(reason: CallEndReason, userId: String) {
488492
let selfInfo = CallStore.shared.state.value.selfInfo
489493
let activeCall = CallStore.shared.state.value.activeCall
490494
let isGroupCall = !activeCall.chatGroupId.isEmpty || activeCall.inviteeIds.count > 1
491495
let triggeredBySelf = !selfInfo.id.isEmpty && userId == selfInfo.id
492-
496+
493497
guard !selfInfo.id.isEmpty else { closeCallKitViewController(); return }
494498
guard !triggeredBySelf else { closeCallKitViewController(); return }
495499
guard !isGroupCall else { closeCallKitViewController(); return }
496500
guard let messageKey = endCallHintKey(for: reason) else { closeCallKitViewController(); return }
497-
501+
498502
let message = TUICallKitLocalize(key: messageKey)
499503
guard !message.isEmpty else { closeCallKitViewController(); return }
500504
guard let callMainViewController = WindowManager.shared.currentCallMainViewController() else {
501505
closeCallKitViewController()
502506
return
503507
}
504-
508+
505509
callMainViewController.showEndCallHint(text: message)
506510
}
507-
511+
508512
private func endCallHintKey(for reason: CallEndReason) -> String? {
509513
switch reason {
510514
case .hangup:
@@ -522,21 +526,6 @@ extension TUICallKitImpl {
522526
}
523527
}
524528

525-
func setDefaultDeviceState() {
526-
let activeCall = CallStore.shared.state.value.activeCall
527-
let mediaType = activeCall.mediaType
528-
let deviceStore = DeviceStore.shared
529-
530-
deviceStore.openLocalMicrophone(completion: nil)
531-
532-
if mediaType == .audio {
533-
deviceStore.setAudioRoute(.earpiece)
534-
} else {
535-
deviceStore.setAudioRoute(.speakerphone)
536-
deviceStore.openLocalCamera(isFront: true, completion: nil)
537-
}
538-
}
539-
540529
func showIMErrorMessage(code: Int32, message: String?) {
541530
let errorMessage = TUITool.convertIMError(Int(code), msg: convertCallKitError(code: code, message: message))
542531
let eventId = getToastEventId(for: code)
@@ -608,41 +597,9 @@ extension TUICallKitImpl {
608597
duration: .long
609598
)
610599
}
611-
}
612-
613-
// MARK: - AI Transcriber
614-
extension TUICallKitImpl {
615-
private static let vadConfigKey = "Liteav.Audio.common.enable.send.eos.packet.in.dtx"
616600

617601
private func isCaller() -> Bool {
618602
let state = CallStore.shared.state.value
619603
return state.selfInfo.id == state.activeCall.inviterId
620604
}
621-
622-
private func startRealtimeTranscriber(callID: String) {
623-
AITranscriberStore.create(roomID: callID).startRealtimeTranscriber(config: TranscriberSettings.config, completion: nil)
624-
closeVAD()
625-
}
626-
627-
private func closeVAD() {
628-
callExperimentalAPI(withConfig: [
629-
"key": Self.vadConfigKey,
630-
"action": "reset"
631-
])
632-
callExperimentalAPI(withConfig: [
633-
"key": Self.vadConfigKey,
634-
"value": 0,
635-
"default": 0
636-
])
637-
}
638-
639-
private func callExperimentalAPI(withConfig config: [String: Any]) {
640-
let jsonObj: [String: Any] = [
641-
"api": "setPrivateConfig",
642-
"params": ["configs": [config]]
643-
]
644-
guard let data = try? JSONSerialization.data(withJSONObject: jsonObj),
645-
let jsonStr = String(data: data, encoding: .utf8) else { return }
646-
TRTCCloud.sharedInstance().callExperimentalAPI(jsonStr)
647-
}
648605
}

‎call/TUICallKit_Swift/View/CallView/CallView.swift‎

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,13 @@ extension CallView {
102102
addSubview(backgroundBlurView)
103103
addSubview(callCoreView)
104104
addSubview(waitingParticipantsView)
105-
addSubview(singleCallControlsView)
106105
addSubview(multiCallControlsView)
107106
addSubview(aiSubtitle)
108107
addSubview(callTranscriberView)
109108
addSubview(timerView)
110109
addSubview(hintView)
110+
111+
callCoreView.callViewAdapter = self
111112
}
112113

113114
private func activateConstraints() {
@@ -137,11 +138,6 @@ extension CallView {
137138
make.centerY.equalToSuperview()
138139
}
139140

140-
singleCallControlsView.snp.remakeConstraints { make in
141-
make.leading.trailing.bottom.equalToSuperview()
142-
make.height.equalTo(260.scale375Height())
143-
}
144-
145141
multiCallControlsView.snp.remakeConstraints { make in
146142
make.leading.trailing.bottom.equalToSuperview()
147143
make.height.equalTo(260.scale375Height())
@@ -352,24 +348,14 @@ extension CallView {
352348
// MARK: - Subscribe
353349
extension CallView {
354350
private func subscribeCallState() {
355-
let callStateSelector = StatePublisherSelector { (state: CallState) -> (CallParticipantStatus, String, String, String, [String]) in
356-
let selfInfo = CallStore.shared.state.value.selfInfo
357-
let activeCall = state.activeCall
358-
return (selfInfo.status, selfInfo.id, activeCall.inviterId, activeCall.chatGroupId, activeCall.inviteeIds)
359-
}
360-
361-
CallStore.shared.state.subscribe(callStateSelector)
362-
.removeDuplicates { prev, current in
363-
return prev.0 == current.0 &&
364-
prev.1 == current.1 &&
365-
prev.2 == current.2 &&
366-
prev.3 == current.3 &&
367-
prev.4 == current.4
368-
}
351+
CallStore.shared.state
352+
.subscribe(StatePublisherSelector(keyPath: \.selfInfo.status))
353+
.removeDuplicates()
369354
.receive(on: RunLoop.main)
370355
.sink { [weak self] _ in
371-
self?.updateControlsView()
372-
self?.updateCamera()
356+
guard let self = self else { return }
357+
self.updateControlsView()
358+
self.updateCamera()
373359
}
374360
.store(in: &cancellables)
375361

@@ -418,3 +404,35 @@ extension CallView: MultiCallControlsViewDelegate {
418404
updateTranscriberViewConstraints()
419405
}
420406
}
407+
408+
// MARK: - CallViewAdapter
409+
extension CallView: CallViewAdapter {
410+
public func onCreateOverlayView(layout: CallLayoutTemplate) -> UIView? {
411+
guard layout == .float else { return nil }
412+
413+
let container = OverlayContainerView()
414+
container.backgroundColor = .clear
415+
container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
416+
417+
singleCallControlsView.removeFromSuperview()
418+
container.addSubview(singleCallControlsView)
419+
420+
let isSingleAudioCall = CallStore.shared.state.value.activeCall.mediaType == .audio
421+
let controlsHeight: CGFloat = isSingleAudioCall ? 144.scale375Height() : 260.scale375Height()
422+
423+
singleCallControlsView.snp.remakeConstraints { make in
424+
make.leading.trailing.bottom.equalToSuperview()
425+
make.height.equalTo(controlsHeight)
426+
}
427+
428+
return container
429+
}
430+
}
431+
432+
private final class OverlayContainerView: UIView {
433+
override func didMoveToSuperview() {
434+
super.didMoveToSuperview()
435+
guard let superview = superview else { return }
436+
frame = superview.bounds
437+
}
438+
}

0 commit comments

Comments
 (0)