@tencent-rtc/mcp 1.3.3 → 1.3.5

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.
Files changed (105) hide show
  1. package/package.json +1 -1
  2. package/resource/doc/chatuikit/android/features/theme.md +363 -0
  3. package/resource/doc/chatuikit/{android/client_api_Android.md → faq/android_sdk/client-api.md} +0 -2
  4. package/resource/doc/chatuikit/faq/common/product.md +8 -0
  5. package/resource/doc/chatuikit/faq/flutter_sdk/faq.md +53 -0
  6. package/resource/doc/chatuikit/{iOS/client_api_iOS.md → faq/ios_sdk/client-api.md} +0 -2
  7. package/resource/doc/chatuikit/flutter/features/theme.md +379 -0
  8. package/resource/doc/chatuikit/flutter/integration.md +413 -0
  9. package/resource/doc/chatuikit/flutter/workflow.md +941 -0
  10. package/resource/doc/chatuikit/iOS/features/theme.md +416 -0
  11. package/resource/doc/chatuikit/iOS/workflow.md +0 -0
  12. package/resource/doc/chatuikit/react/components/chat-setting.md +86 -0
  13. package/resource/doc/chatuikit/react/components/contact-list.md +1093 -0
  14. package/resource/doc/chatuikit/react/components/search.md +745 -0
  15. package/resource/doc/chatuikit/vue/components/chat-setting.md +64 -0
  16. package/resource/doc/chatuikit/vue/components/contact-list.md +679 -0
  17. package/resource/doc/chatuikit/vue/components/search.md +1384 -0
  18. package/resource/doc/livekit/live/android/workflow.md +137 -6
  19. package/resource/doc/livekit/live/ios/live-audience-list.md +339 -0
  20. package/resource/doc/livekit/live/ios/live-audio-effect.md +370 -0
  21. package/resource/doc/livekit/live/ios/live-barrage.md +517 -0
  22. package/resource/doc/livekit/live/ios/live-base-beauty.md +247 -0
  23. package/resource/doc/livekit/live/ios/live-co-guest-interaction.md +518 -0
  24. package/resource/doc/livekit/live/ios/live-gift.md +783 -0
  25. package/resource/doc/livekit/live/ios/live-host-interaction.md +815 -0
  26. package/resource/doc/livekit/live/ios/live-integration.md +931 -0
  27. package/resource/doc/livekit/live/ios/live-live-list.md +485 -0
  28. package/resource/doc/livekit/live/ios/workflow.md +454 -0
  29. package/resource/doc/rtcengine/web/plugin/20-advanced-customized-capture-rendering.md +87 -0
  30. package/resource/doc/rtcengine/web/plugin/21-advanced-auto-play-policy.md +87 -0
  31. package/resource/doc/rtcengine/web/plugin/22-advanced-audio-mixer.md +175 -0
  32. package/resource/doc/rtcengine/web/plugin/23-advanced-support-detection.md +221 -0
  33. package/resource/doc/rtcengine/web/plugin/24-advanced-network-quality.md +140 -0
  34. package/resource/doc/rtcengine/web/plugin/25-advanced-device-change.md +99 -0
  35. package/resource/doc/rtcengine/web/plugin/26-advanced-publish-cdn-stream.md +451 -0
  36. package/resource/doc/rtcengine/web/plugin/27-advanced-small-stream.md +151 -0
  37. package/resource/doc/rtcengine/web/plugin/28-advanced-beauty.md +322 -0
  38. package/resource/doc/rtcengine/web/plugin/29-advanced-water-mark.md +149 -0
  39. package/resource/doc/rtcengine/web/plugin/30-advanced-cross-room-link.md +96 -0
  40. package/resource/doc/rtcengine/web/plugin/31-advanced-plugins-overview.md +330 -0
  41. package/resource/doc/rtcengine/web/plugin/34-advanced-proxy.md +248 -0
  42. package/resource/doc/rtcengine/web/plugin/35-advanced-ai-denoiser.md +81 -0
  43. package/resource/doc/rtcengine/web/plugin/36-advanced-virtual-background.md +242 -0
  44. package/resource/doc/rtcengine/web/plugin/37-advanced-voice-changer.md +99 -0
  45. package/resource/doc/rtcengine/web/plugin/39-advanced-video-decoder.md +33 -0
  46. package/resource/doc/rtcengine/web/plugin/40-advanced-video-mixer.md +379 -0
  47. package/resource/doc/rtcengine/web/plugin/41-advanced-small-stream-auto-switcher.md +91 -0
  48. package/resource/doc/rtcengine/web/plugin/42-advanced-realtime-transcriber.md +315 -0
  49. package/resource/doc/rtcengine/web/plugin/43-advanced-face-detection.md +180 -0
  50. package/tools/chat/get-native-chat-feature-detail.js +30 -0
  51. package/tools/chat/get-native-chat-feature-detail.js.map +1 -0
  52. package/tools/chat/get-native-chat-integration.js +30 -12
  53. package/tools/chat/get-native-chat-integration.js.map +1 -1
  54. package/tools/common/get-faq.js +2 -4
  55. package/tools/common/get-faq.js.map +1 -1
  56. package/tools/definitions/get_native_chat_feature_detail_def.js +32 -0
  57. package/tools/definitions/get_native_chat_feature_detail_def.js.map +1 -0
  58. package/tools/definitions/get_native_chat_uikit_integration_def.js +19 -7
  59. package/tools/definitions/get_native_chat_uikit_integration_def.js.map +1 -1
  60. package/tools/definitions/{get_native_live_extra_features_def.js → get_native_live_uikit_extra_features_def.js} +3 -3
  61. package/tools/definitions/get_native_live_uikit_extra_features_def.js.map +1 -0
  62. package/tools/definitions/{get_native_live_interaction_def.js → get_native_live_uikit_interaction_def.js} +3 -3
  63. package/tools/definitions/get_native_live_uikit_interaction_def.js.map +1 -0
  64. package/tools/definitions/get_web_chat_uikit_component_detail_def.js +49 -10
  65. package/tools/definitions/get_web_chat_uikit_component_detail_def.js.map +1 -1
  66. package/tools/definitions/record_prompt_def.js +42 -11
  67. package/tools/definitions/record_prompt_def.js.map +1 -1
  68. package/tools/definitions/record_result_def.js +1 -1
  69. package/tools/index.js +6 -4
  70. package/tools/index.js.map +1 -1
  71. package/tools/live/{get_native_live_extra_features.js → get_native_live_uikit_extra_features.js} +4 -4
  72. package/tools/live/get_native_live_uikit_extra_features.js.map +1 -0
  73. package/tools/live/{get_native_live_interaction.js → get_native_live_uikit_interaction.js} +4 -4
  74. package/tools/live/get_native_live_uikit_interaction.js.map +1 -0
  75. package/tools/rtcengine/get-rtcengine-web-sdk-integration.js.map +1 -1
  76. package/tools/rtcengine/get-trtc-sdk-faq.js +32 -0
  77. package/tools/rtcengine/get-trtc-sdk-faq.js.map +1 -0
  78. package/tools/rtcengine/get-trtc-web-sdk-faq.js +1 -1
  79. package/tools/rtcengine/get-trtc-web-sdk-integration.js.map +1 -1
  80. package/tools/rtcengine/get-trtc-web-sdk-plugin.js +45 -0
  81. package/tools/rtcengine/get-trtc-web-sdk-plugin.js.map +1 -0
  82. package/utils/handle-component-name.js +0 -16
  83. package/utils/handle-component-name.js.map +1 -1
  84. package/utils/report-cls-client.js +1 -1
  85. package/utils/report-es-client.js +1 -1
  86. package/resource/doc/chatuikit/android/generate_UserSig.md +0 -306
  87. package/resource/doc/chatuikit/android/integrarte_only_tuichat_Android.md +0 -290
  88. package/resource/doc/chatuikit/android/quick_start_Android.md +0 -138
  89. package/resource/doc/chatuikit/android/show_typing_Android.md +0 -43
  90. package/resource/doc/chatuikit/flutter/generate_UserSig.md +0 -306
  91. package/resource/doc/chatuikit/flutter/integrate_tuikit_Flutter.md +0 -133
  92. package/resource/doc/chatuikit/iOS/generate_UserSig.md +0 -306
  93. package/resource/doc/chatuikit/iOS/integrate_only_tuichat_iOS.md +0 -748
  94. package/resource/doc/chatuikit/iOS/quick_start_iOS.md +0 -163
  95. package/resource/doc/chatuikit/iOS/show_typing_iOS.md +0 -52
  96. package/tools/definitions/get_native_live_extra_features_def.js.map +0 -1
  97. package/tools/definitions/get_native_live_interaction_def.js.map +0 -1
  98. package/tools/live/get_native_live_extra_features.js.map +0 -1
  99. package/tools/live/get_native_live_interaction.js.map +0 -1
  100. /package/resource/doc/chatuikit/android/{integrate_tuikit_Android.md → integration.md} +0 -0
  101. /package/resource/doc/chatuikit/{faq/native_sdk/faq.md → android/workflow.md} +0 -0
  102. /package/resource/doc/chatuikit/{flutter/client_api_Flutter.md → faq/flutter_sdk/client-api.md} +0 -0
  103. /package/resource/doc/chatuikit/iOS/{integrate_tuikit_iOS.md → integration.md} +0 -0
  104. /package/resource/doc/chatuikit/react/components/{chatheader.md → chat-header.md} +0 -0
  105. /package/resource/doc/chatuikit/vue/components/{chatheader.md → chat-header.md} +0 -0
@@ -0,0 +1,518 @@
1
+ **AtomicXCore** provides the [CoGuestStore](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/cogueststore) module, purpose-built to manage the complete audience co-hosting workflow. You do not need to handle complex state synchronization or signaling logic—simply call a few intuitive methods to add robust audio and video interaction between viewers and hosts in your live stream.
2
+
3
+ ## Core Features
4
+
5
+ `CoGuestStore` supports the two most common co-hosting scenarios:
6
+ - **Audience Request to Join**: An audience member initiates a co-hosting request, and the host can accept or reject it.
7
+
8
+ - **Host Invites to Join**: The host can invite any audience member in the live room to co-host.
9
+
10
+
11
+ ## Core Concepts
12
+ <table>
13
+ <tr>
14
+ <td rowspan="1" colSpan="1" >**Core Concept**</td>
15
+
16
+ <td rowspan="1" colSpan="1" >**Core Responsibilities**</td>
17
+
18
+ <td rowspan="1" colSpan="1" >**Key APIs / Properties**</td>
19
+ </tr>
20
+
21
+ <tr>
22
+ <td rowspan="1" colSpan="1" >CoGuestStore</td>
23
+
24
+ <td rowspan="1" colSpan="1" >Manages the entire signaling workflow for viewer-host interaction (Apply, Invite, Accept, Reject, Disconnect) and provides Combine publishers for event handling.</td>
25
+
26
+ <td rowspan="1" colSpan="1" >- `state`: A StatePublisher containing `connected`, `applicants`, and `invitees` lists.<br>- `applyForSeat()`: Viewer applies to become a co-guest.<br>- `inviteToSeat()`: Host invites a viewer to take a seat.<br>- `acceptApplication()`: Host accepts a link mic application.<br>- `disConnect()`: Terminates the connection.</td>
27
+ </tr>
28
+
29
+ <tr>
30
+ <td rowspan="1" colSpan="1" >CoGuestState</td>
31
+
32
+ <td rowspan="1" colSpan="1" >Stores all user lists related to link mic, driving UI updates (e.g., notification badges, video window display).</td>
33
+
34
+ <td rowspan="1" colSpan="1" >- `connected`: List of users currently co-hosting.<br>- `applicants`: List of viewers currently applying.<br>- `invitees`: List of viewers currently being invited.</td>
35
+ </tr>
36
+
37
+ <tr>
38
+ <td rowspan="1" colSpan="1" >HostEvent / GuestEvent</td>
39
+
40
+ <td rowspan="1" colSpan="1" >Defines the signaling events received by the host and audience respectively, emitted via Publishers in the Store.</td>
41
+
42
+ <td rowspan="1" colSpan="1" >- `hostEventPublisher`: Publishes host-side events (e.g., onGuestApplicationReceived).<br>- `guestEventPublisher`: Publishes audience-side events (e.g., onHostInvitationReceived).</td>
43
+ </tr>
44
+ </table>
45
+
46
+
47
+ ## Implementation
48
+
49
+ ### Step 1: Component Integration
50
+
51
+ Refer to [Quick Start](https://write.woa.com/document/194571606121816064) to integrate AtomicXCore and complete the setup of `LiveCoreView`.
52
+
53
+ ### Step 2: Implement Audience Request to Join
54
+
55
+ #### Audience-Side Implementation
56
+
57
+ As an audience member, your primary tasks are to **initiate a request, handle the host's response, and leave the seat when desired.**
58
+ 1. **Initiate a Co-hosting Request**
59
+
60
+
61
+ When the user taps the "Request to Join" button, call the `applyForSeat` method.
62
+
63
+ ``` swift
64
+ import AtomicXCore
65
+
66
+ let liveId = "Room ID"
67
+ let guestStore = CoGuestStore.create(liveID: liveId)
68
+
69
+ // User taps "Request to Co-host"
70
+ func requestToConnect() {
71
+ // timeout: Request timeout duration, e.g., 30 seconds
72
+ guestStore.applyForSeat(timeout: 30.0, extraInfo: nil) { result in
73
+ switch result {
74
+ case .success():
75
+ print("Co-hosting request sent, waiting for host response...")
76
+ case .failure(let error):
77
+ print("Failed to send request: \(error.message)")
78
+ }
79
+ }
80
+ }
81
+ ```
82
+ 2. **Listen for Host Response**
83
+
84
+
85
+ Subscribe to `guestEventPublisher` to receive the host's response.
86
+
87
+ ``` swift
88
+ // Subscribe to events during your view controller's initialization
89
+ func subscribeGuestEvents() {
90
+ guestStore.guestEventPublisher
91
+ .sink { [weak self] event in
92
+ if case let .onGuestApplicationResponded(isAccept, hostUser) = event {
93
+ if isAccept {
94
+ print("Host \(hostUser.userName) accepted your request, preparing to go live")
95
+ // 1. Enable camera and microphone
96
+ DeviceStore.shared.openLocalCamera(isFront: true, completion: nil)
97
+ DeviceStore.shared.openLocalMicrophone(completion: nil)
98
+ // 2. Update UI, e.g., disable the request button and show co-hosting status
99
+ } else {
100
+ print("Host \(hostUser.userName) rejected your request")
101
+ // Show a popup to notify the user that the request was rejected
102
+ }
103
+ }
104
+ }
105
+ .store(in: &cancellables) // Manage subscription lifecycle
106
+ }
107
+ ```
108
+ 3. **Leave the Seat**
109
+
110
+
111
+ When a co-hosting audience member wants to end the interaction, call the `disConnect` method to return to audience status.
112
+
113
+ ``` swift
114
+ // User taps "Leave Mic" button
115
+ func leaveSeat() {
116
+ guestStore.disConnect { result in
117
+ switch result {
118
+ case .success():
119
+ print("Successfully left the mic")
120
+ case .failure(let error):
121
+ print("Failed to leave the mic: \(error.message)")
122
+ }
123
+ }
124
+ }
125
+ ```
126
+ 4. **(Optional) Cancel Request**
127
+
128
+
129
+ If the audience member wants to withdraw the request before the host responds, call `cancelApplication`.
130
+
131
+ ``` swift
132
+ // User taps "Cancel Request" while waiting
133
+ func cancelRequest() {
134
+ guestStore.cancelApplication { result in
135
+ switch result {
136
+ case .success():
137
+ print("Request cancelled")
138
+ case .failure(let error):
139
+ print("Failed to cancel request: \(error.message)")
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ #### Host-Side Implementation
146
+
147
+ As a host, your main responsibilities are to **receive requests, display the applicant list, and process requests**.
148
+ 1. **Listen for New Co-hosting Requests**
149
+
150
+
151
+ Subscribe to `hostEventPublisher` to be notified when a new audience member requests to co-host.
152
+
153
+ ``` swift
154
+ import AtomicXCore
155
+
156
+ let liveId = "Room ID"
157
+ let guestStore = CoGuestStore.create(liveID: liveId)
158
+
159
+ // Subscribe to host events
160
+ guestStore.hostEventPublisher
161
+ .sink { [weak self] event in
162
+ if case let .onGuestApplicationReceived(guestUser) = event {
163
+ print("Received co-hosting request from audience member \(guestUser.userName)")
164
+ // Update UI, e.g., show a red dot on the "Request List" button
165
+ }
166
+ }
167
+ .store(in: &cancellables)
168
+ ```
169
+ 2. **Display Request List**
170
+
171
+
172
+ `CoGuestStore` maintains the current list of applicants in real time. Subscribe to this list to update your UI.
173
+
174
+ ``` swift
175
+ // Subscribe to state changes
176
+ guestStore.state
177
+ .subscribe(StatePublisherSelector(keyPath: \CoGuestState.applicants)) // Only observe changes to the applicant list
178
+ .removeDuplicates()
179
+ .sink { applicants in
180
+ print("Current number of applicants: \(applicants.count)")
181
+ // Refresh your "Applicant List" UI here
182
+ // self.applicantListView.update(with: applicants)
183
+ }
184
+ .store(in: &cancellables)
185
+ ```
186
+ 3. **Process Co-hosting Requests**
187
+
188
+
189
+ When you select an audience member and choose "Accept" or "Reject", call the corresponding method.
190
+
191
+ ``` swift
192
+ // Host taps "Accept" button, passing in the applicant's userID
193
+ func accept(userId: String) {
194
+ guestStore.acceptApplication(userID: userId) { result in
195
+ if case .success = result {
196
+ print("Accepted \(userId)'s request, they are joining as a co-host")
197
+ }
198
+ }
199
+ }
200
+
201
+ // Host taps "Reject" button
202
+ func reject(userId: String) {
203
+ guestStore.rejectApplication(userID: userId) { result in
204
+ if case .success = result {
205
+ print("Rejected \(userId)'s request")
206
+ }
207
+ }
208
+ }
209
+ ```
210
+
211
+ ### Step 3: Implement Host Inviting Audience to Join the Stage
212
+
213
+ #### Host-Side Implementation
214
+ 1. **Send Invitation to Audience**
215
+
216
+
217
+ When the host selects an audience member and taps "Invite to Co-host", call the `inviteToSeat` method.
218
+
219
+ ``` swift
220
+ // Host selects an audience member and sends an invite
221
+ func invite(userId: String) {
222
+ // timeout: Invitation timeout duration
223
+ guestStore.inviteToSeat(userID: userId, timeout: 30.0, extraInfo: nil) { result in
224
+ if case .success = result {
225
+ print("Invitation sent to \(userId), waiting for their response...")
226
+ }
227
+ }
228
+ }
229
+ ```
230
+ 2. **Listen for Audience Response**
231
+
232
+
233
+ Listen for the `onHostInvitationResponded` event via `hostEventPublisher`.
234
+
235
+ ``` swift
236
+ // Add this in the hostEventPublisher subscription
237
+ if case let .onHostInvitationResponded(isAccept, guestUser) = event {
238
+ if isAccept {
239
+ print("Audience member \(guestUser.userName) accepted your invitation")
240
+ } else {
241
+ print("Audience member \(guestUser.userName) rejected your invitation")
242
+ }
243
+ }
244
+ ```
245
+
246
+ #### Audience-Side Implementation
247
+ 1. **Receive Host Invitation**
248
+
249
+
250
+ Listen for the `onHostInvitationReceived` event via `guestEventPublisher`.
251
+
252
+ ``` swift
253
+ // Add this in the guestEventPublisher subscription
254
+ if case let .onHostInvitationReceived(hostUser) = event {
255
+ print("Received co-hosting invitation from host \(hostUser.userName)")
256
+ // Show a dialog to let the user choose "Accept" or "Reject"
257
+ // self.showInvitationDialog(from: hostUser)
258
+ }
259
+ ```
260
+ 2. **Respond to Invitation**
261
+
262
+
263
+ After the user makes a selection, call the corresponding method.
264
+
265
+ ``` swift
266
+ let inviterId = "Inviting host's ID" // Obtain from the onHostInvitationReceived event
267
+
268
+ // User taps "Accept"
269
+ func accept() {
270
+ guestStore.acceptInvitation(inviterID: inviterId) { result in
271
+ if case .success = result {
272
+ // Enable camera and microphone
273
+ DeviceStore.shared.openLocalCamera(isFront: true, completion: nil)
274
+ DeviceStore.shared.openLocalMicrophone(completion: nil)
275
+ }
276
+ }
277
+ }
278
+
279
+ // User taps "Reject"
280
+ func reject() {
281
+ guestStore.rejectInvitation(inviterID: inviterId) { result in
282
+ // ...
283
+ }
284
+ }
285
+ ```
286
+
287
+ ### Run and Test
288
+
289
+ After integrating the above features, use two audience members and a host to test co-hosting. For example, Audience A enables both camera and microphone, while Audience B enables only the microphone. The result is shown below. For UI customization, see [Refining UI Details](https://write.woa.com/#736c00b3-02dc-494b-838d-226439fd3e15).
290
+
291
+ ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100027182498/da12f5cec6de11f09e745254007c27c5.png)
292
+
293
+
294
+ ## Refining UI Details
295
+
296
+ Use the "slot" capability provided by the `LiveCoreView.VideoViewDelegate` protocol to add custom views on top of the co-host video stream. For example, display the user's nickname, avatar, or a placeholder image when the camera is off to enhance the visual experience.
297
+
298
+ ### Displaying Nicknames on Video Streams
299
+
300
+ #### Implementation Example
301
+
302
+ ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100027182498/f94d5741c6de11f0aedb525400454e06.png)
303
+
304
+
305
+ #### Implementation Steps
306
+
307
+ > **Note:**
308
+ >
309
+
310
+ > For complete implementation details, refer to the open-source TUILiveKit project files [AnchorCoGuestView.swift](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/live/Sources/Features/AnchorBoardcast/View/LivingView/Video/AnchorCoGuestView.swift) and [AnchorEmptySeatView.swift](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/live/Sources/Features/AnchorBoardcast/View/LivingView/Video/AnchorEmptySeatView.swift).
311
+ >
312
+
313
+ - **Step 1**: Create the foreground view `CustomSeatView` to display user info above the video stream.
314
+
315
+ ``` swift
316
+ import UIKit
317
+
318
+ // Custom floating user info view (foreground)
319
+ class CustomSeatView: UIView {
320
+ lazy var nameLabel: UILabel = {
321
+ let label = UILabel()
322
+ label.textColor = .white
323
+ label.font = .systemFont(ofSize: 14)
324
+ return label
325
+ }()
326
+
327
+ override init(frame: CGRect) {
328
+ super.init(frame: frame)
329
+ backgroundColor = UIColor.black.withAlphaComponent(0.5)
330
+ addSubview(nameLabel)
331
+ nameLabel.snp.makeConstraints { make in
332
+ make.bottom.equalToSuperview().offset(-5)
333
+ make.leading.equalToSuperview().offset(5)
334
+ }
335
+ }
336
+ }
337
+ ```
338
+ - **Step 2**: Create the background view `CustomAvatarView` to serve as a placeholder when the user has no video stream.
339
+
340
+ ``` swift
341
+ import UIKit
342
+
343
+ // Custom avatar placeholder view (background)
344
+ class CustomAvatarView: UIView {
345
+ lazy var avatarImageView: UIImageView = {
346
+ let imageView = UIImageView()
347
+ imageView.tintColor = .gray
348
+ return imageView
349
+ }()
350
+
351
+ override init(frame: CGRect) {
352
+ super.init(frame: frame)
353
+ backgroundColor = .clear
354
+ layer.cornerRadius = 30
355
+ addSubview(avatarImageView)
356
+ avatarImageView.snp.makeConstraints { make in
357
+ make.center.equalToSuperview()
358
+ make.width.height.equalTo(60)
359
+ }
360
+ }
361
+ }
362
+ ```
363
+ - **Step 3**: Implement the `VideoViewDelegate.createCoGuestView` protocol method, returning the appropriate view based on the `viewLayer` value.
364
+
365
+ ``` swift
366
+ import AtomicXCore
367
+
368
+ // 1. In your view controller, conform to the VideoViewDelegate protocol
369
+ class YourViewController: UIViewController, VideoViewDelegate {
370
+
371
+ // ... other code ...
372
+
373
+ // 2. Implement the protocol method to handle both viewLayer types
374
+ func createCoGuestView(seatInfo: TUISeatFullInfo, viewLayer: ViewLayer) -> UIView? {
375
+ guard let userId = seatInfo.userID, !userId.isEmpty else {
376
+ return nil
377
+ }
378
+ if viewLayer == .foreground {
379
+ // When the user's camera is on, display the foreground view
380
+ let seatView = CustomSeatView()
381
+ seatView.nameLabel.text = seatInfo.userName
382
+ return seatView
383
+ } else { // viewLayer == .background
384
+ // When the user's camera is off, display the background view
385
+ let avatarView = CustomAvatarView()
386
+ // Load the user's avatar here using seatInfo.userAvatar if available
387
+ return avatarView
388
+ }
389
+ }
390
+ }
391
+ ```
392
+
393
+ #### Parameter Description:
394
+ <table>
395
+ <tr>
396
+ <td rowspan="1" colSpan="1" >**Parameter**</td>
397
+
398
+ <td rowspan="1" colSpan="1" >**Type**</td>
399
+
400
+ <td rowspan="1" colSpan="1" >**Description**</td>
401
+ </tr>
402
+
403
+ <tr>
404
+ <td rowspan="1" colSpan="1" >`seatInfo`</td>
405
+
406
+ <td rowspan="1" colSpan="1" >`SeatFullInfo?`</td>
407
+
408
+ <td rowspan="1" colSpan="1" >Seat information object, containing detailed information about the user on the seat</td>
409
+ </tr>
410
+
411
+ <tr>
412
+ <td rowspan="1" colSpan="1" >`seatInfo.userId`</td>
413
+
414
+ <td rowspan="1" colSpan="1" >`String`</td>
415
+
416
+ <td rowspan="1" colSpan="1" >ID of the user on the seat</td>
417
+ </tr>
418
+
419
+ <tr>
420
+ <td rowspan="1" colSpan="1" >`seatInfo.userName`</td>
421
+
422
+ <td rowspan="1" colSpan="1" >`String`</td>
423
+
424
+ <td rowspan="1" colSpan="1" >Nickname of the user on the seat</td>
425
+ </tr>
426
+
427
+ <tr>
428
+ <td rowspan="1" colSpan="1" >`seatInfo.userAvatar`</td>
429
+
430
+ <td rowspan="1" colSpan="1" >`String`</td>
431
+
432
+ <td rowspan="1" colSpan="1" >Avatar URL of the user on the seat</td>
433
+ </tr>
434
+
435
+ <tr>
436
+ <td rowspan="1" colSpan="1" >`seatInfo.userMicrophoneStatus`</td>
437
+
438
+ <td rowspan="1" colSpan="1" >`DeviceStatus`</td>
439
+
440
+ <td rowspan="1" colSpan="1" >Microphone status of the user on the seat</td>
441
+ </tr>
442
+
443
+ <tr>
444
+ <td rowspan="1" colSpan="1" >`seatInfo.userCameraStatus`</td>
445
+
446
+ <td rowspan="1" colSpan="1" >`DeviceStatus`</td>
447
+
448
+ <td rowspan="1" colSpan="1" >Camera status of the user on the seat</td>
449
+ </tr>
450
+
451
+ <tr>
452
+ <td rowspan="1" colSpan="1" >`viewLayer`</td>
453
+
454
+ <td rowspan="1" colSpan="1" >`ViewLayer`</td>
455
+
456
+ <td rowspan="1" colSpan="1" >View layer enum:<br>- `.foreground`: Foreground widget view, always displayed on top of the video<br>- `.background`: Background widget view, displayed below the foreground view, only shown when the user has no video stream (e.g., camera is off); typically used for the user's avatar or a placeholder image</td>
457
+ </tr>
458
+ </table>
459
+
460
+
461
+ ## API Documentation
462
+
463
+ For detailed information on all public interfaces, properties, and methods of [CoGuestStore](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/cogueststore) and related classes, refer to the official API documentation included with the [AtomicXCore](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore) framework. The relevant stores used in this guide include:
464
+ <table>
465
+ <tr>
466
+ <td rowspan="1" colSpan="1" >**Store/Component**</td>
467
+
468
+ <td rowspan="1" colSpan="1" >**Function Description**</td>
469
+
470
+ <td rowspan="1" colSpan="1" >**API Documentation**</td>
471
+ </tr>
472
+
473
+ <tr>
474
+ <td rowspan="1" colSpan="1" >LiveCoreView</td>
475
+
476
+ <td rowspan="1" colSpan="1" >Core view component for live video stream display and interaction. Handles video rendering and widget management, supporting host streaming, audience co-hosting, host connections, and more.</td>
477
+
478
+ <td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/livecoreview)</td>
479
+ </tr>
480
+
481
+ <tr>
482
+ <td rowspan="1" colSpan="1" >DeviceStore</td>
483
+
484
+ <td rowspan="1" colSpan="1" >Audio and video device control: microphone (on/off, volume), camera (on/off, switch, quality), screen sharing, real-time device status monitoring.</td>
485
+
486
+ <td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/devicestore)</td>
487
+ </tr>
488
+
489
+ <tr>
490
+ <td rowspan="1" colSpan="1" >CoGuestStore</td>
491
+
492
+ <td rowspan="1" colSpan="1" >Audience co-hosting management: request/invite/accept/reject co-hosting, permission control (microphone/camera), state synchronization.</td>
493
+
494
+ <td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore/cogueststore)</td>
495
+ </tr>
496
+ </table>
497
+
498
+
499
+ ## FAQs
500
+
501
+ ### How do I manage the lifecycle and events of custom views added via `VideoViewDelegate`?
502
+
503
+ `LiveCoreView` automatically manages the addition and removal of views returned by your adapter methods. You do not need to handle this manually. To support user interactions (such as click events) in your custom view, add the appropriate event listeners when creating the view.
504
+
505
+ ### What is the purpose of the viewLayer parameter in VideoViewAdapter?
506
+
507
+ The viewLayer parameter distinguishes between foreground and background widgets:
508
+ - `.foreground`: Foreground layer, always displayed on top of the video.
509
+
510
+ - `.background`: Background layer, displayed only when the user has no video stream (e.g., camera is off); typically used to show the user's avatar or a placeholder image.
511
+
512
+
513
+ ### Why is my custom view not showing up?
514
+ - **Check adapter settings**: Ensure you have called `coreView.videoViewDelegate = self` and set the adapter successfully.
515
+
516
+ - **Check implementation method**: Confirm that you have correctly implemented the relevant adapter method (such as `createCoGuestView`).
517
+
518
+ - **Check return value**: Make sure your adapter method returns a valid `UIView` instance at the appropriate time, not null. Add logs in the adapter method for debugging if needed.