@tencent-rtc/mcp 1.3.8 → 1.3.9
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/package.json +1 -1
- package/resource/doc/chatuikit/android/integration.md +499 -203
- package/resource/doc/chatuikit/android/workflow.md +713 -0
- package/resource/doc/chatuikit/flutter/integration.md +1 -1
- package/resource/doc/livekit/voice/android/voice-audience-list.md +334 -0
- package/resource/doc/livekit/voice/android/voice-audio-effect.md +380 -0
- package/resource/doc/livekit/voice/android/voice-barrage.md +565 -0
- package/resource/doc/livekit/voice/android/voice-co-guest-interaction.md +745 -0
- package/resource/doc/livekit/voice/android/voice-gift.md +822 -0
- package/resource/doc/livekit/voice/android/voice-host-interaction.md +703 -0
- package/resource/doc/livekit/voice/android/voice-integration.md +940 -0
- package/resource/doc/livekit/voice/android/voice-room-list.md +575 -0
- package/resource/doc/livekit/voice/flutter/voice-co-guest-interaction.md +675 -0
- package/resource/doc/livekit/voice/flutter/voice-integration.md +936 -0
- package/resource/doc/livekit/voice/ios/voice-audience-list.md +339 -0
- package/resource/doc/livekit/voice/ios/voice-audio-effect.md +370 -0
- package/resource/doc/livekit/voice/ios/voice-barrage.md +517 -0
- package/resource/doc/livekit/voice/ios/voice-co-guest-interaction.md +708 -0
- package/resource/doc/livekit/voice/ios/voice-gift.md +783 -0
- package/resource/doc/livekit/voice/ios/voice-host-interaction.md +770 -0
- package/resource/doc/livekit/voice/ios/voice-integration.md +898 -0
- package/resource/doc/livekit/voice/ios/voice-room-list.md +485 -0
- package/resource/doc/roomkit/vue/integration.md +179 -288
- package/resource/doc/roomkit/vue/workflow.md +499 -253
- package/resource/doc/tuicallkit/android/integration.md +539 -83
- package/resource/doc/tuicallkit/android/workflow.md +441 -0
- package/tools/common/present-scenario-choice.js +16 -0
- package/tools/common/present-scenario-choice.js.map +1 -0
- package/tools/definitions/get_native_call_uikit_integration_def.js +25 -9
- package/tools/definitions/get_native_call_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_native_chat_uikit_integration_def.js +36 -14
- package/tools/definitions/get_native_chat_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_native_live_uikit_integration_def.js +55 -29
- package/tools/definitions/get_native_live_uikit_integration_def.js.map +1 -1
- package/tools/definitions/get_native_live_uikit_interaction_def.js +43 -54
- package/tools/definitions/get_native_live_uikit_interaction_def.js.map +1 -1
- package/tools/definitions/get_web_room_feature_detail_def.js +52 -55
- package/tools/definitions/get_web_room_feature_detail_def.js.map +1 -1
- package/tools/definitions/get_web_room_uikit_integration_def.js +41 -25
- package/tools/definitions/get_web_room_uikit_integration_def.js.map +1 -1
- package/tools/definitions/present_scenario_choice_def.js +53 -0
- package/tools/definitions/present_scenario_choice_def.js.map +1 -0
- package/tools/definitions/record_prompt_def.js +26 -21
- package/tools/definitions/record_prompt_def.js.map +1 -1
- package/tools/definitions/record_result_def.js +20 -4
- package/tools/definitions/record_result_def.js.map +1 -1
- package/tools/index.js +2 -0
- package/tools/index.js.map +1 -1
- package/tools/live/get-native-live-uikit-integration.js +110 -34
- package/tools/live/get-native-live-uikit-integration.js.map +1 -1
- package/tools/live/get_native_live_uikit_interaction.js +128 -35
- package/tools/live/get_native_live_uikit_interaction.js.map +1 -1
- package/utils/report-cls-client.js +1 -1
- package/utils/report-es-client.js +1 -1
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
`AtomicXCore` provides two core modules: `CoHostStore` for **cross-room connections** and `BattleStore` for **PK battles**. This guide explains how to integrate these modules to enable connection and PK features in a voice chat room application.
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
## Core Concepts
|
|
6
|
+
<table>
|
|
7
|
+
<tr>
|
|
8
|
+
<td rowspan="1" colSpan="1" >**Core Concept**</td>
|
|
9
|
+
|
|
10
|
+
<td rowspan="1" colSpan="1" >**Type**</td>
|
|
11
|
+
|
|
12
|
+
<td rowspan="1" colSpan="1" >**Core Responsibilities & Description**</td>
|
|
13
|
+
</tr>
|
|
14
|
+
|
|
15
|
+
<tr>
|
|
16
|
+
<td rowspan="1" colSpan="1" >**CoHostStore**</td>
|
|
17
|
+
|
|
18
|
+
<td rowspan="1" colSpan="1" >`abstract class`</td>
|
|
19
|
+
|
|
20
|
+
<td rowspan="1" colSpan="1" >Manages the lifecycle of host-to-host connections. Provides connection APIs such as `requestHostConnection` and `acceptHostConnection`.</td>
|
|
21
|
+
</tr>
|
|
22
|
+
|
|
23
|
+
<tr>
|
|
24
|
+
<td rowspan="1" colSpan="1" >**BattleStore**</td>
|
|
25
|
+
|
|
26
|
+
<td rowspan="1" colSpan="1" >`abstract class`</td>
|
|
27
|
+
|
|
28
|
+
<td rowspan="1" colSpan="1" >Handles PK battle signaling and state management across rooms, including PK status tracking.</td>
|
|
29
|
+
</tr>
|
|
30
|
+
|
|
31
|
+
<tr>
|
|
32
|
+
<td rowspan="1" colSpan="1" >**LiveListStore**</td>
|
|
33
|
+
|
|
34
|
+
<td rowspan="1" colSpan="1" >`abstract class`</td>
|
|
35
|
+
|
|
36
|
+
<td rowspan="1" colSpan="1" >Fetches the list of active live rooms (`fetchLiveList`). Use this to discover rooms available for connection.</td>
|
|
37
|
+
</tr>
|
|
38
|
+
|
|
39
|
+
<tr>
|
|
40
|
+
<td rowspan="1" colSpan="1" >**LiveSeatStore**</td>
|
|
41
|
+
|
|
42
|
+
<td rowspan="1" colSpan="1" >`abstract class`</td>
|
|
43
|
+
|
|
44
|
+
<td rowspan="1" colSpan="1" >Manages seat states within a room, including cross-room seats during connection. Tracks user join/leave events and microphone status.</td>
|
|
45
|
+
</tr>
|
|
46
|
+
|
|
47
|
+
<tr>
|
|
48
|
+
<td rowspan="1" colSpan="1" >**CoHostLayoutTemplate**</td>
|
|
49
|
+
|
|
50
|
+
<td rowspan="1" colSpan="1" >`enum`</td>
|
|
51
|
+
|
|
52
|
+
<td rowspan="1" colSpan="1" >Defines seat layout templates for cross-room connections, e.g., `HOST_STATIC_VOICE_6V6`.</td>
|
|
53
|
+
</tr>
|
|
54
|
+
|
|
55
|
+
<tr>
|
|
56
|
+
<td rowspan="1" colSpan="1" >**BattleConfig**</td>
|
|
57
|
+
|
|
58
|
+
<td rowspan="1" colSpan="1" >`data`</td>
|
|
59
|
+
|
|
60
|
+
<td rowspan="1" colSpan="1" >Configures PK battle details such as duration (`duration`) and whether a secondary response is required (`needResponse`).</td>
|
|
61
|
+
</tr>
|
|
62
|
+
</table>
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Prerequisites
|
|
66
|
+
|
|
67
|
+
Integrate the [Quick Start](https://write.woa.com/document/194571595678187521) and ensure you have implemented both **Host Start Live** and **Audience Watch** features.
|
|
68
|
+
|
|
69
|
+
## Host Initiates a Connection
|
|
70
|
+
|
|
71
|
+
### Step 1: Fetch Active Streamers
|
|
72
|
+
|
|
73
|
+
To initiate a connection or PK, the host must retrieve the current list of live rooms and select a target host.
|
|
74
|
+
|
|
75
|
+
**Implementation:** Call `LiveListStore.shared().fetchLiveList`.
|
|
76
|
+
|
|
77
|
+
> **Note:**
|
|
78
|
+
>
|
|
79
|
+
> - If the target room is missing from the returned list, verify that isPublicVisible in TUILiveInfo is set to true when starting the stream.
|
|
80
|
+
> - This API supports pagination. Use the cursor from the onSuccess callback for subsequent fetches. An empty cursor indicates all rooms have been fetched.
|
|
81
|
+
> - For optimal performance, set pageCount to 20.
|
|
82
|
+
|
|
83
|
+
``` java
|
|
84
|
+
import io.trtc.tuikit.atomicxcore.api.live.LiveListStore
|
|
85
|
+
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
|
|
86
|
+
|
|
87
|
+
fun fetchLiveListForCoHost() {
|
|
88
|
+
val cursor = "" // Initial fetch
|
|
89
|
+
val pageCount = 20
|
|
90
|
+
|
|
91
|
+
LiveListStore.shared().fetchLiveList(cursor, pageCount, object : CompletionHandler {
|
|
92
|
+
override fun onSuccess() {
|
|
93
|
+
println("Live room list fetched successfully")
|
|
94
|
+
// Update your invitation panel with LiveListStore.liveState.liveList
|
|
95
|
+
// inviteAdapter.submitList(LiveListStore.liveState.liveList)
|
|
96
|
+
}
|
|
97
|
+
override fun onFailure(code: Int, desc: String) {
|
|
98
|
+
println("Failed to fetch live room list: $code")
|
|
99
|
+
}
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Step 2: Send a Co-hosting Invitation
|
|
105
|
+
|
|
106
|
+
When a host selects another host, use `CoHostStore.requestHostConnection` to send a connection invitation.
|
|
107
|
+
|
|
108
|
+
> **Note:**
|
|
109
|
+
>
|
|
110
|
+
> 1. AtomicXCore supports up to **9** interconnected rooms, each with up to **50** users.
|
|
111
|
+
> 2. This interface supports batch invitations, which you can use continuously; to check if an invitation to a single live room was successful, you need to listen for the `onSuccess` callback.
|
|
112
|
+
> 3. The API supports extension fields. These are delivered to the target host via `onCoHostRequestReceived` in `CoHostListener`. Use this to pass business logic such as "start PK immediately".
|
|
113
|
+
|
|
114
|
+
``` java
|
|
115
|
+
import io.trtc.tuikit.atomicxcore.api.live.CoHostLayoutTemplate
|
|
116
|
+
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
|
|
117
|
+
|
|
118
|
+
val targetHostLiveID = "target_host_room_id"
|
|
119
|
+
val layoutTemplate = CoHostLayoutTemplate.HOST_STATIC_VOICE_6V6
|
|
120
|
+
val timeout = 10 // seconds
|
|
121
|
+
val extraInfo = "" // e.g., direct PK flag
|
|
122
|
+
|
|
123
|
+
coHostStore.requestHostConnection(
|
|
124
|
+
targetHostLiveID,
|
|
125
|
+
layoutTemplate,
|
|
126
|
+
timeout,
|
|
127
|
+
extraInfo,
|
|
128
|
+
object : CompletionHandler {
|
|
129
|
+
override fun onSuccess() {
|
|
130
|
+
println("Connection request sent. Awaiting response...")
|
|
131
|
+
}
|
|
132
|
+
override fun onFailure(code: Int, desc: String) {
|
|
133
|
+
println("Failed to send invitation: $desc")
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Step 3: Target Streamer Receives Invitation
|
|
140
|
+
|
|
141
|
+
The target host receives the invitation via `onCoHostRequestReceived` in `CoHostListener`. Display a UI prompt such as "Host invites you to join the connection".
|
|
142
|
+
``` java
|
|
143
|
+
private val coHostListener = object : CoHostListener() {
|
|
144
|
+
override fun onCoHostRequestReceived(
|
|
145
|
+
inviter: SeatUserInfo, extensionInfo: String
|
|
146
|
+
){
|
|
147
|
+
// Show invitation dialog
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Step 4: Target Host Accepts or Rejects Invitation
|
|
153
|
+
|
|
154
|
+
In the invitation UI, the target host can accept or reject. Call `acceptHostConnection` or `rejectHostConnection` as appropriate.
|
|
155
|
+
``` java
|
|
156
|
+
private val coHostStore = CoHostStore.create(liveID)
|
|
157
|
+
|
|
158
|
+
private val coHostListener = object : CoHostListener() {
|
|
159
|
+
override fun onCoHostRequestReceived(
|
|
160
|
+
inviter: SeatUserInfo, extensionInfo: String
|
|
161
|
+
){
|
|
162
|
+
// Accept connection
|
|
163
|
+
coHostStore.acceptHostConnection(fromHostLiveID, null)
|
|
164
|
+
// Or reject
|
|
165
|
+
// coHostStore.rejectHostConnection(fromHostLiveID, null)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Step 5: Render Co-hosting UI Layout
|
|
171
|
+
|
|
172
|
+
After connection is established, listen to `coHostStatus` in `CoHostStore.coHostState` and `seatList` in `LiveSeatStore.liveSeatState` to update the seat layout dynamically.
|
|
173
|
+
``` java
|
|
174
|
+
import io.trtc.tuikit.atomicxcore.api.live.CoHostStatus
|
|
175
|
+
import io.trtc.tuikit.atomicxcore.api.live.LiveSeatStore
|
|
176
|
+
import io.trtc.tuikit.atomicxcore.api.live.SeatInfo
|
|
177
|
+
import kotlinx.coroutines.flow.collect
|
|
178
|
+
|
|
179
|
+
private val liveSeatStore = LiveSeatStore.create(liveID)
|
|
180
|
+
|
|
181
|
+
coHostStore.coHostState.coHostStatus.collect { status ->
|
|
182
|
+
if (status == CoHostStatus.CONNECTED) {
|
|
183
|
+
// Render connection layout (e.g., 6v6)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
liveSeatStore.liveSeatState.seatList.collect { seatList: List<SeatInfo> ->
|
|
188
|
+
// Update avatars, mute status, etc.
|
|
189
|
+
// Use seatInfo.userInfo.liveID to distinguish local/remote users.
|
|
190
|
+
// Use seatInfo.userInfo.microphoneStatus for mute icon.
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Step 6: Invite Additional Streamers During Co-hosting
|
|
195
|
+
|
|
196
|
+
You can invite more hosts even after a connection is established by calling `requestHostConnection` again.
|
|
197
|
+
``` java
|
|
198
|
+
import io.trtc.tuikit.atomicxcore.api.live.CoHostLayoutTemplate
|
|
199
|
+
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
|
|
200
|
+
|
|
201
|
+
val targetHostLiveID = "target_host_room_id"
|
|
202
|
+
val layoutTemplate = CoHostLayoutTemplate.HOST_STATIC_VOICE_6V6
|
|
203
|
+
val timeout = 10
|
|
204
|
+
val extraInfo = ""
|
|
205
|
+
|
|
206
|
+
coHostStore.requestHostConnection(
|
|
207
|
+
targetHostLiveID,
|
|
208
|
+
layoutTemplate,
|
|
209
|
+
timeout,
|
|
210
|
+
extraInfo,
|
|
211
|
+
object : CompletionHandler {
|
|
212
|
+
override fun onSuccess() {
|
|
213
|
+
println("Connection request sent. Awaiting response...")
|
|
214
|
+
}
|
|
215
|
+
override fun onFailure(code: Int, desc: String) {
|
|
216
|
+
println("Failed to send invitation: $desc")
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Step 7: Exit Co-hosting
|
|
223
|
+
|
|
224
|
+
To disconnect, call `CoHostStore.exitHostConnection`. Remaining hosts should update their seat layout accordingly.
|
|
225
|
+
``` java
|
|
226
|
+
public void onExitButtonClicked() {
|
|
227
|
+
val coHostStore = CoHostStore.create(liveInfo.liveID)
|
|
228
|
+
coHostStore.exitHostConnection(object : CompletionHandler{
|
|
229
|
+
override fun onSuccess(){
|
|
230
|
+
// Handle successful exit
|
|
231
|
+
}
|
|
232
|
+
override fun onFailure(code: Int, desc: String){
|
|
233
|
+
// Handle error
|
|
234
|
+
}
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## PK Streamer Initiates a PK
|
|
240
|
+
|
|
241
|
+
BattleStreamers can start PK battles using two main flows, depending on the room state before PK begins:
|
|
242
|
+
<table>
|
|
243
|
+
<tr>
|
|
244
|
+
<td rowspan="1" colSpan="1" >**PK Mode**</td>
|
|
245
|
+
|
|
246
|
+
<td rowspan="1" colSpan="1" >**Room State (Before PK)**</td>
|
|
247
|
+
|
|
248
|
+
<td rowspan="1" colSpan="1" >**Room State (After PK)**</td>
|
|
249
|
+
</tr>
|
|
250
|
+
|
|
251
|
+
<tr>
|
|
252
|
+
<td rowspan="1" colSpan="1" >Scenario 1: PK after connection</td>
|
|
253
|
+
|
|
254
|
+
<td rowspan="1" colSpan="1" >Both sides connected</td>
|
|
255
|
+
|
|
256
|
+
<td rowspan="1" colSpan="1" >Returns to connection state</td>
|
|
257
|
+
</tr>
|
|
258
|
+
|
|
259
|
+
<tr>
|
|
260
|
+
<td rowspan="1" colSpan="1" >Scenario 2: Connection with PK mode</td>
|
|
261
|
+
|
|
262
|
+
<td rowspan="1" colSpan="1" >Both sides not connected</td>
|
|
263
|
+
|
|
264
|
+
<td rowspan="1" colSpan="1" >Returns to connection state</td>
|
|
265
|
+
</tr>
|
|
266
|
+
</table>
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
### Scenario 1: PK After Connection
|
|
270
|
+
|
|
271
|
+
AtomicXCore enables hosts to start a timed PK battle once connected. Typical UI flow:
|
|
272
|
+
1. Send connection invitation; invited host accepts.
|
|
273
|
+
|
|
274
|
+
2. Hosts click PK to start a timed battle. Winner is determined by gifts received.
|
|
275
|
+
|
|
276
|
+
3. Target host receives a PK prompt and can accept.
|
|
277
|
+
|
|
278
|
+
4. UI enters PK mode and displays a progress bar (based on gifts, likes, etc.).
|
|
279
|
+
|
|
280
|
+
5. When PK ends, winner/loser is displayed and a punishment period begins.
|
|
281
|
+
|
|
282
|
+
6. After PK, state returns to connection mode.
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+

|
|
286
|
+
|
|
287
|
+
|
|
288
|
+

|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
#### Step 1: Initiate PK Invitation
|
|
292
|
+
|
|
293
|
+
To start a PK battle among connected hosts, use `BattleStore.requestBattle`. Configure PK duration, whether a response is required, and any extension info.
|
|
294
|
+
|
|
295
|
+
> **Note:**
|
|
296
|
+
>
|
|
297
|
+
> 1. Default PK duration is 5 minutes if not set in `BattleConfig`.
|
|
298
|
+
> 2. To start PK immediately, set `needResponse` to `false`.
|
|
299
|
+
> 3. If `needResponse` is `false`, set `timeout` to 0.
|
|
300
|
+
> 4. If the target host does not respond within the timeout, both hosts receive `onBattleRequestTimeout`. PK can be retried.
|
|
301
|
+
|
|
302
|
+
``` java
|
|
303
|
+
val targetUserID = "target_host_user_id"
|
|
304
|
+
|
|
305
|
+
val config = BattleConfig(
|
|
306
|
+
duration = 30, // seconds
|
|
307
|
+
needResponse = true,
|
|
308
|
+
extensionInfo = ""
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
battleStore.requestBattle(
|
|
312
|
+
config,
|
|
313
|
+
listOf(targetUserID),
|
|
314
|
+
timeout = 10, // seconds
|
|
315
|
+
completion = null
|
|
316
|
+
)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### Step 2: Target Streamer Receives PK Invitation
|
|
320
|
+
|
|
321
|
+
The target host receives the PK request via `onBattleRequestReceived` in `BattleListener`. Use `needResponse` in `battleInfo.config` to determine whether to prompt the user.
|
|
322
|
+
- If `needResponse` is false, enter PK state directly.
|
|
323
|
+
|
|
324
|
+
- If true, show a dialog and enter PK on acceptance.
|
|
325
|
+
|
|
326
|
+
``` java
|
|
327
|
+
private val mBattleListener: BattleListener = object : BattleListener() {
|
|
328
|
+
override fun onBattleRequestReceived(
|
|
329
|
+
battleId: String,
|
|
330
|
+
inviter: SeatUserInfo,
|
|
331
|
+
invitee: SeatUserInfo,
|
|
332
|
+
) {
|
|
333
|
+
super.onBattleRequestReceived(battleInfo, inviter, invitee)
|
|
334
|
+
val userId = inviter.userId
|
|
335
|
+
val userName = inviter.userName
|
|
336
|
+
val needResponse = battleInfo.config.needResponse
|
|
337
|
+
// Show PK prompt if needed
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### Step 3: Enter PK State
|
|
343
|
+
|
|
344
|
+
When `onBattleStarted` is triggered in `BattleListener`, render the PK progress bar in your UI.
|
|
345
|
+
- If `needResponse` is `false`, PK starts automatically.
|
|
346
|
+
|
|
347
|
+
- If `needResponse` is `true`, PK starts after all invited hosts call `acceptBattle`.
|
|
348
|
+
|
|
349
|
+
- Hosts joining PK receive `onUserJoinBattle`.
|
|
350
|
+
|
|
351
|
+
- All PK participants receive `onBattleStarted`.
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+

|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
#### Step 4: End PK State
|
|
358
|
+
|
|
359
|
+
PK ends either when the duration expires or when all hosts leave.
|
|
360
|
+
1. **PK Time Expires:** All hosts receive `onBattleEnded`.
|
|
361
|
+
|
|
362
|
+
2. **Manual Exit:** Any host can call `exitBattle`. Remaining hosts stay in PK and receive `onUserExitBattle`. If all hosts exit, PK ends early.
|
|
363
|
+
|
|
364
|
+
``` java
|
|
365
|
+
val battleStore: BattleStore = BattleStore.create(liveID)
|
|
366
|
+
battleID = battleStore.battleState.currentBattleInfo.value?.battleID
|
|
367
|
+
battleStore.exitBattle(battleID, null)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
After PK ends, use `onBattleEnded` to display results and determine winner/loser.
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
> **Note:**
|
|
374
|
+
>
|
|
375
|
+
> - After PK ends, the session returns to cross-room co-hosting.
|
|
376
|
+
> - To end co-hosting after PK, call `exitHostConnection`.
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
### Scenario 2: Co-hosting with PK Mode
|
|
380
|
+
|
|
381
|
+
**AtomicXCore** supports direct PK initiation during a live session, without prior co-hosting. After PK ends, the session returns to the live room state.
|
|
382
|
+
1. Streamer clicks `PK`, opens a panel with active streamers (see Step 1 above).
|
|
383
|
+
|
|
384
|
+
2. Selects a streamer and sends a PK invitation.
|
|
385
|
+
|
|
386
|
+
3. Target streamer receives the invitation and can accept or reject.
|
|
387
|
+
|
|
388
|
+
4. Upon acceptance, PK starts automatically. Points are accumulated via gifts or likes.
|
|
389
|
+
|
|
390
|
+
5. After PK ends, the winner is determined by points.
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+

|
|
394
|
+
|
|
395
|
+
|
|
396
|
+

|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
> **Note:**
|
|
402
|
+
>
|
|
403
|
+
|
|
404
|
+
> This workflow requires both CoHostStore and BattleStore, with `needResponse` in BattleConfig set to `false`.
|
|
405
|
+
>
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
#### Step 1: Send Co-hosting Request
|
|
409
|
+
|
|
410
|
+
This step is similar to Steps 1 and 2 in "Host Initiates a Connection". Use the `extensionInfo` field in `requestHostConnection` to indicate PK mode for UI differentiation.
|
|
411
|
+
- If `extraInfo` is `{"withPK:true"}`, show "Host invites you to PK".
|
|
412
|
+
|
|
413
|
+
- If `extraInfo` is `{"withPK:false"}`, show "Host invites you to join a cross-room connection".
|
|
414
|
+
|
|
415
|
+
``` java
|
|
416
|
+
import io.trtc.tuikit.atomicxcore.api.live.CoHostLayoutTemplate
|
|
417
|
+
import io.trtc.tuikit.atomicxcore.api.CompletionHandler
|
|
418
|
+
|
|
419
|
+
val targetHostLiveID = "target_host_room_id"
|
|
420
|
+
val layoutTemplate = CoHostLayoutTemplate.HOST_STATIC_VOICE_6V6
|
|
421
|
+
val timeout = 10
|
|
422
|
+
val extraInfo = "withPK:true"
|
|
423
|
+
|
|
424
|
+
coHostStore.requestHostConnection(
|
|
425
|
+
targetHostLiveID,
|
|
426
|
+
layoutTemplate,
|
|
427
|
+
timeout,
|
|
428
|
+
extraInfo,
|
|
429
|
+
object : CompletionHandler {
|
|
430
|
+
override fun onSuccess() {
|
|
431
|
+
println("Connection request sent. Awaiting response...")
|
|
432
|
+
}
|
|
433
|
+
override fun onFailure(code: Int, desc: String) {
|
|
434
|
+
println("Failed to send invitation: $desc")
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
)
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
#### Step 2: Target Streamer Receives Request and Confirms
|
|
441
|
+
|
|
442
|
+
Target host receives `onCoHostRequestReceived` and can accept or reject.
|
|
443
|
+
``` java
|
|
444
|
+
private val coHostListener = object : CoHostListener() {
|
|
445
|
+
override fun onCoHostRequestReceived(
|
|
446
|
+
inviter: SeatUserInfo, extensionInfo: String
|
|
447
|
+
){
|
|
448
|
+
// Show invitation dialog
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Accept or reject using:
|
|
454
|
+
``` java
|
|
455
|
+
private val coHostStore = CoHostStore.create(liveID)
|
|
456
|
+
|
|
457
|
+
private val coHostListener = object : CoHostListener() {
|
|
458
|
+
override fun onCoHostRequestReceived(
|
|
459
|
+
inviter: SeatUserInfo, extensionInfo: String
|
|
460
|
+
){
|
|
461
|
+
coHostStore.acceptHostConnection(fromHostLiveID, null)
|
|
462
|
+
// Or reject
|
|
463
|
+
// coHostStore.rejectHostConnection(fromHostLiveID, null)
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### Step 3: Initiate PK Automatically
|
|
469
|
+
|
|
470
|
+
When the target streamer accepts, immediately call `BattleStore.requestBattle` with `needResponse: false` to start PK.
|
|
471
|
+
``` java
|
|
472
|
+
override fun onCoHostRequestAccepted(invitee: SeatUserInfo) {
|
|
473
|
+
coHostStore.acceptHostConnection(invitee.liveID, null)
|
|
474
|
+
val directPKConfig = BattleConfig(
|
|
475
|
+
duration = 30,
|
|
476
|
+
needResponse = false,
|
|
477
|
+
extensionInfo = ""
|
|
478
|
+
)
|
|
479
|
+
battleStore.requestBattle(
|
|
480
|
+
directPKConfig,
|
|
481
|
+
listOf(invitee.userID),
|
|
482
|
+
timeout = 0,
|
|
483
|
+
completion = null
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
#### Step 4: Enter PK State
|
|
490
|
+
|
|
491
|
+
This step is the same as [Enter PK State](https://write.woa.com/#166c6a33-f068-4501-898a-6ef07c9b9b21).
|
|
492
|
+
|
|
493
|
+
## PK Score Update and Win/Loss Determination
|
|
494
|
+
|
|
495
|
+
### Updating PK Score via REST API
|
|
496
|
+
|
|
497
|
+
In typical** live host PK scenarios,** the value of gifts received by the host is linked to the PK score (for example, when a viewer sends a "Rocket" gift, the host's PK score increases by 500 points). You can implement real-time PK score updates using our REST API.
|
|
498
|
+
|
|
499
|
+
> **Note:**
|
|
500
|
+
>
|
|
501
|
+
|
|
502
|
+
> The PK score system in the LiveKit backend uses pure numeric calculation and accumulation. You must calculate the PK score according to your own business logic before calling the update API. See the following PK score calculation examples:
|
|
503
|
+
>
|
|
504
|
+
<table>
|
|
505
|
+
<tr>
|
|
506
|
+
<td rowspan="1" colSpan="1" >Gift Type</td>
|
|
507
|
+
|
|
508
|
+
<td rowspan="1" colSpan="1" >Score Calculation Rule</td>
|
|
509
|
+
|
|
510
|
+
<td rowspan="1" colSpan="1" >Example</td>
|
|
511
|
+
</tr>
|
|
512
|
+
|
|
513
|
+
<tr>
|
|
514
|
+
<td rowspan="1" colSpan="1" >Basic Gift</td>
|
|
515
|
+
|
|
516
|
+
<td rowspan="1" colSpan="1" >Gift value × 5</td>
|
|
517
|
+
|
|
518
|
+
<td rowspan="1" colSpan="1" >10 RMB gift → 50 points</td>
|
|
519
|
+
</tr>
|
|
520
|
+
|
|
521
|
+
<tr>
|
|
522
|
+
<td rowspan="1" colSpan="1" >Intermediate Gift</td>
|
|
523
|
+
|
|
524
|
+
<td rowspan="1" colSpan="1" >Gift value × 8</td>
|
|
525
|
+
|
|
526
|
+
<td rowspan="1" colSpan="1" >50 RMB gift → 400 points</td>
|
|
527
|
+
</tr>
|
|
528
|
+
|
|
529
|
+
<tr>
|
|
530
|
+
<td rowspan="1" colSpan="1" >Advanced Gift</td>
|
|
531
|
+
|
|
532
|
+
<td rowspan="1" colSpan="1" >Gift value × 12</td>
|
|
533
|
+
|
|
534
|
+
<td rowspan="1" colSpan="1" >100 RMB gift → 1200 points</td>
|
|
535
|
+
</tr>
|
|
536
|
+
|
|
537
|
+
<tr>
|
|
538
|
+
<td rowspan="1" colSpan="1" >Special Effect Gift</td>
|
|
539
|
+
|
|
540
|
+
<td rowspan="1" colSpan="1" >Fixed high score</td>
|
|
541
|
+
|
|
542
|
+
<td rowspan="1" colSpan="1" >520 RMB gift → 1314 points</td>
|
|
543
|
+
</tr>
|
|
544
|
+
</table>
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
|
|
548
|
+
#### REST API Call Flow
|
|
549
|
+
|
|
550
|
+

|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
#### Key Process Description
|
|
554
|
+
1. **Obtain PK Status:**
|
|
555
|
+
|
|
556
|
+
- **Callback Configuration**: Configure [PK Status Callback](https://write.woa.com/document/170203265552953344) to have the LiveKit backend actively notify your system when PK starts or ends.
|
|
557
|
+
|
|
558
|
+
- **Active Query**: Your backend can call the [PK Status Query](https://write.woa.com/document/170220847572692992) API at any time to check the current PK status.
|
|
559
|
+
|
|
560
|
+
2. **PK Score Calculation**: Your backend calculates the PK score increment based on your business rules.
|
|
561
|
+
|
|
562
|
+
3. **PK Score Update**: Your backend calls the [Update PK Score](https://write.woa.com/document/170220034100383744) API to update the PK score in the LiveKit backend.
|
|
563
|
+
|
|
564
|
+
4. **LiveKit Backend Syncs to Client**: The backend automatically synchronizes the updated PK score to all clients.
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
#### Involved REST API Endpoints
|
|
568
|
+
<table>
|
|
569
|
+
<tr>
|
|
570
|
+
<td rowspan="1" colSpan="1" >**API**</td>
|
|
571
|
+
|
|
572
|
+
<td rowspan="1" colSpan="1" >**Function Description**</td>
|
|
573
|
+
|
|
574
|
+
<td rowspan="1" colSpan="1" >**Request Example**</td>
|
|
575
|
+
</tr>
|
|
576
|
+
|
|
577
|
+
<tr>
|
|
578
|
+
<td rowspan="1" colSpan="1" >Active API - Query PK Status</td>
|
|
579
|
+
|
|
580
|
+
<td rowspan="1" colSpan="1" >Check whether the current room is in PK</td>
|
|
581
|
+
|
|
582
|
+
<td rowspan="1" colSpan="1" >[Example](https://write.woa.com/document/170220847572692992)</td>
|
|
583
|
+
</tr>
|
|
584
|
+
|
|
585
|
+
<tr>
|
|
586
|
+
<td rowspan="1" colSpan="1" >Active API - Update PK Score</td>
|
|
587
|
+
|
|
588
|
+
<td rowspan="1" colSpan="1" >Update the calculated PK score</td>
|
|
589
|
+
|
|
590
|
+
<td rowspan="1" colSpan="1" >[Example](https://write.woa.com/document/170220034100383744)</td>
|
|
591
|
+
</tr>
|
|
592
|
+
|
|
593
|
+
<tr>
|
|
594
|
+
<td rowspan="1" colSpan="1" >Callback Configuration - PK Start Callback</td>
|
|
595
|
+
|
|
596
|
+
<td rowspan="1" colSpan="1" >Receive real-time notification when PK starts</td>
|
|
597
|
+
|
|
598
|
+
<td rowspan="1" colSpan="1" >[Example](https://write.woa.com/document/170203265552953344)</td>
|
|
599
|
+
</tr>
|
|
600
|
+
|
|
601
|
+
<tr>
|
|
602
|
+
<td rowspan="1" colSpan="1" >Callback Configuration - PK End Callback</td>
|
|
603
|
+
|
|
604
|
+
<td rowspan="1" colSpan="1" >Receive real-time notification when PK ends</td>
|
|
605
|
+
|
|
606
|
+
<td rowspan="1" colSpan="1" >[Example](https://write.woa.com/document/170221608179601408)</td>
|
|
607
|
+
</tr>
|
|
608
|
+
</table>
|
|
609
|
+
|
|
610
|
+
|
|
611
|
+
### Winner Determination
|
|
612
|
+
|
|
613
|
+
In PK scenarios, scores are typically based on gifts received, driving competition and engagement. The PK module in RoomEngine supports score updates and broadcasts. Link your gift logic to this system.
|
|
614
|
+
|
|
615
|
+

|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
When your billing system confirms a gift transaction, call the [Modify PK Score](https://write.woa.com/document/170220034100383744) to update the host's PK score. All users in PK rooms see the updated `battleScore` in `BattleState`. Update your PK progress bar whenever `battleScore` changes.
|
|
619
|
+
``` java
|
|
620
|
+
private fun observeBattleScore() {
|
|
621
|
+
val job = lifecycleScope.launch {
|
|
622
|
+
battleStore?.battleState?.battleScore?.collect { battleScore ->
|
|
623
|
+
// Update PK progress bar here
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
collectJobs.add(job)
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
## API Documentation
|
|
631
|
+
|
|
632
|
+
For details on all public interfaces, properties, and methods for CoHostStore, BattleStore, LiveListStore, LiveSeatStore, and related classes, see the [AtomicXCore API documentation](https://tencent-rtc.github.io/TUIKit_iOS/documentation/atomicxcore).
|
|
633
|
+
<table>
|
|
634
|
+
<tr>
|
|
635
|
+
<td rowspan="1" colSpan="1" >**Store/Component**</td>
|
|
636
|
+
|
|
637
|
+
<td rowspan="1" colSpan="1" >**Function Description**</td>
|
|
638
|
+
|
|
639
|
+
<td rowspan="1" colSpan="1" >**API Documentation**</td>
|
|
640
|
+
</tr>
|
|
641
|
+
|
|
642
|
+
<tr>
|
|
643
|
+
<td rowspan="1" colSpan="1" >CoHostStore</td>
|
|
644
|
+
|
|
645
|
+
<td rowspan="1" colSpan="1" >Host Connection Lifecycle Management: Responsible for managing and coordinating the lifecycle of anchor connections, including initiating connection invitations, handling acceptance/rejection, switching connection status, managing video streams during connections, and disconnecting connections.</td>
|
|
646
|
+
|
|
647
|
+
<td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.live/-co-host-store/index.html)</td>
|
|
648
|
+
</tr>
|
|
649
|
+
|
|
650
|
+
<tr>
|
|
651
|
+
<td rowspan="1" colSpan="1" >BattleStore</td>
|
|
652
|
+
|
|
653
|
+
<td rowspan="1" colSpan="1" >Streamer PK Battle Lifecycle Management: Responsible for managing the entire lifecycle of timed PK battles between streamers, including initiating PK invitations, starting the battle, updating PK scores in real time, settling the winner at the end of the PK, and penalty time.</td>
|
|
654
|
+
|
|
655
|
+
<td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.live/-battle-store/index.html)</td>
|
|
656
|
+
</tr>
|
|
657
|
+
|
|
658
|
+
<tr>
|
|
659
|
+
<td rowspan="1" colSpan="1" >LiveListStore</td>
|
|
660
|
+
|
|
661
|
+
<td rowspan="1" colSpan="1" >Manages live room lifecycle: query room list, modify live info, etc.</td>
|
|
662
|
+
|
|
663
|
+
<td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.live/-live-list-store/index.html)</td>
|
|
664
|
+
</tr>
|
|
665
|
+
|
|
666
|
+
<tr>
|
|
667
|
+
<td rowspan="1" colSpan="1" >LiveSeatStore</td>
|
|
668
|
+
|
|
669
|
+
<td rowspan="1" colSpan="1" >Manages seat states within a room (including cross-room seats), tracks user seat changes, microphone status, and more.</td>
|
|
670
|
+
|
|
671
|
+
<td rowspan="1" colSpan="1" >[API Documentation](https://tencent-rtc.github.io/TUIKit_Android/-atomic-x%20-core%20-a-p-i/io.trtc.tuikit.atomicxcore.api.live/-live-seat-store/index.html)</td>
|
|
672
|
+
</tr>
|
|
673
|
+
</table>
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
## FAQs
|
|
677
|
+
|
|
678
|
+
#### What is the maximum number of rooms and users supported for connection or PK?
|
|
679
|
+
|
|
680
|
+
Up to 9 rooms can be connected simultaneously, with 50 users per room.
|
|
681
|
+
|
|
682
|
+
#### How do I implement a punishment period after PK loss?
|
|
683
|
+
|
|
684
|
+
After receiving the `onBattleEnded` callback, determine the winner using `battleScore` from `BattleState`. The connection remains active after PK. Implement a custom 30-second punishment period, then disconnect after the countdown.
|
|
685
|
+
|
|
686
|
+
#### Why did the connection invitation not reach the target host?
|
|
687
|
+
- Verify that **targetHostLiveId** is correct and the target room is actively live.
|
|
688
|
+
|
|
689
|
+
- Check network connectivity; invitation signaling has a default 30-second timeout.
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
#### What happens if a host disconnects or the app crashes during connection or PK?
|
|
693
|
+
|
|
694
|
+
CoHostStore and BattleStore have built-in heartbeat and timeout detection. If a participant exits unexpectedly, the other party is notified via events such as `onCoHostUserLeft` or `onUserExitBattle`. Use these events to update the UI (e.g., "The other party has disconnected") and end the interaction.
|
|
695
|
+
|
|
696
|
+
#### Why can PK scores only be updated via REST API?
|
|
697
|
+
|
|
698
|
+
REST API ensures PK score **security, real-time updates, and scalability**:
|
|
699
|
+
- **Tamper-proof and fair:** Requires authentication and data validation. Each update is traceable (e.g., gift action), preventing manual score changes or cheating.
|
|
700
|
+
|
|
701
|
+
- **Real-time sync:** Standardized formats (e.g., JSON) allow seamless integration with gifts, PK, and display systems, keeping scores consistent across hosts, viewers, and backend.
|
|
702
|
+
|
|
703
|
+
- **Flexible rule adaptation:** Backend configuration changes (e.g., adjusting gift score values) can be made without front-end changes, reducing iteration costs.
|