@tencent-rtc/mcp 1.4.6 → 1.6.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cursor-setting.png +0 -0
- package/knowledge/bm25-cache.js +74 -0
- package/knowledge/bm25-cache.js.map +1 -0
- package/knowledge/bm25.js +148 -0
- package/knowledge/bm25.js.map +1 -0
- package/knowledge/build-index.js +70 -0
- package/knowledge/build-index.js.map +1 -0
- package/knowledge/chunker.js +168 -0
- package/knowledge/chunker.js.map +1 -0
- package/knowledge/content-loader.js +40 -0
- package/knowledge/content-loader.js.map +1 -0
- package/knowledge/doc-url-resolver.js +143 -0
- package/knowledge/doc-url-resolver.js.map +1 -0
- package/knowledge/extractors.js +26 -0
- package/knowledge/extractors.js.map +1 -0
- package/knowledge/path-meta.js +185 -0
- package/knowledge/path-meta.js.map +1 -0
- package/knowledge/search/exact-lookup.js +498 -0
- package/knowledge/search/exact-lookup.js.map +1 -0
- package/knowledge/search/filter-pool.js +105 -0
- package/knowledge/search/filter-pool.js.map +1 -0
- package/knowledge/search/product-scope-intent.js +41 -0
- package/knowledge/search/product-scope-intent.js.map +1 -0
- package/knowledge/search/requires-framework.js +82 -0
- package/knowledge/search/requires-framework.js.map +1 -0
- package/knowledge/search/search-knowledge.js +230 -0
- package/knowledge/search/search-knowledge.js.map +1 -0
- package/mcp-server-prompt.png +0 -0
- package/package.json +1 -1
- package/resource/_schema/feature-aliases.yaml +10 -0
- package/resource/_schema/goal-tags.yaml +72 -0
- package/resource/_schema/products.yaml +19 -0
- package/resource/_schema/trtc-intents.yaml +27 -0
- package/resource/_schema/types.yaml +43 -0
- package/resource/index/component-slugs.json +1 -0
- package/resource/index/doc-source-urls.json +1 -0
- package/resource/index/manifest.json +1 -0
- package/resource/{doc → integration}/callkit/preset/android/integration.md +34 -28
- package/resource/integration/callkit/preset/flutter/integration.md +346 -0
- package/resource/integration/callkit/preset/ios/integration.md +408 -0
- package/resource/integration/callkit/preset/react/integration.md +362 -0
- package/resource/integration/callkit/preset/vue/integration.md +356 -0
- package/resource/integration/chat/preset/android/integration.md +500 -0
- package/resource/integration/chat/preset/flutter/integration.md +370 -0
- package/resource/integration/chat/preset/ios/integration.md +566 -0
- package/resource/integration/chat/preset/react/integration.md +490 -0
- package/resource/integration/chat/preset/vue/integration.md +504 -0
- package/resource/{doc → integration}/livekit/preset/live/vue/live-list-integration.md +26 -22
- package/resource/{doc → integration}/livekit/preset/live/vue/live-player-desk-integration.md +22 -18
- package/resource/integration/livekit/preset/live/vue/live-player-h5-integration.md +309 -0
- package/resource/{doc → integration}/livekit/preset/live/vue/live-pusher-integration.md +47 -39
- package/resource/integration/roomkit/preset/vue/integration.md +562 -0
- package/resource/knowledge/callkit/core-sdk/android/answer-call.md +828 -0
- package/resource/knowledge/callkit/core-sdk/android/make-call.md +897 -0
- package/resource/knowledge/callkit/core-sdk/android/offline-push.md +363 -0
- package/resource/knowledge/callkit/core-sdk/flutter/answer-call.md +1111 -0
- package/resource/knowledge/callkit/core-sdk/flutter/make-call.md +1132 -0
- package/resource/{doc → knowledge}/callkit/core-sdk/flutter/offline-push.md +174 -151
- package/resource/knowledge/callkit/core-sdk/ios/answer-call.md +1084 -0
- package/resource/knowledge/callkit/core-sdk/ios/make-call.md +1252 -0
- package/resource/knowledge/callkit/core-sdk/ios/offline-push.md +534 -0
- package/resource/knowledge/callkit/core-sdk/uni-app/answer-call.md +953 -0
- package/resource/knowledge/callkit/core-sdk/uni-app/make-call.md +1061 -0
- package/resource/knowledge/callkit/faq/android.md +92 -0
- package/resource/{doc/callkit/faq/android-faq.md → knowledge/callkit/faq/common.md} +11 -12
- package/resource/knowledge/callkit/faq/error-code.md +67 -0
- package/resource/knowledge/callkit/faq/flutter.md +52 -0
- package/resource/knowledge/callkit/faq/ios.md +104 -0
- package/resource/knowledge/callkit/faq/web.md +74 -0
- package/resource/knowledge/callkit/preset/android/api.md +412 -0
- package/resource/knowledge/callkit/preset/flutter/api.md +22 -0
- package/resource/knowledge/callkit/preset/ios/api.md +234 -0
- package/resource/knowledge/callkit/preset/web/api.md +83 -0
- package/resource/knowledge/chat/preset/android/features/chat-setting.md +74 -0
- package/resource/knowledge/chat/preset/android/features/contact-list.md +43 -0
- package/resource/knowledge/chat/preset/android/features/conversation-list.md +117 -0
- package/resource/knowledge/chat/preset/android/features/language.md +136 -0
- package/resource/knowledge/chat/preset/android/features/message-input.md +57 -0
- package/resource/knowledge/chat/preset/android/features/message-list.md +142 -0
- package/resource/knowledge/chat/preset/android/features/search.md +64 -0
- package/resource/knowledge/chat/preset/android/features/theme.md +222 -0
- package/resource/knowledge/chat/preset/android-view/integration.md +300 -0
- package/resource/knowledge/chat/preset/flutter/features/chat-setting.md +64 -0
- package/resource/knowledge/chat/preset/flutter/features/contact-list.md +40 -0
- package/resource/knowledge/chat/preset/flutter/features/conversation-list.md +129 -0
- package/resource/knowledge/chat/preset/flutter/features/language.md +104 -0
- package/resource/knowledge/chat/preset/flutter/features/message-input.md +54 -0
- package/resource/knowledge/chat/preset/flutter/features/message-list.md +158 -0
- package/resource/knowledge/chat/preset/flutter/features/search.md +59 -0
- package/resource/knowledge/chat/preset/flutter/features/theme.md +261 -0
- package/resource/knowledge/chat/preset/ios/features/chat-setting.md +94 -0
- package/resource/knowledge/chat/preset/ios/features/contact-list.md +119 -0
- package/resource/knowledge/chat/preset/ios/features/conversation-list.md +134 -0
- package/resource/knowledge/chat/preset/ios/features/language.md +125 -0
- package/resource/knowledge/chat/preset/ios/features/message-input.md +69 -0
- package/resource/knowledge/chat/preset/ios/features/message-list.md +162 -0
- package/resource/knowledge/chat/preset/ios/features/search.md +93 -0
- package/resource/knowledge/chat/preset/ios/features/theme.md +270 -0
- package/resource/{doc/chatkit/ios → knowledge/chat/preset/ios-uikit}/integration.md +160 -158
- package/resource/knowledge/chat/preset/react/features/chat-setting.md +101 -0
- package/resource/{doc/chatkit/react/components → knowledge/chat/preset/react/features}/contact-list.md +43 -41
- package/resource/knowledge/chat/preset/react/features/conversation-actions.md +215 -0
- package/resource/knowledge/chat/preset/react/features/conversation-list.md +339 -0
- package/resource/knowledge/chat/preset/react/features/conversation-preview.md +101 -0
- package/resource/knowledge/chat/preset/react/features/conversation-search.md +61 -0
- package/resource/{doc/chatkit/react/components → knowledge/chat/preset/react/features}/message-input.md +117 -156
- package/resource/knowledge/chat/preset/react/features/message-list.md +297 -0
- package/resource/{doc/chatkit/react/components → knowledge/chat/preset/react/features}/search.md +65 -59
- package/resource/knowledge/chat/preset/react/features/theme.md +93 -0
- package/resource/knowledge/chat/preset/vue/features/chat-header.md +331 -0
- package/resource/knowledge/chat/preset/vue/features/chat-setting.md +79 -0
- package/resource/knowledge/chat/preset/vue/features/contact-list.md +277 -0
- package/resource/knowledge/chat/preset/vue/features/conversation-actions.md +234 -0
- package/resource/knowledge/chat/preset/vue/features/conversation-list.md +331 -0
- package/resource/knowledge/chat/preset/vue/features/conversation-preview.md +216 -0
- package/resource/{doc/chatkit/vue/components → knowledge/chat/preset/vue/features}/conversation-search.md +13 -13
- package/resource/knowledge/chat/preset/vue/features/message-input.md +551 -0
- package/resource/knowledge/chat/preset/vue/features/message-list.md +350 -0
- package/resource/{doc/chatkit/vue/components → knowledge/chat/preset/vue/features}/search.md +79 -73
- package/resource/knowledge/chat/preset/vue/features/theme.md +136 -0
- package/resource/knowledge/chat/urls/error-code.md +17 -0
- package/resource/knowledge/chat/urls/product.md +43 -0
- package/resource/knowledge/chat/urls/restapi.md +204 -0
- package/resource/knowledge/chat/urls/sdk/android.md +80 -0
- package/resource/knowledge/chat/urls/sdk/flutter.md +71 -0
- package/resource/knowledge/chat/urls/sdk/ios.md +80 -0
- package/resource/knowledge/chat/urls/sdk/web.md +80 -0
- package/resource/knowledge/chat/urls/webhook.md +68 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/AudioEffectStore.md +286 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/BarrageStore.md +174 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/BattleStore.md +329 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/CameraView.md +55 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/CoGuestStore.md +434 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/CoHostStore.md +362 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/DeviceStore.md +466 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/GiftStore.md +173 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/LikeStore.md +51 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/LiveAudienceStore.md +291 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/LiveCoreView.md +78 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/LiveSeatStore.md +488 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/android/LoginStore.md +219 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/AudioEffectStore.md +282 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/BarrageStore.md +212 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/BaseBeautyStore.md +153 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/BattleStore.md +312 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/CoGuestStore.md +404 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/CoHostStore.md +334 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/DeviceStore.md +426 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/GiftStore.md +166 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/LikeStore.md +52 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/LiveAudienceStore.md +281 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/LiveCoreView.md +150 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/LiveSeatStore.md +438 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/flutter/LoginStore.md +190 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/AudioEffectStore.md +291 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/BarrageStore.md +192 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/BaseBeautyStore.md +146 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/BattleStore.md +309 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/CoGuestStore.md +370 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/CoHostStore.md +339 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/DeviceStore.md +503 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/GiftStore.md +188 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/LikeStore.md +51 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/LiveAudienceStore.md +289 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/LiveCoreView.md +78 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/LiveSeatStore.md +487 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/ios/LoginStore.md +183 -0
- package/resource/knowledge/livekit/core-sdk/api-reference/web/index.md +736 -0
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-audience-list.md +53 -47
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-audio-effect.md +28 -24
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-barrage.md +22 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-base-beauty.md +17 -15
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-co-guest-interaction.md +19 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-gift.md +102 -89
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-host-interaction.md +41 -37
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-integration.md +45 -43
- package/resource/{doc → knowledge}/livekit/core-sdk/live/android/live-live-list.md +23 -20
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-audience-list.md +41 -41
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-audio-effect.md +70 -69
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-barrage.md +68 -71
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-base-beauty.md +43 -47
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-co-guest-interaction.md +59 -56
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-gift.md +103 -105
- package/resource/knowledge/livekit/core-sdk/live/flutter/live-host-interaction.md +869 -0
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-integration.md +84 -87
- package/resource/{doc → knowledge}/livekit/core-sdk/live/flutter/live-live-list.md +43 -40
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-audience-list.md +11 -10
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-audio-effect.md +28 -24
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-barrage.md +22 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-base-beauty.md +15 -14
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-co-guest-interaction.md +19 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-gift.md +54 -50
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-host-interaction.md +41 -37
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-integration.md +40 -40
- package/resource/{doc → knowledge}/livekit/core-sdk/live/ios/live-live-list.md +19 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-audience-list.md +53 -47
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-audio-effect.md +28 -24
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-barrage.md +22 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-co-guest-interaction.md +41 -33
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-gift.md +94 -81
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-host-interaction.md +35 -30
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-integration.md +45 -42
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/android/voice-room-list.md +23 -20
- package/resource/knowledge/livekit/core-sdk/voice/flutter/voice-audience-list.md +260 -0
- package/resource/knowledge/livekit/core-sdk/voice/flutter/voice-audio-effect.md +598 -0
- package/resource/knowledge/livekit/core-sdk/voice/flutter/voice-barrage.md +490 -0
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/flutter/voice-co-guest-interaction.md +65 -59
- package/resource/knowledge/livekit/core-sdk/voice/flutter/voice-gift.md +424 -0
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/flutter/voice-integration.md +69 -76
- package/resource/knowledge/livekit/core-sdk/voice/flutter/voice-room-list.md +726 -0
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-audience-list.md +11 -10
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-audio-effect.md +28 -24
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-barrage.md +22 -18
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-co-guest-interaction.md +41 -33
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-gift.md +54 -50
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-host-interaction.md +35 -30
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-integration.md +49 -46
- package/resource/{doc → knowledge}/livekit/core-sdk/voice/ios/voice-room-list.md +19 -18
- package/resource/knowledge/livekit/faq/error-code.md +193 -0
- package/resource/{doc/livekit/preset/live/vue/components → knowledge/livekit/preset/live/vue/features}/barrage.md +56 -53
- package/resource/{doc/livekit/preset/live/vue/components → knowledge/livekit/preset/live/vue/features}/live-audience-list.md +22 -21
- package/resource/{doc/livekit/preset/live/vue/components → knowledge/livekit/preset/live/vue/features}/live-view.md +34 -32
- package/resource/knowledge/push/config/android.md +92 -0
- package/resource/knowledge/push/config/harmonyos.md +83 -0
- package/resource/knowledge/push/config/ios.md +254 -0
- package/resource/knowledge/push/config/react-native.md +254 -0
- package/resource/knowledge/push/config/unity.md +209 -0
- package/resource/knowledge/push/config/unreal-engine.md +194 -0
- package/resource/knowledge/push/integration/android.md +404 -0
- package/resource/knowledge/push/integration/flutter.md +465 -0
- package/resource/knowledge/push/integration/harmonyos.md +63 -0
- package/resource/knowledge/push/integration/ios.md +246 -0
- package/resource/knowledge/push/integration/react-native.md +366 -0
- package/resource/knowledge/push/integration/uni-app.md +208 -0
- package/resource/knowledge/push/integration/unity.md +389 -0
- package/resource/knowledge/push/integration/unreal-engine.md +390 -0
- package/resource/knowledge/push/overview/prepare.md +60 -0
- package/resource/knowledge/roomkit/core-sdk/android/call-user-to-room.md +241 -0
- package/resource/knowledge/roomkit/core-sdk/android/room-participant-state.md +588 -0
- package/resource/knowledge/roomkit/core-sdk/android/room-state.md +364 -0
- package/resource/knowledge/roomkit/core-sdk/android/schedule-room.md +340 -0
- package/resource/knowledge/roomkit/core-sdk/flutter/call-user-to-room.md +230 -0
- package/resource/knowledge/roomkit/core-sdk/flutter/room-participant-state.md +797 -0
- package/resource/knowledge/roomkit/core-sdk/flutter/room-state.md +325 -0
- package/resource/knowledge/roomkit/core-sdk/flutter/schedule-room.md +325 -0
- package/resource/knowledge/roomkit/core-sdk/ios/call-user-to-room.md +233 -0
- package/resource/knowledge/roomkit/core-sdk/ios/room-participant-state.md +569 -0
- package/resource/knowledge/roomkit/core-sdk/ios/room-state.md +325 -0
- package/resource/knowledge/roomkit/core-sdk/ios/schedule-room.md +322 -0
- package/resource/knowledge/roomkit/core-sdk/vue/call-user-to-room.md +221 -0
- package/resource/{doc/roomkit/vue/features → knowledge/roomkit/core-sdk/vue}/device-detection.md +49 -48
- package/resource/knowledge/roomkit/core-sdk/vue/device-state.md +461 -0
- package/resource/knowledge/roomkit/core-sdk/vue/free-beauty-panel.md +216 -0
- package/resource/knowledge/roomkit/core-sdk/vue/room-chat.md +370 -0
- package/resource/{doc/roomkit/vue/features → knowledge/roomkit/core-sdk/vue}/room-participant-state.md +61 -60
- package/resource/knowledge/roomkit/core-sdk/vue/room-state.md +280 -0
- package/resource/{doc/roomkit/vue/features → knowledge/roomkit/core-sdk/vue}/room-view.md +57 -56
- package/resource/knowledge/roomkit/core-sdk/vue/schedule-room.md +319 -0
- package/resource/knowledge/roomkit/core-sdk/vue/screen-share.md +267 -0
- package/resource/knowledge/roomkit/core-sdk/vue/virtual-background.md +261 -0
- package/resource/knowledge/roomkit/preset/android/integration.md +396 -0
- package/resource/knowledge/roomkit/preset/flutter/integration.md +404 -0
- package/resource/knowledge/roomkit/preset/ios/integration.md +369 -0
- package/resource/knowledge/roomkit/preset/react/integration.md +576 -0
- package/resource/knowledge/rtcengine/web/how_to_run_web_sdk_demo.md +44 -0
- package/resource/{doc → knowledge}/rtcengine/web/plugin/21-advanced-auto-play-policy.md +8 -2
- package/resource/{doc → knowledge}/rtcengine/web/plugin/22-advanced-audio-mixer.md +19 -1
- package/resource/{doc → knowledge}/rtcengine/web/plugin/23-advanced-support-detection.md +1 -1
- package/resource/{doc → knowledge}/rtcengine/web/plugin/24-advanced-network-quality.md +8 -8
- package/resource/{doc → knowledge}/rtcengine/web/plugin/25-advanced-device-change.md +1 -1
- package/resource/{doc → knowledge}/rtcengine/web/plugin/26-advanced-publish-cdn-stream.md +6 -6
- package/resource/{doc → knowledge}/rtcengine/web/plugin/27-advanced-small-stream.md +3 -3
- package/resource/{doc → knowledge}/rtcengine/web/plugin/29-advanced-water-mark.md +18 -0
- package/resource/{doc → knowledge}/rtcengine/web/plugin/31-advanced-plugins-overview.md +1 -1
- package/resource/{doc → knowledge}/rtcengine/web/plugin/34-advanced-proxy.md +2 -2
- package/resource/{doc → knowledge}/rtcengine/web/plugin/35-advanced-ai-denoiser.md +1 -1
- package/resource/knowledge/trtc/android/TRTCCloud.md +1915 -0
- package/resource/knowledge/trtc/android/TRTCCloudDef.md +1029 -0
- package/resource/knowledge/trtc/android/TRTCCloudListener.md +1095 -0
- package/resource/knowledge/trtc/android/TRTCStatistics.md +68 -0
- package/resource/knowledge/trtc/android/TXAudioEffectManager.md +502 -0
- package/resource/knowledge/trtc/android/TXBeautyManager.md +415 -0
- package/resource/knowledge/trtc/android/TXDeviceManager.md +169 -0
- package/resource/knowledge/trtc/android/TXLiteAVCode.md +125 -0
- package/resource/knowledge/trtc/c++/ITRTCCloud.md +2069 -0
- package/resource/knowledge/trtc/c++/ITRTCStatistics.md +73 -0
- package/resource/knowledge/trtc/c++/ITXAudioEffectManager.md +502 -0
- package/resource/knowledge/trtc/c++/ITXDeviceManager.md +391 -0
- package/resource/knowledge/trtc/c++/TRTCCloudCallback.md +1191 -0
- package/resource/knowledge/trtc/c++/TRTCTypeDef.md +931 -0
- package/resource/knowledge/trtc/c++/TXLiteAVCode.md +127 -0
- package/resource/knowledge/trtc/ios/TRTCCloud.md +2118 -0
- package/resource/knowledge/trtc/ios/TRTCCloudDef.md +975 -0
- package/resource/knowledge/trtc/ios/TRTCCloudDelegate.md +1131 -0
- package/resource/knowledge/trtc/ios/TRTCStatistics.md +68 -0
- package/resource/knowledge/trtc/ios/TXAudioEffectManager.md +423 -0
- package/resource/knowledge/trtc/ios/TXBeautyManager.md +416 -0
- package/resource/knowledge/trtc/ios/TXDeviceManager.md +387 -0
- package/resource/knowledge/trtc/ios/TXLiteAVCode.md +127 -0
- package/server.js +35 -10
- package/server.js.map +1 -1
- package/tools/call/get_native_call_uikit_integration.js +2 -3
- package/tools/call/get_native_call_uikit_integration.js.map +1 -1
- package/tools/call/get_native_callkit_core_integration.js +2 -5
- package/tools/call/get_native_callkit_core_integration.js.map +1 -1
- package/tools/call/get_web_call_uikit_integration.js +2 -3
- package/tools/call/get_web_call_uikit_integration.js.map +1 -1
- package/tools/chat/get_native_chat_uikit_integration.js +2 -3
- package/tools/chat/get_native_chat_uikit_integration.js.map +1 -1
- package/tools/chat/get_web_chat_uikit_integration.js +2 -3
- package/tools/chat/get_web_chat_uikit_integration.js.map +1 -1
- package/tools/common/present_framework_choice.js +19 -13
- package/tools/common/present_framework_choice.js.map +1 -1
- package/tools/common/record_answer.js +19 -25
- package/tools/common/record_answer.js.map +1 -1
- package/tools/common/record_feedback.js +17 -30
- package/tools/common/record_feedback.js.map +1 -1
- package/tools/common/search_trtc_knowledge.js +45 -0
- package/tools/common/search_trtc_knowledge.js.map +1 -0
- package/tools/definitions/get_native_call_uikit_integration_def.js +3 -1
- package/tools/definitions/get_native_call_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_native_callkit_core_integration_def.js +5 -3
- package/tools/definitions/get_native_callkit_core_integration_def.js.map +1 -1
- package/tools/definitions/get_native_chat_uikit_integration_def.js +5 -2
- package/tools/definitions/get_native_chat_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_native_livekit_core_integration_def.js +6 -5
- package/tools/definitions/get_native_livekit_core_integration_def.js.map +1 -1
- package/tools/definitions/get_web_call_uikit_integration_def.js +4 -2
- package/tools/definitions/get_web_call_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_web_chat_uikit_integration_def.js +2 -0
- package/tools/definitions/get_web_chat_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_web_live_uikit_integration_def.js +5 -5
- package/tools/definitions/get_web_live_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_web_room_core_integration_def.js +50 -0
- package/tools/definitions/get_web_room_core_integration_def.js.map +1 -0
- package/tools/definitions/get_web_room_uikit_integration_def.js +5 -4
- package/tools/definitions/get_web_room_uikit_integration_def.js.map +1 -1
- package/tools/definitions/integration-boundary.js +6 -0
- package/tools/definitions/integration-boundary.js.map +1 -0
- package/tools/definitions/present_framework_choice_def.js +12 -10
- package/tools/definitions/present_framework_choice_def.js.map +1 -1
- package/tools/definitions/record_answer_def.js +19 -17
- package/tools/definitions/record_answer_def.js.map +1 -1
- package/tools/definitions/record_feedback_def.js +14 -13
- package/tools/definitions/record_feedback_def.js.map +1 -1
- package/tools/definitions/search_trtc_knowledge_def.js +40 -0
- package/tools/definitions/search_trtc_knowledge_def.js.map +1 -0
- package/tools/index.js +5 -36
- package/tools/index.js.map +1 -1
- package/tools/live/get_native_livekit_core_integration.js +1 -3
- package/tools/live/get_native_livekit_core_integration.js.map +1 -1
- package/tools/live/get_web_live_uikit_integration.js +2 -4
- package/tools/live/get_web_live_uikit_integration.js.map +1 -1
- package/tools/room/get_web_room_core_integration.js +48 -0
- package/tools/room/get_web_room_core_integration.js.map +1 -0
- package/tools/room/get_web_room_uikit_integration.js +2 -3
- package/tools/room/get_web_room_uikit_integration.js.map +1 -1
- package/utils/generate-structured-result.js +24 -30
- package/utils/generate-structured-result.js.map +1 -1
- package/utils/get-doc-content.js +14 -8
- package/utils/get-doc-content.js.map +1 -1
- package/utils/report-cls-client.js +18 -20
- package/utils/report-cls-client.js.map +1 -1
- package/utils/report-es-client.js +1 -1
- package/resource/doc/callkit/core-sdk/.gitkeep +0 -0
- package/resource/doc/callkit/core-sdk/android/answer-call.md +0 -852
- package/resource/doc/callkit/core-sdk/android/make-call.md +0 -954
- package/resource/doc/callkit/core-sdk/android/offline-push.md +0 -361
- package/resource/doc/callkit/core-sdk/flutter/answer-call.md +0 -1160
- package/resource/doc/callkit/core-sdk/flutter/make-call.md +0 -1205
- package/resource/doc/callkit/core-sdk/ios/answer-call.md +0 -1090
- package/resource/doc/callkit/core-sdk/ios/make-call.md +0 -1248
- package/resource/doc/callkit/core-sdk/ios/offline-push.md +0 -485
- package/resource/doc/callkit/core-sdk/uni-app/answer-call.md +0 -950
- package/resource/doc/callkit/core-sdk/uni-app/make-call.md +0 -1052
- package/resource/doc/callkit/faq/common/error-code.md +0 -47
- package/resource/doc/callkit/faq/flutter-faq.md +0 -115
- package/resource/doc/callkit/faq/ios-faq.md +0 -115
- package/resource/doc/callkit/faq/web-faq.md +0 -36
- package/resource/doc/callkit/preset/android/api.md +0 -296
- package/resource/doc/callkit/preset/flutter/api.md +0 -410
- package/resource/doc/callkit/preset/flutter/integration.md +0 -164
- package/resource/doc/callkit/preset/ios/api.md +0 -80
- package/resource/doc/callkit/preset/ios/integration.md +0 -187
- package/resource/doc/callkit/preset/react/api.md +0 -501
- package/resource/doc/callkit/preset/react/integration.md +0 -86
- package/resource/doc/callkit/preset/vue/api.md +0 -501
- package/resource/doc/callkit/preset/vue/integration.md +0 -83
- package/resource/doc/chatkit/android/faq.md +0 -111
- package/resource/doc/chatkit/android/features/theme.md +0 -219
- package/resource/doc/chatkit/android/integration.md +0 -490
- package/resource/doc/chatkit/faq/android_sdk/client-api.md +0 -281
- package/resource/doc/chatkit/faq/common/product.md +0 -7
- package/resource/doc/chatkit/faq/common/server.md +0 -44
- package/resource/doc/chatkit/faq/common/server_error_code.md +0 -74
- package/resource/doc/chatkit/faq/flutter_sdk/client-api.md +0 -199
- package/resource/doc/chatkit/faq/flutter_sdk/faq.md +0 -53
- package/resource/doc/chatkit/faq/ios_sdk/client-api.md +0 -235
- package/resource/doc/chatkit/faq/web_sdk/error_code.md +0 -47
- package/resource/doc/chatkit/faq/web_sdk/faq.md +0 -287
- package/resource/doc/chatkit/flutter/faq.md +0 -23
- package/resource/doc/chatkit/flutter/features/theme.md +0 -235
- package/resource/doc/chatkit/flutter/integration.md +0 -344
- package/resource/doc/chatkit/ios/faq.md +0 -111
- package/resource/doc/chatkit/ios/features/theme.md +0 -267
- package/resource/doc/chatkit/react/components/avatar.md +0 -104
- package/resource/doc/chatkit/react/components/chat-header.md +0 -148
- package/resource/doc/chatkit/react/components/chat-setting.md +0 -57
- package/resource/doc/chatkit/react/components/chat.md +0 -38
- package/resource/doc/chatkit/react/components/component-list.md +0 -37
- package/resource/doc/chatkit/react/components/conversation-actions.md +0 -174
- package/resource/doc/chatkit/react/components/conversation-list.md +0 -333
- package/resource/doc/chatkit/react/components/conversation-preview.md +0 -118
- package/resource/doc/chatkit/react/components/conversation-search.md +0 -60
- package/resource/doc/chatkit/react/components/message-list.md +0 -293
- package/resource/doc/chatkit/react/components/tuikit.md +0 -34
- package/resource/doc/chatkit/react/faq.md +0 -26
- package/resource/doc/chatkit/react/integration.md +0 -416
- package/resource/doc/chatkit/vue/components/avatar.md +0 -104
- package/resource/doc/chatkit/vue/components/chat-header.md +0 -148
- package/resource/doc/chatkit/vue/components/chat-setting.md +0 -62
- package/resource/doc/chatkit/vue/components/chat.md +0 -45
- package/resource/doc/chatkit/vue/components/component-list.md +0 -87
- package/resource/doc/chatkit/vue/components/contact-list.md +0 -271
- package/resource/doc/chatkit/vue/components/conversation-actions.md +0 -228
- package/resource/doc/chatkit/vue/components/conversation-list.md +0 -320
- package/resource/doc/chatkit/vue/components/conversation-preview.md +0 -213
- package/resource/doc/chatkit/vue/components/message-input.md +0 -1054
- package/resource/doc/chatkit/vue/components/message-list.md +0 -433
- package/resource/doc/chatkit/vue/components/tuikit.md +0 -31
- package/resource/doc/chatkit/vue/components/userpicker.md +0 -256
- package/resource/doc/chatkit/vue/faq.md +0 -36
- package/resource/doc/chatkit/vue/integration.md +0 -428
- package/resource/doc/livekit/core-sdk/live/flutter/live-host-interaction.md +0 -866
- package/resource/doc/livekit/faq/common/error-code.md +0 -88
- package/resource/doc/livekit/preset/live/vue/api-reference/index.md +0 -780
- package/resource/doc/livekit/preset/live/vue/components/co-guest-panel.md +0 -91
- package/resource/doc/livekit/preset/live/vue/components/live-scene-panel.md +0 -112
- package/resource/doc/livekit/preset/live/vue/components/stream-mixer.md +0 -215
- package/resource/doc/livekit/preset/live/vue/live-player-h5-integration.md +0 -300
- package/resource/doc/roomkit/faq/common/error-code.md +0 -67
- package/resource/doc/roomkit/vue/features/call-user-to-room.md +0 -220
- package/resource/doc/roomkit/vue/features/device-state.md +0 -460
- package/resource/doc/roomkit/vue/features/free-beauty-panel.md +0 -215
- package/resource/doc/roomkit/vue/features/room-chat.md +0 -369
- package/resource/doc/roomkit/vue/features/room-state.md +0 -282
- package/resource/doc/roomkit/vue/features/schedule-room.md +0 -318
- package/resource/doc/roomkit/vue/features/screen-share.md +0 -265
- package/resource/doc/roomkit/vue/features/virtual-background.md +0 -271
- package/resource/doc/roomkit/vue/integration.md +0 -315
- package/resource/doc/rtcengine/faq/common/error_code.md +0 -1
- package/resource/doc/rtcengine/faq/web_sdk/.gitkeep +0 -0
- package/resource/doc/rtcengine/web/.gitkeep +0 -0
- package/resource/doc/rtcengine/web/how_to_run_web_sdk_demo.md +0 -59
- package/resource/doc/trtc/C++/ITRTCCloud.md +0 -1970
- package/resource/doc/trtc/C++/ITRTCStatistics.md +0 -70
- package/resource/doc/trtc/C++/ITXAudioEffectManager.md +0 -469
- package/resource/doc/trtc/C++/ITXDeviceManager.md +0 -387
- package/resource/doc/trtc/C++/TRTCCloudCallback.md +0 -1082
- package/resource/doc/trtc/C++/TRTCTypeDef.md +0 -925
- package/resource/doc/trtc/C++/TXLiteAVCode.md +0 -129
- package/resource/doc/trtc/android/TRTCCloud.md +0 -1815
- package/resource/doc/trtc/android/TRTCCloudDef.md +0 -992
- package/resource/doc/trtc/android/TRTCCloudListener.md +0 -1004
- package/resource/doc/trtc/android/TRTCStatistics.md +0 -65
- package/resource/doc/trtc/android/TXAudioEffectManager.md +0 -469
- package/resource/doc/trtc/android/TXBeautyManager.md +0 -402
- package/resource/doc/trtc/android/TXDeviceManager.md +0 -173
- package/resource/doc/trtc/android/TXLiteAVCode.md +0 -127
- package/resource/doc/trtc/iOS/TRTCCloud.md +0 -2028
- package/resource/doc/trtc/iOS/TRTCCloudDef.md +0 -958
- package/resource/doc/trtc/iOS/TRTCCloudDelegate.md +0 -1046
- package/resource/doc/trtc/iOS/TRTCStatistics.md +0 -65
- package/resource/doc/trtc/iOS/TXAudioEffectManager.md +0 -397
- package/resource/doc/trtc/iOS/TXBeautyManager.md +0 -403
- package/resource/doc/trtc/iOS/TXDeviceManager.md +0 -381
- package/resource/doc/trtc/iOS/TXLiteAVCode.md +0 -130
- package/tools/call/get_callkit_api.js +0 -33
- package/tools/call/get_callkit_api.js.map +0 -1
- package/tools/chat/get_native_chat_uikit_feature_detail.js +0 -35
- package/tools/chat/get_native_chat_uikit_feature_detail.js.map +0 -1
- package/tools/chat/get_web_chat_uikit_component_detail.js +0 -35
- package/tools/chat/get_web_chat_uikit_component_detail.js.map +0 -1
- package/tools/common/get_faq.js +0 -266
- package/tools/common/get_faq.js.map +0 -1
- package/tools/common/record_skill_session.js +0 -69
- package/tools/common/record_skill_session.js.map +0 -1
- package/tools/definitions/get_callkit_api_def.js +0 -29
- package/tools/definitions/get_callkit_api_def.js.map +0 -1
- package/tools/definitions/get_faq_def.js +0 -49
- package/tools/definitions/get_faq_def.js.map +0 -1
- package/tools/definitions/get_native_chat_uikit_feature_detail_def.js +0 -31
- package/tools/definitions/get_native_chat_uikit_feature_detail_def.js.map +0 -1
- package/tools/definitions/get_native_livekit_core_features_def.js +0 -34
- package/tools/definitions/get_native_livekit_core_features_def.js.map +0 -1
- package/tools/definitions/get_native_trtc_sdk_docs_def.js +0 -32
- package/tools/definitions/get_native_trtc_sdk_docs_def.js.map +0 -1
- package/tools/definitions/get_web_chat_uikit_component_detail_def.js +0 -31
- package/tools/definitions/get_web_chat_uikit_component_detail_def.js.map +0 -1
- package/tools/definitions/get_web_livekit_api_def.js +0 -30
- package/tools/definitions/get_web_livekit_api_def.js.map +0 -1
- package/tools/definitions/get_web_livekit_component_detail_def.js +0 -32
- package/tools/definitions/get_web_livekit_component_detail_def.js.map +0 -1
- package/tools/definitions/get_web_roomkit_feature_detail_def.js +0 -31
- package/tools/definitions/get_web_roomkit_feature_detail_def.js.map +0 -1
- package/tools/definitions/get_web_trtc_sdk_api_def.js +0 -27
- package/tools/definitions/get_web_trtc_sdk_api_def.js.map +0 -1
- package/tools/definitions/get_web_trtc_sdk_integration_def.js +0 -27
- package/tools/definitions/get_web_trtc_sdk_integration_def.js.map +0 -1
- package/tools/definitions/get_web_trtc_sdk_plugin_def.js +0 -27
- package/tools/definitions/get_web_trtc_sdk_plugin_def.js.map +0 -1
- package/tools/definitions/record_skill_session_def.js +0 -31
- package/tools/definitions/record_skill_session_def.js.map +0 -1
- package/tools/live/get_native_livekit_core_features.js +0 -68
- package/tools/live/get_native_livekit_core_features.js.map +0 -1
- package/tools/live/get_web_livekit_api.js +0 -33
- package/tools/live/get_web_livekit_api.js.map +0 -1
- package/tools/live/get_web_livekit_component_detail.js +0 -35
- package/tools/live/get_web_livekit_component_detail.js.map +0 -1
- package/tools/room/get_web_roomkit_feature_detail.js +0 -69
- package/tools/room/get_web_roomkit_feature_detail.js.map +0 -1
- package/tools/rtcengine/get_web_trtc_sdk_api.js +0 -32
- package/tools/rtcengine/get_web_trtc_sdk_api.js.map +0 -1
- package/tools/rtcengine/get_web_trtc_sdk_integration.js +0 -32
- package/tools/rtcengine/get_web_trtc_sdk_integration.js.map +0 -1
- package/tools/rtcengine/get_web_trtc_sdk_plugin.js +0 -32
- package/tools/rtcengine/get_web_trtc_sdk_plugin.js.map +0 -1
- package/tools/trtc/get_native_trtc_sdk_docs.js +0 -74
- package/tools/trtc/get_native_trtc_sdk_docs.js.map +0 -1
- package/utils/build-session-directives.js +0 -120
- package/utils/build-session-directives.js.map +0 -1
- package/utils/handle-framework.js +0 -9
- package/utils/handle-framework.js.map +0 -1
- package/utils/handle-state-name.js +0 -29
- package/utils/handle-state-name.js.map +0 -1
- package/utils/report-runtime-error-cls-client.js +0 -91
- package/utils/report-runtime-error-cls-client.js.map +0 -1
- /package/resource/{doc/livekit/preset/live/vue/faq.md → knowledge/push/config/donut.md} +0 -0
- /package/resource/{doc/roomkit/vue/faq.md → knowledge/push/integration/donut.md} +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/api.md +0 -0
- /package/resource/{doc/rtcengine/faq/web/web.md → knowledge/rtcengine/web/faq.md} +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/how_to_integrated_web_sdk.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/20-advanced-customized-capture-rendering.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/28-advanced-beauty.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/30-advanced-cross-room-link.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/36-advanced-virtual-background.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/37-advanced-voice-changer.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/39-advanced-video-decoder.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/40-advanced-video-mixer.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/41-advanced-small-stream-auto-switcher.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/42-advanced-realtime-transcriber.md +0 -0
- /package/resource/{doc → knowledge}/rtcengine/web/plugin/43-advanced-face-detection.md +0 -0
|
@@ -0,0 +1,1252 @@
|
|
|
1
|
+
This guide walks you through implementing the "Make a Call" feature using the **AtomicXCore SDK**, leveraging the **DeviceStore**, **CallStore**, and the core UI component **CallCoreView**.
|
|
2
|
+
|
|
3
|
+
## Core Features
|
|
4
|
+
|
|
5
|
+
To build multi-party audio/video calling scenarios with **AtomicXCore**, you’ll use the following three core modules:
|
|
6
|
+
|
|
7
|
+
|**Module**|**Description**|
|
|
8
|
+
|---------|---------|
|
|
9
|
+
|[CallCoreView](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview)|Core call UI component. Automatically observes CallStore data and renders video streams, with support for UI customization such as layout switching, avatar and icon configuration.|
|
|
10
|
+
|[CallStore](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstore)|Manages the call lifecycle: make, answer, reject, and hang up calls. Provides real-time access to participant audio/video status, call duration, call history, and more.|
|
|
11
|
+
|[DeviceStore](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore)|Controls audio/video devices: microphone (toggle/on/off, volume), camera (toggle/on/off, switch, quality), screen sharing, and real-time device status monitoring.|
|
|
12
|
+
|
|
13
|
+
## Getting Started
|
|
14
|
+
|
|
15
|
+
### Step 1: Activate the Service
|
|
16
|
+
|
|
17
|
+
Follow the Activate the service guide to obtain either a trial or paid version of the SDK.
|
|
18
|
+
|
|
19
|
+
### Step 2: Integrate the SDK
|
|
20
|
+
1. **Add Pod dependency:** Add `pod 'AtomicXCore'` to your project's `Podfile`.
|
|
21
|
+
|
|
22
|
+
``` ruby
|
|
23
|
+
target 'YourProjectTarget' do
|
|
24
|
+
pod 'AtomicXCore'
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> **Tips:**
|
|
29
|
+
>
|
|
30
|
+
|
|
31
|
+
> If your project doesn’t have a Podfile, navigate to your `.xcodeproj` directory in the terminal and run `pod init` to create one.
|
|
32
|
+
>
|
|
33
|
+
|
|
34
|
+
2. **Install the component:** In the terminal, go to the directory containing your Podfile and run:
|
|
35
|
+
|
|
36
|
+
``` bash
|
|
37
|
+
pod install --repo-update
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
> **Tips:**
|
|
41
|
+
>
|
|
42
|
+
|
|
43
|
+
> After installation, open your project using the `YourProjectName.xcworkspace` file.
|
|
44
|
+
>
|
|
45
|
+
|
|
46
|
+
### Step 3: Initialize and Log In
|
|
47
|
+
|
|
48
|
+
To start the call service, initialize CallStore and log in the user in sequence. CallStore automatically syncs user information after a successful login and enters the ready state. The following flowchart and sample code illustrate the process:
|
|
49
|
+
|
|
50
|
+
``` swift
|
|
51
|
+
import UIKit
|
|
52
|
+
import AtomicXCore
|
|
53
|
+
import Combine
|
|
54
|
+
|
|
55
|
+
class ViewController: UIViewController {
|
|
56
|
+
var cancellables = Set<AnyCancellable>()
|
|
57
|
+
|
|
58
|
+
override func viewDidLoad() {
|
|
59
|
+
super.viewDidLoad()
|
|
60
|
+
// Initialize CallStore
|
|
61
|
+
let _ = CallStore.shared
|
|
62
|
+
|
|
63
|
+
// Set up user information
|
|
64
|
+
let userID = "test_001" // Replace with your UserID
|
|
65
|
+
let sdkAppID: Int = 1400000001 // Replace with your SDKAppID from the console
|
|
66
|
+
let secretKey = "**************" // Replace with your SecretKey from the console
|
|
67
|
+
|
|
68
|
+
// Generate UserSig (for local testing only; always generate UserSig on your server in production)
|
|
69
|
+
let userSig = GenerateTestUserSig.genTestUserSig(
|
|
70
|
+
userID: userID,
|
|
71
|
+
sdkAppID: sdkAppID,
|
|
72
|
+
secretKey: secretKey
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
// Log in
|
|
76
|
+
LoginStore.shared.login(
|
|
77
|
+
sdkAppID: sdkAppID,
|
|
78
|
+
userID: userID,
|
|
79
|
+
userSig: userSig
|
|
80
|
+
) { result in
|
|
81
|
+
switch result {
|
|
82
|
+
case .success:
|
|
83
|
+
Log.info("login success")
|
|
84
|
+
// Initialize TUICallEngine
|
|
85
|
+
TUICallEngine.createInstance().`init`(Int32(sdkAppID), userId: userID, userSig: userSig) {
|
|
86
|
+
Log.info("TUICallEngine init success")
|
|
87
|
+
} fail: { code, message in
|
|
88
|
+
Log.error("TUICallEngine init failed, code: \(code), message: \(message ?? "")")
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
case .failure(let error):
|
|
92
|
+
Log.error("login failed, code: \(error.code), error: \(error.message)")
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
| <strong>Parameter</strong> | <strong>Type</strong> | <strong>Description</strong> |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| userID | String | Unique identifier for the current user. Only letters, numbers, hyphens, and underscores are allowed. Avoid using simple IDs like 1 or 123 to prevent multi-device login conflicts. |
|
|
101
|
+
| sdkAppID | int | Obtain from the <a href="https://trtc.io/login?fro=gt&s_url=https%3A%2F%2Fconsole.trtc.io%2F">console</a>. |
|
|
102
|
+
| secretKey | String | SDKSecretKey for your audio/video application, created in the <a href="https://trtc.io/login?fro=gt&s_url=https%3A%2F%2Fconsole.trtc.io%2F">console</a>. |
|
|
103
|
+
| userSig | String | Authentication token for TRTC.<br>- Development: Use the local <a href="https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/application/Debug/GenerateTestUserSig.swift">GenerateTestUserSig.genTestUserSig</a> function or the <a href="https://console.trtc.io/usersig">UserSig Tool</a> to generate a temporary UserSig.<br>- Production: Always generate UserSig server-side to prevent SecretKey leakage. See Server-side UserSig Generation. For more details, see How to calculate and use UserSig. |
|
|
104
|
+
|
|
105
|
+
## Implementation Steps
|
|
106
|
+
|
|
107
|
+
**Before making a call, ensure the user is logged in**—this is required for the service to function. The following five steps outline how to implement the "Make a Call" feature.
|
|
108
|
+
|
|
109
|
+
### Step 1: Create the Call Interface
|
|
110
|
+
|
|
111
|
+
You need to create a call screen that is displayed when a call is initiated.
|
|
112
|
+
1. **Create the call screen:** Implement a new UIViewController to serve as the call interface. This will be used for both outgoing and incoming calls.
|
|
113
|
+
|
|
114
|
+
2. **Attach **[CallCoreView](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview/)**:** Add the core call view component to your call screen. CallCoreView automatically observes **CallStore** data and renders video streams, with options for customizing layout, avatars, and icons.
|
|
115
|
+
|
|
116
|
+
``` swift
|
|
117
|
+
import UIKit
|
|
118
|
+
import AtomicXCore
|
|
119
|
+
|
|
120
|
+
class CallViewController: UIViewController {
|
|
121
|
+
override func viewDidLoad() {
|
|
122
|
+
super.viewDidLoad()
|
|
123
|
+
view.backgroundColor = .black
|
|
124
|
+
// Attach CallCoreView to the call screen
|
|
125
|
+
callCoreView = CallCoreView(frame: view.bounds)
|
|
126
|
+
callCoreView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
127
|
+
if let callCoreView = callCoreView {
|
|
128
|
+
view.addSubview(callCoreView)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**CallCoreView Feature Overview:**
|
|
135
|
+
|
|
136
|
+
|**Feature**|**Description**|**Reference**|
|
|
137
|
+
|---------|---------|---------|
|
|
138
|
+
|Set Layout Mode|Switch between layout modes. If not set, layout adapts automatically based on participant count.|Switch Layout Mode|
|
|
139
|
+
|Set Avatar|Customize avatars for specific users by providing avatar resource paths.|Customize Default Avatar|
|
|
140
|
+
|Set Volume Indicator Icon|Set custom volume indicator icons for different volume levels.|Customize Volume Indicator Icon|
|
|
141
|
+
|Set Network Indicator Icon|Set network status indicator icons based on real-time network quality.|Customize Network Indicator Icon|
|
|
142
|
+
|Set Waiting Animation for Users|Support GIF animations for users in waiting state during multi-party calls.|Step 2: Add Call Control Buttons|
|
|
143
|
+
|
|
144
|
+
### Step 2: Add Call Control Buttons
|
|
145
|
+
|
|
146
|
+
Use the APIs from [**DeviceStore**](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore) and [**CallStore**](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstore) to implement custom call control buttons.
|
|
147
|
+
- **DeviceStore Controls:** Microphone (toggle/on/off, volume), camera (toggle/on/off, switch, quality), screen sharing, and real-time device status monitoring. Bind button actions to the corresponding methods, and update button UI in real time by observing device status changes.
|
|
148
|
+
|
|
149
|
+
- **CallStore Controls:** Answer, hang up, reject, and other core call actions. Bind button actions to the appropriate methods and observe call status to keep the UI in sync.
|
|
150
|
+
|
|
151
|
+
- **Icon Resources:** Download button icons from [GitHub](http://github.com/Tencent-RTC/TUIKit_iOS/tree/main/call/TUICallKit_Swift/Resources/Assets.xcassets). These icons are designed for TUICallKit and are free to use.
|
|
152
|
+
|
|
153
|
+
| <strong>Icons:</strong> | | | | | | | | |
|
|
154
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
155
|
+
|
|
156
|
+
- **Example: Adding Hang Up, Microphone, and Camera Buttons**
|
|
157
|
+
|
|
158
|
+
1. **Add Hang Up Button:** Create and add a hang up button. When tapped, call `hangup` and close the call screen.
|
|
159
|
+
|
|
160
|
+
``` swift
|
|
161
|
+
import UIKit
|
|
162
|
+
import AtomicXCore
|
|
163
|
+
import Combine
|
|
164
|
+
|
|
165
|
+
class CallViewController: UIViewController {
|
|
166
|
+
private lazy var buttonHangup: UIButton = {
|
|
167
|
+
let buttonWidth: CGFloat = 80
|
|
168
|
+
let buttonHeight: CGFloat = 80
|
|
169
|
+
let spacing: CGFloat = 30
|
|
170
|
+
let bottomMargin: CGFloat = 80
|
|
171
|
+
|
|
172
|
+
let totalWidth = buttonWidth * 3 + spacing * 2
|
|
173
|
+
let startX = (view.bounds.width - totalWidth) / 2
|
|
174
|
+
let buttonY = view.bounds.height - bottomMargin - buttonHeight
|
|
175
|
+
|
|
176
|
+
let button = createButton(
|
|
177
|
+
frame: CGRect(x: startX + (buttonWidth + spacing) * 2, y: buttonY, width: buttonWidth, height: buttonHeight),
|
|
178
|
+
title: "hangup"
|
|
179
|
+
)
|
|
180
|
+
button.backgroundColor = .systemRed
|
|
181
|
+
button.addTarget(self, action: #selector(touchHangupButton), for: .touchUpInside)
|
|
182
|
+
return button
|
|
183
|
+
}()
|
|
184
|
+
|
|
185
|
+
override func viewDidLoad() {
|
|
186
|
+
super.viewDidLoad()
|
|
187
|
+
// Other initialization code
|
|
188
|
+
// 1. Add a hang-up button
|
|
189
|
+
view.addSubview(buttonHangup)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
@objc private func touchHangupButton() {
|
|
193
|
+
// 2. Call the hangup API in the click event and destroy the page
|
|
194
|
+
CallStore.shared.hangup(completion: nil)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private func createButton(frame: CGRect, title: String) -> UIButton {
|
|
198
|
+
let button = UIButton(type: .system)
|
|
199
|
+
button.frame = frame
|
|
200
|
+
button.setTitle(title, for: .normal)
|
|
201
|
+
button.setTitleColor(.white, for: .normal)
|
|
202
|
+
button.backgroundColor = UIColor(white: 0.3, alpha: 0.8)
|
|
203
|
+
button.layer.cornerRadius = frame.width / 2
|
|
204
|
+
button.titleLabel?.font = UIFont.systemFont(ofSize: 14)
|
|
205
|
+
return button
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
2. **Add Microphone Toggle Button:** Create and add a microphone toggle button. When tapped, call [openLocalMicrophone](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore/openlocalmicrophone(completion:)) or [closeLocalMicrophone](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore/closelocalmicrophone()).
|
|
210
|
+
|
|
211
|
+
``` swift
|
|
212
|
+
import UIKit
|
|
213
|
+
import AtomicXCore
|
|
214
|
+
import Combine
|
|
215
|
+
|
|
216
|
+
class CallViewController: UIViewController {
|
|
217
|
+
private lazy var buttonMicrophone: UIButton = {
|
|
218
|
+
let buttonWidth: CGFloat = 80
|
|
219
|
+
let buttonHeight: CGFloat = 80
|
|
220
|
+
let spacing: CGFloat = 30
|
|
221
|
+
let bottomMargin: CGFloat = 80
|
|
222
|
+
let totalWidth = buttonWidth * 3 + spacing * 2
|
|
223
|
+
let startX = (view.bounds.width - totalWidth) / 2
|
|
224
|
+
let buttonY = view.bounds.height - bottomMargin - buttonHeight
|
|
225
|
+
|
|
226
|
+
let button = createButton(
|
|
227
|
+
frame: CGRect(x: startX + buttonWidth + spacing, y: buttonY, width: buttonWidth, height: buttonHeight),
|
|
228
|
+
title: "Microphone"
|
|
229
|
+
)
|
|
230
|
+
button.addTarget(self, action: #selector(touchMicrophoneButton), for: .touchUpInside)
|
|
231
|
+
return button
|
|
232
|
+
}()
|
|
233
|
+
|
|
234
|
+
override func viewDidLoad() {
|
|
235
|
+
super.viewDidLoad()
|
|
236
|
+
// Other initialization code
|
|
237
|
+
// 1. Add a microphone toggle button
|
|
238
|
+
view.addSubview(buttonMicrophone)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// 2. Toggle the microphone (on/off) in the click event
|
|
242
|
+
@objc private func touchMicrophoneButton() {
|
|
243
|
+
let microphoneStatus = DeviceStore.shared.state.value.microphoneStatus
|
|
244
|
+
if microphoneStatus == .on {
|
|
245
|
+
DeviceStore.shared.closeLocalMicrophone()
|
|
246
|
+
} else {
|
|
247
|
+
DeviceStore.shared.openLocalMicrophone(completion: nil)
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Helper method to create circular buttons
|
|
252
|
+
private func createButton(frame: CGRect, title: String) -> UIButton {
|
|
253
|
+
let button = UIButton(type: .system)
|
|
254
|
+
button.frame = frame
|
|
255
|
+
button.setTitle(title, for: .normal)
|
|
256
|
+
button.setTitleColor(.white, for: .normal)
|
|
257
|
+
button.backgroundColor = UIColor(white: 0.3, alpha: 0.8)
|
|
258
|
+
button.layer.cornerRadius = frame.width / 2
|
|
259
|
+
button.titleLabel?.font = UIFont.systemFont(ofSize: 14)
|
|
260
|
+
return button
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
3. **Add Camera Toggle Button:** Add a camera toggle button to the bottom toolbar. When tapped, call [openLocalCamera](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore/openlocalcamera(isfront:completion:)) or [closeLocalCamera](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore/closelocalcamera()).
|
|
265
|
+
|
|
266
|
+
``` swift
|
|
267
|
+
import UIKit
|
|
268
|
+
import AtomicXCore
|
|
269
|
+
import Combine
|
|
270
|
+
|
|
271
|
+
class CallViewController: UIViewController {
|
|
272
|
+
private lazy var buttonCamera: UIButton = {
|
|
273
|
+
let buttonWidth: CGFloat = 80
|
|
274
|
+
let buttonHeight: CGFloat = 80
|
|
275
|
+
let spacing: CGFloat = 30
|
|
276
|
+
let bottomMargin: CGFloat = 80
|
|
277
|
+
let totalWidth = buttonWidth * 3 + spacing * 2
|
|
278
|
+
let startX = (view.bounds.width - totalWidth) / 2
|
|
279
|
+
let buttonY = view.bounds.height - bottomMargin - buttonHeight
|
|
280
|
+
|
|
281
|
+
let button = createButton(
|
|
282
|
+
frame: CGRect(x: startX, y: buttonY, width: buttonWidth, height: buttonHeight),
|
|
283
|
+
title: "Camera" // Camera
|
|
284
|
+
)
|
|
285
|
+
button.addTarget(self, action: #selector(touchCameraButton), for: .touchUpInside)
|
|
286
|
+
return button
|
|
287
|
+
}()
|
|
288
|
+
|
|
289
|
+
override func viewDidLoad() {
|
|
290
|
+
super.viewDidLoad()
|
|
291
|
+
// Other initialization code
|
|
292
|
+
// 1. Add camera toggle button
|
|
293
|
+
view.addSubview(buttonCamera)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 2. Camera button click event
|
|
297
|
+
@objc private func touchCameraButton() {
|
|
298
|
+
let cameraStatus = DeviceStore.shared.state.value.cameraStatus
|
|
299
|
+
if cameraStatus == .on {
|
|
300
|
+
DeviceStore.shared.closeLocalCamera()
|
|
301
|
+
} else {
|
|
302
|
+
let isFront = DeviceStore.shared.state.value.isFrontCamera
|
|
303
|
+
DeviceStore.shared.openLocalCamera(isFront: isFront, completion: nil)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Helper method to create circular buttons
|
|
308
|
+
private func createButton(frame: CGRect, title: String) -> UIButton {
|
|
309
|
+
let button = UIButton(type: .system)
|
|
310
|
+
button.frame = frame
|
|
311
|
+
button.setTitle(title, for: .normal)
|
|
312
|
+
button.setTitleColor(.white, for: .normal)
|
|
313
|
+
button.backgroundColor = UIColor(white: 0.3, alpha: 0.8)
|
|
314
|
+
button.layer.cornerRadius = frame.width / 2
|
|
315
|
+
button.titleLabel?.font = UIFont.systemFont(ofSize: 14)
|
|
316
|
+
return button
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
4. **Update Button Labels in Real Time:** Observe microphone and camera status and update button labels accordingly.
|
|
321
|
+
|
|
322
|
+
``` swift
|
|
323
|
+
import UIKit
|
|
324
|
+
import AtomicXCore
|
|
325
|
+
import Combine
|
|
326
|
+
|
|
327
|
+
class CallViewController: UIViewController {
|
|
328
|
+
private var cancellables = Set<AnyCancellable>()
|
|
329
|
+
|
|
330
|
+
override func viewDidLoad() {
|
|
331
|
+
super.viewDidLoad()
|
|
332
|
+
// Other initialization code
|
|
333
|
+
// 1. Observe microphone and camera status
|
|
334
|
+
observeDeviceState()
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private func observeDeviceState() {
|
|
338
|
+
DeviceStore.shared.state.subscribe()
|
|
339
|
+
.map { $0.cameraStatus }
|
|
340
|
+
.removeDuplicates()
|
|
341
|
+
.receive(on: DispatchQueue.main)
|
|
342
|
+
.sink { [weak self] cameraStatus in
|
|
343
|
+
// 2. Update camera button text
|
|
344
|
+
let title = cameraStatus == .on ? "Turn Off Camera" : "Turn On Camera"
|
|
345
|
+
self?.buttonCamera?.setTitle(title, for: .normal)
|
|
346
|
+
}
|
|
347
|
+
.store(in: &cancellables)
|
|
348
|
+
|
|
349
|
+
DeviceStore.shared.state.subscribe()
|
|
350
|
+
.map { $0.microphoneStatus }
|
|
351
|
+
.removeDuplicates()
|
|
352
|
+
.receive(on: DispatchQueue.main)
|
|
353
|
+
.sink { [weak self] microphoneStatus in
|
|
354
|
+
// 2. Update microphone button text
|
|
355
|
+
let title = microphoneStatus == .on ? "Turn Off Mic" : "Turn On Mic"
|
|
356
|
+
self?.buttonMicrophone?.setTitle(title, for: .normal)
|
|
357
|
+
}
|
|
358
|
+
.store(in: &cancellables)
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Step 3: Request Microphone/Camera Permissions
|
|
364
|
+
|
|
365
|
+
Check for audio/video permissions before starting a call. If permissions are missing, prompt the user to grant them.
|
|
366
|
+
1. **Declare permissions:** Add the following keys to your app’s `Info.plist` with appropriate usage descriptions. These will be shown to users when the system requests permissions:
|
|
367
|
+
|
|
368
|
+
``` xml
|
|
369
|
+
<key>NSCameraUsageDescription</key>
|
|
370
|
+
<string>Camera access is required for video calls and group video calls.</string>
|
|
371
|
+
<key>NSMicrophoneUsageDescription</key>
|
|
372
|
+
<string>Microphone access is required for audio calls, group audio calls, video calls, and group video calls.</string>
|
|
373
|
+
```
|
|
374
|
+
2. **Request permissions dynamically:** Request audio/video permissions based on the call media type when initiating a call.
|
|
375
|
+
|
|
376
|
+
``` swift
|
|
377
|
+
import AVFoundation
|
|
378
|
+
import UIKit
|
|
379
|
+
|
|
380
|
+
extension UIViewController {
|
|
381
|
+
|
|
382
|
+
// Check microphone permission
|
|
383
|
+
func checkMicrophonePermission(completion: @escaping (Bool) -> Void) {
|
|
384
|
+
let status = AVCaptureDevice.authorizationStatus(for: .audio)
|
|
385
|
+
|
|
386
|
+
switch status {
|
|
387
|
+
case .authorized:
|
|
388
|
+
completion(true)
|
|
389
|
+
|
|
390
|
+
case .notDetermined:
|
|
391
|
+
AVCaptureDevice.requestAccess(for: .audio) { granted in
|
|
392
|
+
DispatchQueue.main.async {
|
|
393
|
+
completion(granted)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
case .denied, .restricted:
|
|
398
|
+
completion(false)
|
|
399
|
+
|
|
400
|
+
@unknown default:
|
|
401
|
+
completion(false)
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Check camera permission
|
|
406
|
+
func checkCameraPermission(completion: @escaping (Bool) -> Void) {
|
|
407
|
+
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
|
408
|
+
|
|
409
|
+
switch status {
|
|
410
|
+
case .authorized:
|
|
411
|
+
completion(true)
|
|
412
|
+
|
|
413
|
+
case .notDetermined:
|
|
414
|
+
AVCaptureDevice.requestAccess(for: .video) { granted in
|
|
415
|
+
DispatchQueue.main.async {
|
|
416
|
+
completion(granted)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
case .denied, .restricted:
|
|
421
|
+
completion(false)
|
|
422
|
+
|
|
423
|
+
@unknown default:
|
|
424
|
+
completion(false)
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Show permission alert
|
|
429
|
+
func showPermissionAlert(message: String) {
|
|
430
|
+
let alert = UIAlertController(
|
|
431
|
+
title: "Permission Required", // Permission Required
|
|
432
|
+
message: message,
|
|
433
|
+
preferredStyle: .alert
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
alert.addAction(UIAlertAction(title: "Settings", style: .default) { _ in // Settings
|
|
437
|
+
if let url = URL(string: UIApplication.openSettingsURLString) {
|
|
438
|
+
UIApplication.shared.open(url)
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
|
|
442
|
+
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) // Cancel
|
|
443
|
+
present(alert, animated: true)
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Step 4: Make a Call
|
|
449
|
+
|
|
450
|
+
After calling [calls](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstore/calls(participantids:callmediatype:params:completion:)), navigate to the call screen. For the best user experience, automatically enable the microphone or camera based on the media type.
|
|
451
|
+
1. **Initiate the call:** Call `calls` to start a call.
|
|
452
|
+
|
|
453
|
+
2. **Enable media devices:** After the call is initiated, enable the microphone. If it’s a video call, also enable the camera.
|
|
454
|
+
|
|
455
|
+
3. **Present the call screen:** On successful call initiation, present the call screen.
|
|
456
|
+
|
|
457
|
+
``` swift
|
|
458
|
+
import UIKit
|
|
459
|
+
import AtomicXCore
|
|
460
|
+
import Combine
|
|
461
|
+
|
|
462
|
+
class MainViewController: UIViewController {
|
|
463
|
+
// 1. Initiate a call
|
|
464
|
+
private func startCall(userIdList: [String], mediaType: CallMediaType) {
|
|
465
|
+
var params = CallParams()
|
|
466
|
+
params.timeout = 30 // Set call timeout to 30 seconds
|
|
467
|
+
|
|
468
|
+
CallStore.shared.calls(
|
|
469
|
+
participantIds: userIdList,
|
|
470
|
+
callMediaType: mediaType, // Call type: .audio or .video
|
|
471
|
+
params: params
|
|
472
|
+
) { [weak self] result in
|
|
473
|
+
switch result {
|
|
474
|
+
case .success:
|
|
475
|
+
// 2. Enable media devices
|
|
476
|
+
self?.openDevices(for: mediaType)
|
|
477
|
+
// 3. Launch the call interface
|
|
478
|
+
DispatchQueue.main.async {
|
|
479
|
+
let callVC = CallViewController()
|
|
480
|
+
callVC.modalPresentationStyle = .fullScreen
|
|
481
|
+
self?.present(callVC, animated: true)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
case .failure(let error):
|
|
485
|
+
Log.error("Failed to initiate call: \(error)")
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private func openDevices(for mediaType: CallMediaType) {
|
|
491
|
+
DeviceStore.shared.openLocalMicrophone(completion: nil)
|
|
492
|
+
if mediaType == .video {
|
|
493
|
+
let isFront = DeviceStore.shared.state.value.isFrontCamera
|
|
494
|
+
DeviceStore.shared.openLocalCamera(isFront: isFront, completion: nil)
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**calls API Parameter Reference:**
|
|
501
|
+
|
|
502
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Required</strong> | <strong>Description</strong> |
|
|
503
|
+
| --- | --- | --- | --- |
|
|
504
|
+
| participantIds | List<String> | Yes | A list of target user IDs. |
|
|
505
|
+
| callMediaType | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callmediatype">CallMediaType</a> | Yes | The media type of the call, used to specify whether to initiate an audio or video call.<br>- <code>CallMediaType.video</code> : Video call.<br>- <code>CallMediaType.audio</code> : Audio call. |
|
|
506
|
+
| params | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callparams">CallParams</a> | No | Extended call parameters, such as Room ID, call invitation timeout, etc.<br>- <code>roomId</code> (String) : Room ID. An optional parameter; if not specified, it will be automatically assigned by the server.<br>- <code>timeout</code> (Int) : Call Timeout (in seconds).<br>- <code>userData</code> (String) : Custom User Data for application-specific information.<br>- <code>chatGroupId</code> (String) : Chat Group ID, used for group call scenarios.<br>- <code>isEphemeralCall</code> (Boolean) : Ephemeral Call. If set to true, no call history record will be generated. |
|
|
507
|
+
|
|
508
|
+
### Step 5: End the Call
|
|
509
|
+
|
|
510
|
+
When you call [hangup](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstore/hangup(completion:)) or the remote party ends the call, the [onCallEnded](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callevent/oncallended(callid:mediatype:reason:userid:)) event is triggered. Listen for this event and close the call screen when the call ends.
|
|
511
|
+
1. **Listen for call end event:** Observe the `onCallEnded` event.
|
|
512
|
+
|
|
513
|
+
2. **Close the call screen:** When `onCallEnded` is triggered, dismiss the call screen.
|
|
514
|
+
|
|
515
|
+
``` swift
|
|
516
|
+
import UIKit
|
|
517
|
+
import AtomicXCore
|
|
518
|
+
import Combine
|
|
519
|
+
|
|
520
|
+
class CallViewController: UIViewController {
|
|
521
|
+
override func viewDidLoad() {
|
|
522
|
+
super.viewDidLoad()
|
|
523
|
+
// Other initialization code
|
|
524
|
+
|
|
525
|
+
// 1. Add call event listener
|
|
526
|
+
addListener()
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
private func addListener() {
|
|
530
|
+
CallStore.shared.callEventPublisher
|
|
531
|
+
.receive(on: DispatchQueue.main)
|
|
532
|
+
.sink { [weak self] event in
|
|
533
|
+
if case .onCallEnded = event {
|
|
534
|
+
// 2. Dismiss the call interface
|
|
535
|
+
self?.dismiss(animated: true)
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
.store(in: &cancellables)
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**onCallEnded Event Parameters:**
|
|
544
|
+
|
|
545
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Description</strong> |
|
|
546
|
+
| --- | --- | --- |
|
|
547
|
+
| callId | String | Unique ID for this call. |
|
|
548
|
+
| mediaType | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callmediatype">CallMediaType</a> | The media type of the call:<br>- <code>CallMediaType.video</code> : Video call.<br>- <code>CallMediaType.audio</code> : Audio call. |
|
|
549
|
+
| reason | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callendreason">CallEndReason</a> | The reason why the call ended.<br>- <code>unknown</code> : Unable to determine the reason for termination.<br>- <code>hangup</code> : Normal termination; a user actively ended the call.<br>- <code>reject</code> : The callee declined the incoming call.<br>- <code>noResponse</code> : The callee did not answer within the timeout period.<br>- <code>offline</code> : The callee is currently offline.<br>- <code>lineBusy</code> : The callee is already in another call.<br>- <code>canceled</code> : The caller canceled the call before it was answered.<br>- <code>otherDeviceAccepted</code> : The call was answered on another logged-in device.<br>- <code>otherDeviceReject</code> : The call was declined on another logged-in device.<br>- <code>endByServer</code> : The call was forced to end by the server. |
|
|
550
|
+
| userId | String | The User ID of the person who triggered the call termination. |
|
|
551
|
+
|
|
552
|
+
### Demo
|
|
553
|
+
|
|
554
|
+
After completing these five steps, the "Make a Call" feature will look like this:
|
|
555
|
+
|
|
556
|
+
## Customization
|
|
557
|
+
|
|
558
|
+
**CallCoreView** provides extensive UI customization, including support for custom avatars and volume indicator icons. To speed up your integration, you can download ready-to-use icons from [GitHub](http://github.com/Tencent-RTC/TUIKit_iOS/tree/main/call/TUICallKit_Swift/Resources/Assets.xcassets). All icons are designed for TUICallKit and are free to use.
|
|
559
|
+
|
|
560
|
+
### Customizing Volume Indicator Icons
|
|
561
|
+
|
|
562
|
+
Use the **CallCoreView**[setVolumeLevelIcons](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview/setvolumelevelicons(icons:)) method to assign different icons for each volume level.
|
|
563
|
+
|
|
564
|
+
``` swift
|
|
565
|
+
// Set volume indicator icons
|
|
566
|
+
let volumeLevelIcons: [VolumeLevel: String] = [
|
|
567
|
+
.mute: "Path to the corresponding icon resource"
|
|
568
|
+
]
|
|
569
|
+
callCoreView.setVolumeLevelIcons(icons: volumeLevelIcons)
|
|
570
|
+
```
|
|
571
|
+
- **setVolumeLevelIcons API Parameters:**
|
|
572
|
+
|
|
573
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Required</strong> | <strong>Description</strong> |
|
|
574
|
+
| --- | --- | --- | --- |
|
|
575
|
+
| icons | [VolumeLevel: String] | Yes | A mapping table of volume levels to icon resources. The dictionary structure is defined as follows:<br>Key ( VolumeLevel ) Represents the volume intensity level:<br>- <code>VolumeLevel.mute</code> :Microphone is off or muted.<br>- <code>VolumeLevel.low</code> :Volume range (0, 25].<br>- <code>VolumeLevel.medium</code> : Volume range (25, 50].<br>- <code>VolumeLevel.high</code> : Volume range (50, 75].<br>- <code>VolumeLevel.peak</code> : Volume range (75, 100].<br>Value ( String ) The resource path or name of the icon corresponding to the volume level. |
|
|
576
|
+
|
|
577
|
+
- **Icon Configuration Guide:**
|
|
578
|
+
|
|
579
|
+
| <strong>Icons</strong> | <strong>Description</strong> |
|
|
580
|
+
| --- | --- |
|
|
581
|
+
| | Volume Indicator Icon.<br>You can set this icon for <code>VolumeLevel.low</code> or <code>VolumeLevel.medium</code>. It will be displayed when the user's volume exceeds the specified level. |
|
|
582
|
+
| | Volume Indicator Icon.<br>You can set this icon for VolumeLevel.mute. It will be displayed when the user is currently muted. |
|
|
583
|
+
|
|
584
|
+
### Customizing Network Indicator Icons
|
|
585
|
+
|
|
586
|
+
Use the **CallCoreView**[setNetworkQualityIcons](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview/setnetworkqualityicons(icons:)) method to assign icons for different network states.
|
|
587
|
+
|
|
588
|
+
``` swift
|
|
589
|
+
// Set network quality icons
|
|
590
|
+
let networkQualityIcons: [NetworkQuality: String] = [
|
|
591
|
+
.bad: "Path to the corresponding icon"
|
|
592
|
+
]
|
|
593
|
+
callCoreView.setNetworkQualityIcons(icons: networkQualityIcons)
|
|
594
|
+
```
|
|
595
|
+
- **setNetworkQualityIcons API Parameters:**
|
|
596
|
+
|
|
597
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Required</strong> | <strong>Description</strong> |
|
|
598
|
+
| --- | --- | --- | --- |
|
|
599
|
+
| icons | [NetworkQuality: String] | Yes | Network Quality Icon Mapping Table. The dictionary structure is defined as follows:<br>Key ( NetworkQuality ) : NetworkQuality<br><code>NetworkQuality.unknown</code> :Network status is undetermined.<br><code>NetworkQuality.excellent</code>:Outstanding network connection.<br><code>NetworkQuality.good</code> : Stable and good network connection.<br><code>NetworkQuality.poor</code> : Weak network signal.<br><code>NetworkQuality.bad</code> : Very weak or unstable network.<br><code>NetworkQuality.veryBad</code> :Extremely poor network, near disconnection.<br><code>NetworkQuality.down</code> :Network is disconnected.<br>Value ( String ) : The absolute path or resource name of the icon corresponding to the network status. |
|
|
600
|
+
|
|
601
|
+
- **Network Warning Icon: **
|
|
602
|
+
|
|
603
|
+
| <strong>Icons</strong> | <strong>Description</strong> |
|
|
604
|
+
| --- | --- |
|
|
605
|
+
| | Poor Network Indicator.<br>You can set this icon for <code>NetworkQuality.bad, NetworkQuality.veryBad</code> or <code>NetworkQuality.down</code> .It will be displayed when the network quality is poor. |
|
|
606
|
+
|
|
607
|
+
### Customizing Default Avatars
|
|
608
|
+
|
|
609
|
+
Use the **CallCoreView**[setParticipantAvatars](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview/setparticipantavatars(avatars:)) API to set user avatars. Listen to the [allParticipants](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstate/allparticipants) reactive data: when you have a user's avatar, set and display it; if not, show the default avatar.
|
|
610
|
+
``` swift
|
|
611
|
+
// Set user avatars
|
|
612
|
+
var avatars: [String: String] = [:]
|
|
613
|
+
let userId = "" // User ID
|
|
614
|
+
let avatarPath = "" // Path to user's default avatar resource
|
|
615
|
+
avatars[userId] = avatarPath
|
|
616
|
+
|
|
617
|
+
callCoreView.setParticipantAvatars(avatars: avatars)
|
|
618
|
+
```
|
|
619
|
+
- **setParticipantAvatars API Parameters:**
|
|
620
|
+
|
|
621
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Required</strong> | <strong>Description</strong> |
|
|
622
|
+
| --- | --- | --- | --- |
|
|
623
|
+
| avatars | [String: String] | Yes | User Avatar Mapping Table. The dictionary structure is described as follows:<br>- Key : The <code>userID</code> of the user.<br>- Value : The absolute path to the user's avatar resource. |
|
|
624
|
+
|
|
625
|
+
- **Default Avatar:**
|
|
626
|
+
|
|
627
|
+
| <strong>Icons</strong> | <strong>Description</strong> |
|
|
628
|
+
| --- | --- |
|
|
629
|
+
| | Default Profile Picture.<br>You can set this as the default avatar for a user when their profile image fails to load or if no avatar is provided. |
|
|
630
|
+
|
|
631
|
+
### Customizing Waiting Animations
|
|
632
|
+
|
|
633
|
+
Use the **CallCoreView**[setWaitingAnimation](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview/setwaitinganimation(path:)) API to set a waiting animation for users who are waiting to answer.
|
|
634
|
+
|
|
635
|
+
``` swift
|
|
636
|
+
// Set waiting animation
|
|
637
|
+
let waitingAnimationPath = "" // Path to waiting animation GIF resource
|
|
638
|
+
callCoreView.setWaitingAnimation(path: waitingAnimationPath)
|
|
639
|
+
```
|
|
640
|
+
- **setWaitingAnimation API Parameters:**
|
|
641
|
+
|
|
642
|
+
|**Params**|**Type**|**Required**|**Description**|
|
|
643
|
+
|---------|---------|---------|---------|
|
|
644
|
+
|path|String|Yes|Absolute path to a GIF format image resource.|
|
|
645
|
+
|
|
646
|
+
- **User Waiting Animation:**
|
|
647
|
+
|
|
648
|
+
| <strong>Icons</strong> | <strong>Description</strong> |
|
|
649
|
+
| --- | --- |
|
|
650
|
+
| | User Waiting Animation<br>Animations for group calls. Once configured, this animation will be displayed when the user's status is "Waiting to Answer" (Pending). |
|
|
651
|
+
|
|
652
|
+
### Adding a Call Duration Indicator
|
|
653
|
+
|
|
654
|
+
To display the call duration in real time, subscribe to the [activeCall](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstate/activecall)`duration` field.
|
|
655
|
+
1. **Subscribe to the data layer:** Observe `CallStore.observerState.activeCall` for changes.
|
|
656
|
+
|
|
657
|
+
2. **Bind the duration to your UI:** The `activeCall.duration` field is reactive and will automatically update your UI.
|
|
658
|
+
|
|
659
|
+
``` swift
|
|
660
|
+
import UIKit
|
|
661
|
+
import AtomicXCore
|
|
662
|
+
import Combine
|
|
663
|
+
|
|
664
|
+
class TimerView: UILabel {
|
|
665
|
+
private var cancellables = Set<AnyCancellable>()
|
|
666
|
+
|
|
667
|
+
override init(frame: CGRect) {
|
|
668
|
+
super.init(frame: frame)
|
|
669
|
+
setupView()
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
required init?(coder: NSCoder) {
|
|
673
|
+
super.init(coder: coder)
|
|
674
|
+
setupView()
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
private func setupView() {
|
|
678
|
+
textColor = .white
|
|
679
|
+
textAlignment = .center
|
|
680
|
+
font = .systemFont(ofSize: 16)
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
override func didMoveToWindow() {
|
|
684
|
+
super.didMoveToWindow()
|
|
685
|
+
if window != nil {
|
|
686
|
+
// [Recommended Usage] Animation for group calls.
|
|
687
|
+
// Once configured, this animation is displayed when the user's status is "Waiting to Answer".
|
|
688
|
+
registerActiveCallObserver()
|
|
689
|
+
} else {
|
|
690
|
+
cancellables.removeAll()
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
private func registerActiveCallObserver() {
|
|
695
|
+
CallStore.shared.state.subscribe()
|
|
696
|
+
.map { $0.activeCall }
|
|
697
|
+
.removeDuplicates { $0.duration == $1.duration }
|
|
698
|
+
.receive(on: DispatchQueue.main)
|
|
699
|
+
.sink { [weak self] activeCall in
|
|
700
|
+
// Update call duration
|
|
701
|
+
self?.updateDurationView(activeCall: activeCall)
|
|
702
|
+
}
|
|
703
|
+
.store(in: &cancellables)
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
private func updateDurationView(activeCall: CallInfo) {
|
|
707
|
+
let currentDuration = activeCall.duration
|
|
708
|
+
let minutes = currentDuration / 60
|
|
709
|
+
let seconds = currentDuration % 60
|
|
710
|
+
text = String(format: "%02d:%02d", minutes, seconds)
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
> **Note:**
|
|
716
|
+
>
|
|
717
|
+
|
|
718
|
+
> For more reactive call status data, see [CallState](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstate).
|
|
719
|
+
>
|
|
720
|
+
|
|
721
|
+
## More Features
|
|
722
|
+
|
|
723
|
+
### Customizing User Avatar and Nickname
|
|
724
|
+
|
|
725
|
+
Before a call starts, set your own nickname and avatar using [setSelfInfo](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/loginstore/setselfinfo(userprofile:completion:)).
|
|
726
|
+
``` swift
|
|
727
|
+
var userProfile = UserProfile()
|
|
728
|
+
userProfile.userID = "" // Your User ID
|
|
729
|
+
userProfile.avatarURL = "" // URL of the avatar image
|
|
730
|
+
userProfile.nickname = "" // The nickname to be set
|
|
731
|
+
|
|
732
|
+
LoginStore.shared.setSelfInfo(userProfile: userProfile) { result in
|
|
733
|
+
switch result {
|
|
734
|
+
case .success:
|
|
735
|
+
// Success callback: profile updated successfully
|
|
736
|
+
case .failure(let error):
|
|
737
|
+
// Failure callback: handle the error
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
```
|
|
741
|
+
- **setSelfInfo API Parameters:**
|
|
742
|
+
|
|
743
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Required</strong> | <strong>Description</strong> |
|
|
744
|
+
| --- | --- | --- | --- |
|
|
745
|
+
| userProfile | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/userprofile">UserProfile</a> | Yes | User info struct:<br>- <code>userID</code>: User ID<br>- <code>avatarURL</code>: User avatar URL<br>- <code>nickname</code>: User nickname<br>For more field details, please refer to the <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/userprofile">UserProfile</a> class. |
|
|
746
|
+
|
|
747
|
+
### Switching Layout Modes
|
|
748
|
+
|
|
749
|
+
**CallCoreView** supports three built-in layout modes. Use [setLayoutTemplate](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callcoreview/setlayouttemplate(_:)) to set the layout. If not set, **CallCoreView** will automatically use `Float` mode for 1-on-1 calls and `Grid` mode for multi-party calls.
|
|
750
|
+
| <strong>Float Mode</strong> | <strong>Grid Mode</strong> | <strong>PIP Mode</strong> |
|
|
751
|
+
| --- | --- | --- |
|
|
752
|
+
| | | |
|
|
753
|
+
| - <strong>Layout:</strong> While waiting, display your own video full screen. After answering, show the remote video full screen and your own video as a floating window.<br>- <strong>Interaction:</strong> Drag the small window or tap to swap big/small video. | - <strong>Layout:</strong> All participant videos are tiled in a grid. Best for 2+ participants. Tap to enlarge a video.<br>- <strong>Interaction:</strong> Tap a participant to enlarge their video. | - <strong>Layout:</strong> In 1v1, remote video is fixed; in multi-party, the active speaker is shown full screen.<br>- <strong>Interaction:</strong> Shows your own video while waiting, displays call timer after answering. |
|
|
754
|
+
|
|
755
|
+
- **setLayoutTemplate Sample code:**
|
|
756
|
+
|
|
757
|
+
``` swift
|
|
758
|
+
func setLayoutTemplate(_ template: CallLayoutTemplate)
|
|
759
|
+
```
|
|
760
|
+
- **setLayoutTemplate API Parameters:**
|
|
761
|
+
|
|
762
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Description</strong> |
|
|
763
|
+
| --- | --- | --- |
|
|
764
|
+
| template | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/calllayouttemplate">CallLayoutTemplate</a> | CallCoreView's layout mode<br>- <code>CallLayoutTemplate.float</code> :<br>- <strong>Layout:</strong> While waiting, display your own video full screen. After answering, show the remote video full screen and your own video as a floating window.<br>- <strong>Interaction:</strong> Drag the small window or tap to swap big/small video.<br>- <code>CallLayoutTemplate.grid</code> :<br>- <strong>Layout:</strong> All participant videos are tiled in a grid. Best for 2+ participants. Tap to enlarge a video.<br>- <strong>Interaction:</strong> Tap a participant to enlarge their video.<br>- <code>CallLayoutTemplate.pip</code> :<br>- <strong>Layout:</strong> In 1v1, remote video is fixed; in multi-party, the active speaker is shown full screen.<br>- <strong>Interaction:</strong> Shows your own video while waiting, displays call timer after answering. |
|
|
765
|
+
|
|
766
|
+
### Setting Default Call Timeout
|
|
767
|
+
|
|
768
|
+
When making a call using [calls](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callstore/calls(participantids:callmediatype:params:completion:)), set the `timeout` field in [CallParams](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callparams) to specify the call invitation timeout.
|
|
769
|
+
``` swift
|
|
770
|
+
var callParams = CallParams()
|
|
771
|
+
callParams.timeout = 30 // Set call timeout to 30 seconds.
|
|
772
|
+
CallStore.shared.calls(
|
|
773
|
+
participantIds: userIdList,
|
|
774
|
+
callMediaType: .video,
|
|
775
|
+
params: callParams,
|
|
776
|
+
completion: nil
|
|
777
|
+
)
|
|
778
|
+
```
|
|
779
|
+
| <strong>Params</strong> | <strong>Type</strong> | <strong>Required</strong> | <strong>Description</strong> |
|
|
780
|
+
| --- | --- | --- | --- |
|
|
781
|
+
| participantIds | List<String> | Yes | A list of User IDs for the target participants. |
|
|
782
|
+
| callMediaType | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callmediatype">CallMediaType</a> | Yes | The media type of the call, used to specify whether to initiate an audio or video call.<br>- <code>CallMediaType.video</code> : Video Call.<br>- <code>CallMediaType.audio</code> : Audio Call. |
|
|
783
|
+
| params | <a href="https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/callparams">CallParams</a> | No | Extended call parameters, such as Room ID, call invitation timeout, etc.<br>- <code>roomId</code> (String) : Room ID. An optional parameter; if not specified, it will be automatically assigned by the server.<br>- <code>timeout</code> (Int) : Call Timeout (in seconds).<br>- <code>userData</code> (String) : User Custom Data for app-specific logic.<br>- <code>chatGroupId</code> (String) : Chat Group ID, used specifically for group call scenarios.<br>- <code>isEphemeralCall</code> (Boolean) : Ephemeral Call. Whether the call is encrypted and transient (will not generate a call history record). |
|
|
784
|
+
|
|
785
|
+
### Implementing In-App Floating Window
|
|
786
|
+
|
|
787
|
+
The AtomicXCore SDK provides the `CallPipView` component to enable in-app floating windows. When the call interface is covered by another screen (e.g., the user navigates away but the call is ongoing), a floating window displays call status and lets users quickly return to the call.
|
|
788
|
+
|
|
789
|
+
**Step 1: Create the Floating Window Controller.**
|
|
790
|
+
``` swift
|
|
791
|
+
import UIKit
|
|
792
|
+
import AtomicXCore
|
|
793
|
+
import Combine
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Floating Window Controller
|
|
797
|
+
* * Used to display the call in a floating window, containing a CallCoreView internally.
|
|
798
|
+
*/
|
|
799
|
+
class FloatWindowViewController: UIViewController {
|
|
800
|
+
|
|
801
|
+
var tapGestureAction: (() -> Void)?
|
|
802
|
+
private var cancellables = Set<AnyCancellable>()
|
|
803
|
+
|
|
804
|
+
private lazy var callCoreView: CallCoreView = {
|
|
805
|
+
let view = CallCoreView(frame: self.view.bounds)
|
|
806
|
+
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
807
|
+
view.setLayoutTemplate(.pip) // Set to Picture-in-Picture (PIP) layout mode
|
|
808
|
+
view.isUserInteractionEnabled = false // Disable interaction to allow taps to pass through to the parent view
|
|
809
|
+
return view
|
|
810
|
+
}()
|
|
811
|
+
|
|
812
|
+
override func viewDidLoad() {
|
|
813
|
+
super.viewDidLoad()
|
|
814
|
+
view.backgroundColor = UIColor(white: 0.1, alpha: 1.0)
|
|
815
|
+
view.layer.cornerRadius = 10
|
|
816
|
+
view.layer.masksToBounds = true
|
|
817
|
+
|
|
818
|
+
view.addSubview(callCoreView)
|
|
819
|
+
|
|
820
|
+
// Add tap gesture recognizer
|
|
821
|
+
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
|
|
822
|
+
view.addGestureRecognizer(tapGesture)
|
|
823
|
+
|
|
824
|
+
// Delay status observation to prevent the window from closing immediately upon creation
|
|
825
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
|
|
826
|
+
self?.observeCallStatus()
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
@objc private func handleTap() {
|
|
831
|
+
tapGestureAction?()
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Observe call status changes
|
|
836
|
+
* Automatically closes the floating window when the call ends.
|
|
837
|
+
*/
|
|
838
|
+
private func observeCallStatus() {
|
|
839
|
+
CallStore.shared.state
|
|
840
|
+
.subscribe(StatePublisherSelector<CallState, CallParticipantStatus>(keyPath: \.selfInfo.status))
|
|
841
|
+
.removeDuplicates()
|
|
842
|
+
.receive(on: DispatchQueue.main)
|
|
843
|
+
.sink { [weak self] status in
|
|
844
|
+
if status == .none {
|
|
845
|
+
// Call ended, post notification to hide the floating window
|
|
846
|
+
NotificationCenter.default.post(name: NSNotification.Name("HideFloatingWindow"), object: nil)
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
.store(in: &cancellables)
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
deinit {
|
|
853
|
+
cancellables.removeAll()
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
**Step 2: Implement floating window management logic in the main interface.**
|
|
859
|
+
``` swift
|
|
860
|
+
import UIKit
|
|
861
|
+
import AtomicXCore
|
|
862
|
+
|
|
863
|
+
class MainViewController: UIViewController {
|
|
864
|
+
|
|
865
|
+
private var floatWindow: UIWindow?
|
|
866
|
+
|
|
867
|
+
override func viewDidLoad() {
|
|
868
|
+
super.viewDidLoad()
|
|
869
|
+
|
|
870
|
+
// Listen for the notification to show the floating window
|
|
871
|
+
NotificationCenter.default.addObserver(
|
|
872
|
+
self,
|
|
873
|
+
selector: #selector(showFloatingWindow),
|
|
874
|
+
name: NSNotification.Name("ShowFloatingWindow"),
|
|
875
|
+
object: nil
|
|
876
|
+
)
|
|
877
|
+
|
|
878
|
+
// Listen for the notification to hide the floating window
|
|
879
|
+
NotificationCenter.default.addObserver(
|
|
880
|
+
self,
|
|
881
|
+
selector: #selector(hideFloatingWindow),
|
|
882
|
+
name: NSNotification.Name("HideFloatingWindow"),
|
|
883
|
+
object: nil
|
|
884
|
+
)
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Displays the in-app floating window.
|
|
889
|
+
*/
|
|
890
|
+
@objc private func showFloatingWindow() {
|
|
891
|
+
// Check if the call is currently active/accepted
|
|
892
|
+
let selfStatus = CallStore.shared.state.value.selfInfo.status
|
|
893
|
+
guard selfStatus == .accept else {
|
|
894
|
+
return
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// Prevent duplicate creation if the floating window already exists
|
|
898
|
+
guard floatWindow == nil else { return }
|
|
899
|
+
|
|
900
|
+
// ⚠️ CRITICAL: The current windowScene must be used to create the new window
|
|
901
|
+
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
|
|
902
|
+
return
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// Define floating window dimensions (9:16 aspect ratio)
|
|
906
|
+
let pipWidth: CGFloat = 100
|
|
907
|
+
let pipHeight: CGFloat = pipWidth * 16 / 9
|
|
908
|
+
let pipX = UIScreen.main.bounds.width - pipWidth - 20
|
|
909
|
+
let pipY: CGFloat = 100
|
|
910
|
+
|
|
911
|
+
// Create the floating window (associated with the windowScene)
|
|
912
|
+
let window = UIWindow(windowScene: windowScene)
|
|
913
|
+
window.windowLevel = .alert + 1 // Ensure it stays above standard UI
|
|
914
|
+
window.backgroundColor = .clear
|
|
915
|
+
window.frame = CGRect(x: pipX, y: pipY, width: pipWidth, height: pipHeight)
|
|
916
|
+
|
|
917
|
+
// Initialize the floating window controller
|
|
918
|
+
let floatVC = FloatWindowViewController()
|
|
919
|
+
floatVC.tapGestureAction = { [weak self] in
|
|
920
|
+
self?.openCallViewController()
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
window.rootViewController = floatVC
|
|
924
|
+
|
|
925
|
+
self.floatWindow = window
|
|
926
|
+
|
|
927
|
+
// Make the window visible
|
|
928
|
+
window.isHidden = false
|
|
929
|
+
window.makeKeyAndVisible()
|
|
930
|
+
|
|
931
|
+
// Immediately restore the main window as the key window to maintain proper app focus
|
|
932
|
+
if let mainWindow = windowScene.windows.first(where: { $0 != window }) {
|
|
933
|
+
mainWindow.makeKey()
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
/**
|
|
938
|
+
* Hides the in-app floating window.
|
|
939
|
+
*/
|
|
940
|
+
@objc private func hideFloatingWindow() {
|
|
941
|
+
floatWindow?.isHidden = true
|
|
942
|
+
floatWindow = nil
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Opens the call interface (triggered upon tapping the floating window).
|
|
947
|
+
*/
|
|
948
|
+
private func openCallViewController() {
|
|
949
|
+
// Dismiss the floating window first
|
|
950
|
+
hideFloatingWindow()
|
|
951
|
+
|
|
952
|
+
// Retrieve the current top-most ViewController
|
|
953
|
+
guard let topVC = getTopViewController() else {
|
|
954
|
+
return
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
let callVC = CallViewController()
|
|
958
|
+
callVC.modalPresentationStyle = .fullScreen
|
|
959
|
+
topVC.present(callVC, animated: true)
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/**
|
|
963
|
+
* Utility to retrieve the current top-most ViewController in the view hierarchy.
|
|
964
|
+
*/
|
|
965
|
+
private func getTopViewController() -> UIViewController? {
|
|
966
|
+
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
967
|
+
let keyWindow = windowScene.windows.first(where: { $0.isKeyWindow }),
|
|
968
|
+
let rootVC = keyWindow.rootViewController else {
|
|
969
|
+
return nil
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
var topVC = rootVC
|
|
973
|
+
while let presentedVC = topVC.presentedViewController {
|
|
974
|
+
topVC = presentedVC
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
return topVC
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
deinit {
|
|
981
|
+
NotificationCenter.default.removeObserver(self)
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
**Step 3: Add the floating window trigger logic to the Call Interface.**
|
|
987
|
+
``` swift
|
|
988
|
+
import UIKit
|
|
989
|
+
import AtomicXCore
|
|
990
|
+
|
|
991
|
+
class CallViewController: UIViewController {
|
|
992
|
+
|
|
993
|
+
override func viewWillAppear(_ animated: Bool) {
|
|
994
|
+
super.viewWillAppear(animated)
|
|
995
|
+
|
|
996
|
+
// When entering the call interface, post a notification to hide the floating window
|
|
997
|
+
NotificationCenter.default.post(name: NSNotification.Name("HideFloatingWindow"), object: nil)
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
override func viewWillDisappear(_ animated: Bool) {
|
|
1001
|
+
super.viewWillDisappear(animated)
|
|
1002
|
+
|
|
1003
|
+
// When leaving the call interface, check if the call is still active
|
|
1004
|
+
let selfStatus = CallStore.shared.state.value.selfInfo.status
|
|
1005
|
+
if selfStatus == .accept {
|
|
1006
|
+
// If the call is still ongoing, post a notification to show the floating window
|
|
1007
|
+
NotificationCenter.default.post(name: NSNotification.Name("ShowFloatingWindow"), object: nil)
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
```
|
|
1012
|
+
|
|
1013
|
+
### Enabling System Picture-in-Picture (PiP) Outside the App
|
|
1014
|
+
|
|
1015
|
+
AtomicXCore SDK supports system-level PiP via the underlying TRTC engine. When your app goes to the background, the call video can float above other apps as a system PiP window, so users can continue their video call while multitasking.
|
|
1016
|
+
|
|
1017
|
+
> **Note:**
|
|
1018
|
+
>
|
|
1019
|
+
> 1. In Xcode, add `Background Modes` under `Signing & Capabilities` and enable `Audio, AirPlay, and Picture in Picture`.
|
|
1020
|
+
> 2. Requires iOS 15.0 or later.
|
|
1021
|
+
|
|
1022
|
+
1. **Configure PiP Parameters:** You need to set parameters such as the fill mode for the PiP window, user video regions, and canvas configurations.
|
|
1023
|
+
|
|
1024
|
+
``` swift
|
|
1025
|
+
import Foundation
|
|
1026
|
+
import AtomicXCore
|
|
1027
|
+
|
|
1028
|
+
// Fill Mode Enumeration
|
|
1029
|
+
enum PictureInPictureFillMode: Int, Codable {
|
|
1030
|
+
case fill = 0 // Aspect Fill (Scale to fill, may crop)
|
|
1031
|
+
case fit = 1 // Aspect Fit (Scale to fit, no cropping)
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// User Video Region
|
|
1035
|
+
struct PictureInPictureRegion: Codable {
|
|
1036
|
+
let userId: String // Unique User ID
|
|
1037
|
+
let width: Double // Width (0.0 - 1.0, relative to canvas)
|
|
1038
|
+
let height: Double // Height (0.0 - 1.0, relative to canvas)
|
|
1039
|
+
let x: Double // X coordinate (0.0 - 1.0, relative to top-left of canvas)
|
|
1040
|
+
let y: Double // Y coordinate (0.0 - 1.0, relative to top-left of canvas)
|
|
1041
|
+
let fillMode: PictureInPictureFillMode // Rendering fill mode
|
|
1042
|
+
let streamType: String // Stream type ("high" for HD or "low" for SD)
|
|
1043
|
+
let backgroundColor: String // Hex background color (e.g., "#000000")
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// Canvas Configuration
|
|
1047
|
+
struct PictureInPictureCanvas: Codable {
|
|
1048
|
+
let width: Int // Canvas width in pixels
|
|
1049
|
+
let height: Int // Canvas height in pixels
|
|
1050
|
+
let backgroundColor: String // Hex background color
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Picture-in-Picture Parameters
|
|
1054
|
+
struct PictureInPictureParams: Codable {
|
|
1055
|
+
let enable: Bool // Toggle PiP functionality
|
|
1056
|
+
let cameraBackgroundCapture: Bool? // Whether to continue camera capture in background
|
|
1057
|
+
let canvas: PictureInPictureCanvas? // Canvas settings (Optional)
|
|
1058
|
+
let regions: [PictureInPictureRegion]? // List of user video regions (Optional)
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
// PiP API Request Object
|
|
1062
|
+
struct PictureInPictureRequest: Codable {
|
|
1063
|
+
let api: String // API identifier name
|
|
1064
|
+
let params: PictureInPictureParams // Parameter payload
|
|
1065
|
+
}
|
|
1066
|
+
```
|
|
1067
|
+
2. **Enable Picture-in-Picture: **You can enable or disable the PiP feature using the`configPictureInPicture` method.
|
|
1068
|
+
|
|
1069
|
+
``` swift
|
|
1070
|
+
let params = PictureInPictureParams(
|
|
1071
|
+
enable: true,
|
|
1072
|
+
cameraBackgroundCapture: true,
|
|
1073
|
+
canvas: nil,
|
|
1074
|
+
regions: nil
|
|
1075
|
+
)
|
|
1076
|
+
|
|
1077
|
+
let request = PictureInPictureRequest(
|
|
1078
|
+
api: "configPictureInPicture",
|
|
1079
|
+
params: params
|
|
1080
|
+
)
|
|
1081
|
+
|
|
1082
|
+
// Encode to JSON string and call the Experimental API
|
|
1083
|
+
let encoder = JSONEncoder()
|
|
1084
|
+
if let data = try? encoder.encode(request),
|
|
1085
|
+
let jsonString = String(data: data, encoding: .utf8) {
|
|
1086
|
+
TUICallEngine.createInstance().callExperimentalAPI(jsonObject: jsonString)
|
|
1087
|
+
}
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
### Keeping the Screen Awake During Calls
|
|
1091
|
+
|
|
1092
|
+
To prevent the screen from dimming or locking during a call, set `UIApplication.shared.isIdleTimerDisabled = true` when the call starts, and restore it when the call ends.
|
|
1093
|
+
``` swift
|
|
1094
|
+
class CallViewController: UIViewController {
|
|
1095
|
+
|
|
1096
|
+
override func viewDidLoad() {
|
|
1097
|
+
super.viewDidLoad()
|
|
1098
|
+
|
|
1099
|
+
// Disable automatic screen lock to keep the screen on
|
|
1100
|
+
UIApplication.shared.isIdleTimerDisabled = true
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
override func viewWillDisappear(_ animated: Bool) {
|
|
1104
|
+
super.viewWillDisappear(animated)
|
|
1105
|
+
|
|
1106
|
+
// Restore the automatic screen lock behavior
|
|
1107
|
+
UIApplication.shared.isIdleTimerDisabled = false
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
### Playing a Ringtone While Waiting for Answer
|
|
1113
|
+
|
|
1114
|
+
Listen to your own call status to play a ringtone while waiting for an answer, and stop the ringtone when the call is answered or ends.
|
|
1115
|
+
``` swift
|
|
1116
|
+
import Combine
|
|
1117
|
+
|
|
1118
|
+
private var cancellables = Set<AnyCancellable>()
|
|
1119
|
+
|
|
1120
|
+
private func observeSelfCallStatus() {
|
|
1121
|
+
CallStore.shared.state.subscribe()
|
|
1122
|
+
.map { $0.selfInfo.status }
|
|
1123
|
+
.removeDuplicates()
|
|
1124
|
+
.receive(on: DispatchQueue.main)
|
|
1125
|
+
.sink { [weak self] status in
|
|
1126
|
+
if status == .accept || status == .none {
|
|
1127
|
+
// Stop playing ringtone
|
|
1128
|
+
return
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
if status == .waiting {
|
|
1132
|
+
// Start playing ringtone
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
.store(in: &cancellables)
|
|
1136
|
+
}
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
### Enabling Background Audio/Video Capture
|
|
1140
|
+
|
|
1141
|
+
To allow your app to capture audio and video while in the background (e.g., when the user locks the screen or switches apps), configure iOS background mode permissions and set up the audio session.
|
|
1142
|
+
|
|
1143
|
+
**Configuration Steps:**
|
|
1144
|
+
1. In Xcode, select your project `Target` → `Signing & Capabilities`.
|
|
1145
|
+
|
|
1146
|
+
2. Click `+ Capability`.
|
|
1147
|
+
|
|
1148
|
+
3. Add `Background Modes`.
|
|
1149
|
+
|
|
1150
|
+
4. Enable:
|
|
1151
|
+
|
|
1152
|
+
- `Audio, AirPlay, and Picture in Picture` (for audio capture and PiP)
|
|
1153
|
+
|
|
1154
|
+
- `Voice over IP` (for VoIP calls)
|
|
1155
|
+
|
|
1156
|
+
- `Remote notifications` (optional, for offline push)
|
|
1157
|
+
|
|
1158
|
+
Your `Info.plist` will then include:
|
|
1159
|
+
|
|
1160
|
+
``` xml
|
|
1161
|
+
<key>UIBackgroundModes</key>
|
|
1162
|
+
<array>
|
|
1163
|
+
<string>audio</string>
|
|
1164
|
+
<string>voip</string>
|
|
1165
|
+
<string>remote-notification</string>
|
|
1166
|
+
</array>
|
|
1167
|
+
```
|
|
1168
|
+
- **Configure Audio Session (AVAudioSession):**
|
|
1169
|
+
|
|
1170
|
+
Set up the audio session before the call starts, ideally in the call interface’s `viewDidLoad` or before making/answering a call.
|
|
1171
|
+
|
|
1172
|
+
``` swift
|
|
1173
|
+
import AVFoundation
|
|
1174
|
+
|
|
1175
|
+
/**
|
|
1176
|
+
* Configure the Audio Session to support background audio capture.
|
|
1177
|
+
* * Recommended to call this method in the following scenarios:
|
|
1178
|
+
* 1. Inside viewDidLoad of the call interface.
|
|
1179
|
+
* 2. Before initiating a call (calls).
|
|
1180
|
+
* 3. Before answering a call (accept).
|
|
1181
|
+
*/
|
|
1182
|
+
private func setupAudioSession() {
|
|
1183
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
1184
|
+
do {
|
|
1185
|
+
// Set the audio session category to PlayAndRecord.
|
|
1186
|
+
// .allowBluetooth: Support for standard Bluetooth headsets.
|
|
1187
|
+
// .allowBluetoothA2DP: Support for high-quality Bluetooth audio (A2DP protocol).
|
|
1188
|
+
try audioSession.setCategory(.playAndRecord, options: [.allowBluetooth, .allowBluetoothA2DP])
|
|
1189
|
+
|
|
1190
|
+
// Activate the audio session.
|
|
1191
|
+
try audioSession.setActive(true)
|
|
1192
|
+
} catch {
|
|
1193
|
+
// Audio session configuration failed.
|
|
1194
|
+
print("Failed to configure Audio Session: \(error)")
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
```
|
|
1198
|
+
- **Special Handling for Ringtone Playback (Optional):**
|
|
1199
|
+
|
|
1200
|
+
To play a ringtone through the speaker while waiting for an answer, temporarily switch the audio session to `.playback` mode.
|
|
1201
|
+
|
|
1202
|
+
``` swift
|
|
1203
|
+
/**
|
|
1204
|
+
* Switch the Audio Session for ringtone playback.
|
|
1205
|
+
* * Use Case: When using AVAudioPlayer to play the ringtone.
|
|
1206
|
+
*/
|
|
1207
|
+
private func setAudioSessionForRingtone() {
|
|
1208
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
1209
|
+
do {
|
|
1210
|
+
// Switch to playback mode (optimizes for output only)
|
|
1211
|
+
try audioSession.setCategory(.playback, options: [.allowBluetooth, .allowBluetoothA2DP])
|
|
1212
|
+
|
|
1213
|
+
// Force the ringtone to play through the built-in speaker
|
|
1214
|
+
try audioSession.overrideOutputAudioPort(.speaker)
|
|
1215
|
+
|
|
1216
|
+
try audioSession.setActive(true)
|
|
1217
|
+
} catch {
|
|
1218
|
+
// Failed to configure Audio Session for ringtone
|
|
1219
|
+
print("Ringtone audio session error: \(error)")
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
/**
|
|
1224
|
+
* Restore to Call Mode after the ringtone stops playing.
|
|
1225
|
+
*/
|
|
1226
|
+
private func restoreAudioSessionForCall() {
|
|
1227
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
1228
|
+
do {
|
|
1229
|
+
// Restore to PlayAndRecord mode (required for two-way VoIP communication)
|
|
1230
|
+
try audioSession.setCategory(.playAndRecord, options: [.allowBluetooth, .allowBluetoothA2DP])
|
|
1231
|
+
|
|
1232
|
+
try audioSession.setActive(true)
|
|
1233
|
+
} catch {
|
|
1234
|
+
// Failed to restore Audio Session
|
|
1235
|
+
print("Failed to restore call audio session: \(error)")
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
```
|
|
1239
|
+
|
|
1240
|
+
## Next Steps
|
|
1241
|
+
|
|
1242
|
+
Congratulations! You’ve completed the "Make a Call" feature. Next, see Answer Your First Call to implement the answer call functionality.
|
|
1243
|
+
|
|
1244
|
+
## FAQs
|
|
1245
|
+
|
|
1246
|
+
### If the callee is offline and comes online within the call invitation timeout, will they receive the incoming call event?
|
|
1247
|
+
|
|
1248
|
+
For one-on-one calls, if the callee comes online within the timeout, they will receive an incoming call invitation. For group calls, if the callee comes online within the timeout, up to 20 pending group messages will be retrieved. If there is a call invitation, the incoming call event will be triggered.
|
|
1249
|
+
|
|
1250
|
+
## Contact Us
|
|
1251
|
+
|
|
1252
|
+
If you have any questions or suggestions during the integration or usage process, feel free to join our [Telegram technical group](https://t.me/+EPk6TMZEZMM5OGY1) or [contact us](https://trtc.io/contact) for support.
|