@tencent-rtc/mcp 1.3.5 → 1.3.7

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 (33) hide show
  1. package/index.js +4 -4
  2. package/index.js.map +1 -1
  3. package/package.json +1 -1
  4. package/resource/doc/livekit/live/flutter/live-audience-list.md +339 -0
  5. package/resource/doc/livekit/live/flutter/live-audio-effect.md +742 -0
  6. package/resource/doc/livekit/live/flutter/live-barrage.md +581 -0
  7. package/resource/doc/livekit/live/flutter/live-base-beauty.md +486 -0
  8. package/resource/doc/livekit/live/flutter/live-co-guest-interaction.md +608 -0
  9. package/resource/doc/livekit/live/flutter/live-gift.md +800 -0
  10. package/resource/doc/livekit/live/flutter/live-host-interaction.md +1113 -0
  11. package/resource/doc/livekit/live/flutter/live-integration.md +1041 -0
  12. package/resource/doc/livekit/live/flutter/live-live-list.md +865 -0
  13. package/resource/doc/livekit/live/flutter/workflow.md +353 -0
  14. package/resource/doc/tuicallkit/flutter/workflow.md +331 -0
  15. package/tools/call/get-native-call-integration.js +27 -11
  16. package/tools/call/get-native-call-integration.js.map +1 -1
  17. package/tools/definitions/get_native_call_uikit_integration_def.js +17 -7
  18. package/tools/definitions/get_native_call_uikit_integration_def.js.map +1 -1
  19. package/utils/report-cls-client.js +1 -1
  20. package/utils/report-es-client.js +1 -1
  21. package/resource/doc/tuicallkit/flutter/how_to_run_flutter_callkit_demo.md +0 -101
  22. package/resource/doc/tuicallkit/iOS/how_to_run_iOS_callkit_demo.md +0 -98
  23. /package/resource/doc/tuicallkit/android/{how_to_integrated_android_callkit.md → integration.md} +0 -0
  24. /package/resource/doc/tuicallkit/android/{.gitkeep → workflow.md} +0 -0
  25. /package/resource/doc/tuicallkit/{android/api_TUICallObserver.md → faq/android_sdk/call-observer-api.md} +0 -0
  26. /package/resource/doc/tuicallkit/{android/api_TUICallKit.md → faq/android_sdk/callkit-api.md} +0 -0
  27. /package/resource/doc/tuicallkit/{flutter/api_TUICallDefine.md → faq/flutter_sdk/call-define-api.md} +0 -0
  28. /package/resource/doc/tuicallkit/{flutter/api_TUICallObserver.md → faq/flutter_sdk/call-observer-api.md} +0 -0
  29. /package/resource/doc/tuicallkit/{flutter/api_TUICallKit.md → faq/flutter_sdk/callkit-api.md} +0 -0
  30. /package/resource/doc/tuicallkit/{iOS/api_TUICallObserver.md → faq/ios_sdk/call-observer-api.md} +0 -0
  31. /package/resource/doc/tuicallkit/{iOS/api_TUICallKit.md → faq/ios_sdk/callkit-api.md} +0 -0
  32. /package/resource/doc/tuicallkit/flutter/{how_to_integrated_flutter_callkit.md → integration.md} +0 -0
  33. /package/resource/doc/tuicallkit/iOS/{how_to_integrated_iOS_callkit.md → integration.md} +0 -0
@@ -0,0 +1,581 @@
1
+ This document aims to guide Flutter developers on how to use the `BarrageStore` module in the `AtomicXCore` framework to quickly integrate a bullet screen system with various features and outstanding performance for your live stream app.
2
+
3
+ ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100032457995/e62bfa87f76211f0822d525400074c32.png)
4
+
5
+
6
+ ## Core Features
7
+
8
+ `BarrageStore` provides a complete bullet screen solution for your live stream app. Core features include:
9
+ - Receive and show danmakus information in live rooms.
10
+
11
+ - Send text bullet screen for audience interaction.
12
+
13
+ - Send custom business bullet screen to support complex scenarios such as gift and likes.
14
+
15
+ - Insert a system prompt in the local message list (for example, "Welcome XX to enter live room").
16
+
17
+
18
+ ## Core Concept Analysis
19
+ <table>
20
+ <tr>
21
+ <td rowspan="1" colSpan="1" >**Core Concept**</td>
22
+
23
+ <td rowspan="1" colSpan="1" >**Type**</td>
24
+
25
+ <td rowspan="1" colSpan="1" >**Core Responsibility and Description**</td>
26
+ </tr>
27
+
28
+ <tr>
29
+ <td rowspan="1" colSpan="1" >[Barrage](https://tencent-rtc.github.io/TUIKit_Flutter/api_barrage_barrage_store/Barrage-class.html)</td>
30
+
31
+ <td rowspan="1" colSpan="1" >`class`</td>
32
+
33
+ <td rowspan="1" colSpan="1" >Represents a data model for a Danmu Message. It contains all key information such as sender information (`sender`), message content (`textContent` or `data`), and message type (`messageType`).</td>
34
+ </tr>
35
+
36
+ <tr>
37
+ <td rowspan="1" colSpan="1" >[BarrageState](https://tencent-rtc.github.io/TUIKit_Flutter/api_barrage_barrage_store/BarrageState-class.html)</td>
38
+
39
+ <td rowspan="1" colSpan="1" >`class`</td>
40
+
41
+ <td rowspan="1" colSpan="1" >Represents the current status of the bullet screen module. Its core attribute `messageList` is a `ValueListenable<List<Barrage>>`, storing all Danmu messages in the live streaming room in chronological order, serving as the data source for UI rendering.</td>
42
+ </tr>
43
+
44
+ <tr>
45
+ <td rowspan="1" colSpan="1" >[BarrageStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_barrage_barrage_store/BarrageStore-class.html)</td>
46
+
47
+ <td rowspan="1" colSpan="1" >`class`</td>
48
+
49
+ <td rowspan="1" colSpan="1" >This is the core management class for danmu function interaction. Through it, you can send messages (`sendTextMessage`, `sendCustomMessage`) and receive and listen to ALL Danmu Message updates by listening to its `barrageState.messageList` property.</td>
50
+ </tr>
51
+ </table>
52
+
53
+
54
+ ## Implementation Steps
55
+
56
+ ### Step 1: Integrating the Component
57
+ - **Live streaming**: Refer to [quick integration](https://write.woa.com/document/200455640177692672) for seamless integration with **AtomicXCore** and service access.
58
+
59
+ - **Voice chat room**: Refer to [quick integration](https://write.woa.com/document/200555778169073664) for seamless integration with **AtomicXCore** and service access.
60
+
61
+
62
+ Return to the current project after integration.
63
+
64
+
65
+ ### Step 2: Initialize and Listen to the Bullet Screen
66
+
67
+ Retrieve a `BarrageStore` instance bound to the current live streaming room `liveId`, and set a listener to receive the latest **Full** barrage message list in real time.
68
+ ``` java
69
+ import 'package:flutter/foundation.dart';
70
+ import 'package:atomic_x_core/atomicxcore.dart';
71
+
72
+ class BarrageManager {
73
+ final String liveId;
74
+ late final BarrageStore barrageStore;
75
+ late final VoidCallback _messageListChangedListener = _onMessageListChanged;
76
+
77
+ // Expose message list change notification to the public
78
+ final ValueNotifier<List<Barrage>> messagesNotifier =
79
+ ValueNotifier<List<Barrage>>([]);
80
+
81
+ BarrageManager({required this.liveId}) {
82
+ // 1. Get the singleton of BarrageStore by liveId (location parameter)
83
+ barrageStore = BarrageStore.create(liveId);
84
+
85
+ // 2. Start listening to the bullet screen immediately after initialization
86
+ _subscribeToBarrageUpdates();
87
+ }
88
+
89
+ void _subscribeToBarrageUpdates() {
90
+ // 3. Use ValueListenable's addListener to listen for messages list adjustment
91
+ barrageStore.barrageState.messageList.addListener(_messageListChangedListener);
92
+ }
93
+
94
+ void _onMessageListChanged() {
95
+ // 4. When the messageList is updating, get the new list and notify the UI layer
96
+ // Key point: The complete list obtained here contains ALL historical messages
97
+ messagesNotifier.value = barrageStore.barrageState.messageList.value;
98
+ }
99
+
100
+ void dispose() {
101
+ barrageStore.barrageState.messageList.removeListener(_messageListChangedListener);
102
+ messagesNotifier.dispose();
103
+ }
104
+ }
105
+ ```
106
+
107
+ ### Step 3: Send Text Bullet Screen
108
+
109
+ Call the `sendTextMessage` method to broadcast a text message to all users in the live streaming room.
110
+ ``` java
111
+ extension BarrageManagerSend on BarrageManager {
112
+ Send a text bullet screen
113
+ Future<void> sendTextMessage(String text) async {
114
+ // Recommendation: Add non-null verification to avoid sending invalid messages.
115
+ if (text.isEmpty) {
116
+ debugPrint("Bullet screen content cannot be empty");
117
+ return;
118
+ }
119
+
120
+ // Call the core API to sendMessage
121
+ final result = await barrageStore.sendTextMessage(
122
+ text: text,
123
+ extensionInfo: null,
124
+ );
125
+
126
+ // Use isSuccess to check the result
127
+ if (result.isSuccess) {
128
+ debugPrint("Bullet screen text '$text' sent successfully");
129
+ } else {
130
+ debugPrint("Bullet screen text sending failure: ${result.errorMessage}");
131
+ }
132
+ }
133
+ }
134
+ ```
135
+
136
+ **API parameter:**
137
+ <table>
138
+ <tr>
139
+ <td rowspan="1" colSpan="1" >**Parameter**</td>
140
+
141
+ <td rowspan="1" colSpan="1" >**Type**</td>
142
+
143
+ <td rowspan="1" colSpan="1" >**Description**</td>
144
+ </tr>
145
+
146
+ <tr>
147
+ <td rowspan="1" colSpan="1" >`text`</td>
148
+
149
+ <td rowspan="1" colSpan="1" >`String`</td>
150
+
151
+ <td rowspan="1" colSpan="1" >The text content to be sent.</td>
152
+ </tr>
153
+
154
+ <tr>
155
+ <td rowspan="1" colSpan="1" >`extensionInfo`</td>
156
+
157
+ <td rowspan="1" colSpan="1" >`Map<String, String>?`</td>
158
+
159
+ <td rowspan="1" colSpan="1" >Attach extra extended information applicable to business customization.</td>
160
+ </tr>
161
+ </table>
162
+
163
+
164
+ ### Step 4: Send Custom Barrage Item
165
+
166
+ Send a message containing custom business logic, such as gift, like or gaming interaction command. This message is transparent to other clients and requires the business layer to parse.
167
+ ``` java
168
+ import 'dart:convert';
169
+
170
+ extension BarrageManagerCustom on BarrageManager {
171
+ /// Send a custom barrage item, for example for sending a gift
172
+ Future<void> sendGiftMessage({
173
+ required String giftId,
174
+ required int giftCount,
175
+ }) async {
176
+ // 1. Define a business ID
177
+ const businessID = "live_gift";
178
+
179
+ // 2. Encode business data as a JSON string
180
+ final giftData = {"gift_id": giftId, "gift_count": giftCount};
181
+ final jsonString = jsonEncode(giftData);
182
+
183
+ // 3. Call the core API to send custom messages
184
+ final result = await barrageStore.sendCustomMessage(
185
+ businessID: businessID,
186
+ data: jsonString,
187
+ );
188
+
189
+ if (result.isSuccess) {
190
+ debugPrint("Gift message (custom barrage item) sent successfully");
191
+ } else {
192
+ debugPrint("Gift message send fail: ${result.errorMessage}");
193
+ }
194
+ }
195
+ }
196
+ ```
197
+
198
+ **API parameter:**
199
+ <table>
200
+ <tr>
201
+ <td rowspan="1" colSpan="1" >**Parameter**</td>
202
+
203
+ <td rowspan="1" colSpan="1" >**Type**</td>
204
+
205
+ <td rowspan="1" colSpan="1" >**Description**</td>
206
+ </tr>
207
+
208
+ <tr>
209
+ <td rowspan="1" colSpan="1" >`businessID`</td>
210
+
211
+ <td rowspan="1" colSpan="1" >`String`</td>
212
+
213
+ <td rowspan="1" colSpan="1" >Business unique identifier, such as "live_gift", used for recipient to distinguish different custom messages.</td>
214
+ </tr>
215
+
216
+ <tr>
217
+ <td rowspan="1" colSpan="1" >`data`</td>
218
+
219
+ <td rowspan="1" colSpan="1" >`String`</td>
220
+
221
+ <td rowspan="1" colSpan="1" >Business data, typically strings in JSON format.</td>
222
+ </tr>
223
+ </table>
224
+
225
+
226
+ ### Step 5: Insert Prompt Message Locally
227
+
228
+ Insert a local message into the current user's message list. This message will not be sent to other users in the live streaming room. It is suitable for displaying system welcome, warning or operation prompt information.
229
+ ``` java
230
+ extension BarrageManagerLocal on BarrageManager {
231
+ Insert a welcome notification into the local message list
232
+ void showWelcomeMessage(LiveUserInfo user) {
233
+ // 1. Create a Barrage message (using named parameters construct function)
234
+ final welcomeTip = Barrage(
235
+ messageType: BarrageType.text,
236
+ Welcome ${user.userName} to the live room.
237
+ );
238
+
239
+ // 2. Call API to insert it into the local list
240
+ barrageStore.appendLocalTip(welcomeTip);
241
+ }
242
+ }
243
+ ```
244
+
245
+ ### Step 6: Manage User Speaking (Mute and Unblock)
246
+
247
+ As an Anchor or admin, you can manage the user speaking permission in the live streaming room to maintain a healthy communication environment.
248
+
249
+ #### Forbid/Unblock Single-User Speaking
250
+
251
+ Mute or unblock designated users can be achieved by the `disableSendMessage` API in `LiveAudienceStore`.
252
+ ``` java
253
+ // 1. Get the LiveAudienceStore instance bound to the current live streaming room (location parameter)
254
+ final liveId = "your_live_id";
255
+ final audienceStore = LiveAudienceStore.create(liveId);
256
+
257
+ // 2. Define the operating user ID and mute status
258
+ final userIdToMute = "user_id_to_be_muted";
259
+ final shouldDisable = true; // true for mute, false for unblock
260
+
261
+ // 3. Call API to perform operation
262
+ final result = await audienceStore.disableSendMessage(
263
+ userID: userIdToMute,
264
+ isDisable: shouldDisable,
265
+ );
266
+
267
+ if (result.isSuccess) {
268
+ debugPrint("${shouldDisable ? "mute" : "unblock"} user $userIdToMute successfully");
269
+ } else {
270
+ debugPrint("Operation failure: ${result.errorMessage}");
271
+ }
272
+ ```
273
+
274
+ #### Enable/Disable Global Mute
275
+
276
+ To mute all users in the live streaming room (normally excluding the Anchor), you need to update the live room information through `LiveListStore`.
277
+ ``` java
278
+ // 1. Get the LiveListStore singleton
279
+ final liveListStore = LiveListStore.shared;
280
+
281
+ // 2. Get the current live room information, create a new LiveInfo object, and modify the global mute status
282
+ final currentLiveInfo = liveListStore.liveState.currentLive.value;
283
+ final updatedLiveInfo = LiveInfo(
284
+ liveID: currentLiveInfo.liveID,
285
+ liveName: currentLiveInfo.liveName,
286
+ isMessageDisable: true, // true for mute all, false for shutdown
287
+ );
288
+
289
+ // 3. Call the update API and specify the modify flags list
290
+ final result = await liveListStore.updateLiveInfo(
291
+ liveInfo: updatedLiveInfo,
292
+ modifyFlagList: [ModifyFlag.isMessageDisable],
293
+ );
294
+
295
+ if (result.isSuccess) {
296
+ debugPrint("Global mute status updated successfully");
297
+ } else {
298
+ debugPrint("Operation failure: ${result.errorMessage}");
299
+ }
300
+ ```
301
+
302
+ ## Complete UI Example
303
+ ``` java
304
+ import 'package:flutter/material.dart';
305
+ import 'package:atomic_x_core/atomicxcore.dart';
306
+
307
+ class BarrageWidget extends StatefulWidget {
308
+ final String liveId;
309
+
310
+ const BarrageWidget({Key? key, required this.liveId}) : super(key: key);
311
+
312
+ @override
313
+ State<BarrageWidget> createState() => _BarrageWidgetState();
314
+ }
315
+
316
+ class _BarrageWidgetState extends State<BarrageWidget> {
317
+ late BarrageManager _barrageManager;
318
+ final TextEditingController _inputController = TextEditingController();
319
+ final ScrollController _scrollController = ScrollController();
320
+
321
+ @override
322
+ void initState() {
323
+ super.initState();
324
+ _barrageManager = BarrageManager(liveId: widget.liveId);
325
+ }
326
+
327
+ void _scrollToBottom() {
328
+ WidgetsBinding.instance.addPostFrameCallback((_) {
329
+ if (_scrollController.hasClients) {
330
+ _scrollController.animateTo(
331
+ _scrollController.position.maxScrollExtent,
332
+ duration: const Duration(milliseconds: 200),
333
+ curve: Curves.easeOut,
334
+ );
335
+ }
336
+ });
337
+ }
338
+
339
+ @override
340
+ void dispose() {
341
+ _barrageManager.dispose();
342
+ _inputController.dispose();
343
+ _scrollController.dispose();
344
+ super.dispose();
345
+ }
346
+
347
+ @override
348
+ Widget build(BuildContext context) {
349
+ return Column(
350
+ children: [
351
+ // Bullet screen list
352
+ Expanded(
353
+ child: ValueListenableBuilder<List<Barrage>>(
354
+ valueListenable: _barrageManager.messagesNotifier,
355
+ builder: (context, messageList, child) {
356
+ // Scroll to the bottom
357
+ _scrollToBottom();
358
+ return ListView.builder(
359
+ controller: _scrollController,
360
+ itemCount: messageList.length,
361
+ itemBuilder: (context, index) {
362
+ final barrage = messageList[index];
363
+ return _buildBarrageItem(barrage);
364
+ },
365
+ );
366
+ },
367
+ ),
368
+ ),
369
+ // input box
370
+ _buildInputBar(),
371
+ ],
372
+ );
373
+ }
374
+
375
+ Widget _buildBarrageItem(Barrage barrage) {
376
+ return Container(
377
+ margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
378
+ padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
379
+ decoration: BoxDecoration(
380
+ color: Colors.black54,
381
+ borderRadius: BorderRadius.circular(16),
382
+ ),
383
+ child: RichText(
384
+ text: TextSpan(
385
+ children: [
386
+ TextSpan(
387
+ text: '${barrage.sender.userName}: ',
388
+ style: const TextStyle(
389
+ color: Colors.yellow,
390
+ fontSize: 14,
391
+ fontWeight: FontWeight.bold,
392
+ ),
393
+ ),
394
+ TextSpan(
395
+ text: barrage.textContent,
396
+ style: const TextStyle(color: Colors.white, fontSize: 14),
397
+ ),
398
+ ],
399
+ ),
400
+ ),
401
+ );
402
+ }
403
+
404
+ Widget _buildInputBar() {
405
+ return Container(
406
+ padding: const EdgeInsets.all(8),
407
+ color: Colors.white,
408
+ child: Row(
409
+ children: [
410
+ Expanded(
411
+ child: TextField(
412
+ controller: _inputController,
413
+ decoration: const InputDecoration(
414
+ hintText: 'Say something...',
415
+ border: OutlineInputBorder(),
416
+ contentPadding: EdgeInsets.symmetric(horizontal: 12),
417
+ ),
418
+ onSubmitted: (_) => _sendMessage(),
419
+ ),
420
+ ),
421
+ const SizedBox(width: 8),
422
+ ElevatedButton(
423
+ onPressed: _sendMessage,
424
+ child: const Text('Send')
425
+ ),
426
+ ],
427
+ ),
428
+ );
429
+ }
430
+
431
+ void _sendMessage() {
432
+ final text = _inputController.text.trim();
433
+ if (text.isNotEmpty) {
434
+ _barrageManager.sendTextMessage(text);
435
+ _inputController.clear();
436
+ }
437
+ }
438
+ }
439
+ ```
440
+
441
+ ## Advanced Features: Optimizing Performance in High Concurrency Scenarios
442
+
443
+ After using `BarrageStore` to build the danmaku function, this chapter will guide you on how to handle more complex business scenarios, ensuring it can still provide users with a smooth and stable experience in real, complex high-concurrency live broadcasting scenarios. This chapter will focus on three core business scenarios, offering clear optimization schemes and example code.
444
+
445
+ ### Scenario One: High-Concurrency Bullet Screen Scenario
446
+
447
+ #### Scenario Description
448
+
449
+ During a popular event, a large number of audience flooded into the live streaming room, with bullet screens updating at a frequency of dozens per second.
450
+
451
+ #### **Technical Challenge**
452
+
453
+ The SDK returns the complete bullet screen list at an extremely high frequency. Each time the UI is rebuilt, the main thread will be blocked by intensive UI layout and rendering operations, causing interface lag.
454
+
455
+ #### **Optimization Scheme: **Batch Processing & Traffic Peak Shaving
456
+
457
+ Do not respond to every data update, but set a time threshold (such as 300 ms). Only when the distance from the last UI refresh exceeds this threshold, execute the next refresh operation. This reduces UI redraws from dozens per second to 3-4 per second, significantly improving smoothness.
458
+ ``` java
459
+ class BarrageUIManager {
460
+ List<Barrage>? _latestMessageList;
461
+ Timer? _refreshTimer;
462
+ final void Function(List<Barrage>) onUpdate;
463
+
464
+ BarrageUIManager({required this.onUpdate}) {
465
+ // Check whether need to refresh every 0.3 seconds
466
+ _refreshTimer = Timer.periodic(
467
+ const Duration(milliseconds: 300),
468
+ (_) => _refreshUIIfNeeded(),
469
+ );
470
+ }
471
+
472
+ /// This method is frequently invoked externally with the latest full list
473
+ void update(List<Barrage> fullList) {
474
+ _latestMessageList = fullList;
475
+ }
476
+
477
+ void _refreshUIIfNeeded() {
478
+ // Check whether there is new data pending refresh
479
+ final newList = _latestMessageList;
480
+ if (newList == null) return;
481
+
482
+ _latestMessageList = null; // Clear flags to avoid repeated refresh
483
+
484
+ // Update data source and refresh UI
485
+ onUpdate(newList);
486
+ }
487
+
488
+ void dispose() {
489
+ _refreshTimer?.cancel();
490
+ }
491
+ }
492
+ ```
493
+
494
+ ### Scenario 2: Guarantee Memory Stability for Long-Term Live Stream
495
+
496
+ #### Scenario Description
497
+
498
+ Your application requires support for uninterrupted live streaming lasting several hours or even around the clock, such as game live broadcast or slow live streaming. During this period, the App must maintain stable operation and cannot exit unexpectedly due to long-running.
499
+
500
+ #### Technical Challenge
501
+
502
+ The full `messageList` returned by the SDK will grow infinitely during long-term live streams. Even if the UI layer implements traffic throttling, the huge array held by the data layer will continue to occupy memory, eventually causing the app to crash.
503
+
504
+ #### **Optimization Scheme**: Fixed Capacity Circular Buffer
505
+
506
+ **Only let your own data source (DataSource) hold a finite number of messages**. Regardless of how large the full list returned by the SDK is, your application only takes the latest part for display.
507
+ ``` java
508
+ void _refreshUIIfNeeded() {
509
+ final fullList = _latestMessageList;
510
+ if (fullList == null) return;
511
+
512
+ _latestMessageList = null;
513
+
514
+ // Key point: Take the latest N messages
515
+ const capacity = 500; // The client keeps the latest 500 messages only
516
+ final cappedList = fullList.length > capacity
517
+ ? fullList.sublist(fullList.length - capacity)
518
+ : fullList;
519
+
520
+ onUpdate(cappedList);
521
+ }
522
+ ```
523
+
524
+ ## API documentation
525
+
526
+ For detailed information about ALL public interfaces, attributes, and methods of [BarrageStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_barrage_barrage_store/BarrageStore-class.html) and its related classes, see the official API documentation included with the [AtomicXCore](https://tencent-rtc.github.io/TUIKit_Flutter/index.html) framework.
527
+
528
+ ## FAQs
529
+
530
+ ### How to Achieve Various Bullet Screen Styles Such As Color Bullet Screen and Gift Bullet Screen
531
+
532
+ This is actually achieved by the custom message `sendCustomMessage`. `BarrageStore` does not limit your business imagination.
533
+
534
+ **Implementation Approach**
535
+ 1. **Define data structure:** Work with your client and server team to define the JSON structure of custom messages. For example, a color bullet screen can be defined as follows:
536
+
537
+ ``` json
538
+ { "type": "colored_text", "text": "This is a color bullet screen!", "color": "#FF5733" }
539
+ ```
540
+ 2. **Sender:** During sending, convert this JSON structure to a string and send it via the `data` parameter of `sendCustomMessage`. `businessId` can be set to a unique identifier representing your business, such as "`barrage_style_v1`".
541
+
542
+ 3. **Receiver**: After receiving the Danmu Message, check whether its `messageType` is `.custom` and whether `businessId` matches. If matched, parse the `data` string (usually parsing JSON), and render your custom UI style based on the parsed data (such as `color, text`).
543
+
544
+
545
+ ### Different Classes and Files Call `BarrageStore.create("some_id")`. Will This Create Multiple Instances and Cause Chaos?
546
+
547
+ No worries at all. `AtomicXCore`'s internal mechanism will underwrite that as long as the `liveId` passed in is identical, the `BarrageStore` instance obtained will always be the same one bound to the live streaming room. You can use it wherever required without manually managing the singleton.
548
+
549
+ ### Why Call SendTextMessage but Can'T See Messages Sent in the Message List?
550
+
551
+ **Take the following steps to troubleshoot:**
552
+ 1. **Check returned results**: The `sendTextMessage` method has a complete callback. Please check if the callback returned a successful status or failure. If unsuccessful, the error information will specify the issue (such as "You are muted", "network error").
553
+
554
+ 2. **Confirm the timing of listening**: Underwrite your `barrageStore.state` subscription occurs after the `liveId` live stream starts. If you start listening before joining the live streaming room, you may miss some messages.
555
+
556
+ 3. **Check liveId**: Confirm the `liveId` used when creating the `BarrageStore` instance, joining the live streaming room, and sending messages is the same, including case sensitivity.
557
+
558
+ 4. **Network issue**: Check whether the current network connection of the device is normal. Sending messages depends on the network.
559
+
560
+
561
+ ### How to Show New Audience the History Danmu Messages When They Enter the Live Room
562
+
563
+ `AtomicXCore` supports pulling history Danmu Messages, but this requires you to perform one simple configuration in the **server console**. Once configured, the SDK will automatically handle everything subsequently with no need to write additional code.
564
+
565
+ #### **Procedure 1: Perform Configuration in the Live Console**
566
+ 1. Log in to the [**console > Live > Configuration**](https://console.trtc.io/live/configuration), and select the target application at the **top**.
567
+
568
+ 2. On the Live configuration page, select **new member pull historical messages**, modify **new member viewable latest message count**, supports a maximum of **50**.
569
+
570
+ ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100032457995/f7e29319f76211f0831c52540073fd3b.png)
571
+
572
+
573
+ **Step 2: Client Seamless Retrieval**
574
+
575
+
576
+ After completing the above configuration, your client-side code **requires no modification**.
577
+
578
+
579
+ When a new user joins the live room, the `AtomicXCore` underlying layer will automatically pull your configuration history message count. These historical messages will be pushed to your UI layer through your realized `BarrageStore.barrageState` subscription channel, just like real-time messages. Your application will naturally receive and show these historical bullet screens, same as receiving real-time bullet screens.
580
+
581
+