@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,742 @@
1
+ This document aims to guide you on how to use the `AtomicXCore` framework's `AudioEffectStore` and `DeviceStore` modules to quickly integrate audio effect control features for your live stream app, including Microphone Volume, listen, and add multiple fun voice-changing effects and reverb effects.
2
+
3
+ ![](https://write-document-release-1258344699.cos.ap-guangzhou.tencentcos.cn/100032457995/5a187583f76311f0859b52540097cba1.png)
4
+
5
+
6
+ ## Core Features
7
+
8
+ By combining `AudioEffectStore` and `DeviceStore`, you can implement the following core features:
9
+ - **Vocal Volume Adjustment**: Controls the capturing volume of Local Audio Uplink, which determines the Anchor's sound level heard by the audience.
10
+
11
+ - **Ear monitoring function**: Allows the Anchor or co-streaming users to hear their own sound in real-time through headphones for listening and pronunciation correction.
12
+
13
+ - **Voice-changing effects**: Offers multiple fun voice changing options, such as lolita, uncle, and mischievous child.
14
+
15
+ - **Reverb effect**: Simulates sound field effects in different environments, such as KTV, metallic sound, deep, and resonant.
16
+
17
+
18
+ ## Conceptual Introduction
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 Responsibilities and Description**</td>
26
+ </tr>
27
+
28
+ <tr>
29
+ <td rowspan="1" colSpan="1" >[AudioEffectState](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_audio_effect_store/AudioEffectState-class.html)</td>
30
+
31
+ <td rowspan="1" colSpan="1" >`class`</td>
32
+
33
+ <td rowspan="1" colSpan="1" >Represents the current status of the audio effect module, usually used for UI rendering. Includes voice-changing status, reverberation status, ear return enabled status, ear return volume. All attributes are `ValueListenable` data type, support subscription listen.</td>
34
+ </tr>
35
+
36
+ <tr>
37
+ <td rowspan="1" colSpan="1" >[AudioEffectStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_audio_effect_store/AudioEffectStore-class.html)</td>
38
+
39
+ <td rowspan="1" colSpan="1" >`class`</td>
40
+
41
+ <td rowspan="1" colSpan="1" >Represents the **singleton data management class** of the audio effect module. Through it you can call the audio effect API to modify sound effects. When you call the API, the appropriate `audioEffectState` property will auto-update. You can subscribe to this state's responsive data to receive and listen for status updates.</td>
42
+ </tr>
43
+
44
+ <tr>
45
+ <td rowspan="1" colSpan="1" >[DeviceState](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_device_store/DeviceState-class.html)</td>
46
+
47
+ <td rowspan="1" colSpan="1" >`class`</td>
48
+
49
+ <td rowspan="1" colSpan="1" >Represents the current status of the device module, usually used for UI rendering. Core attributes include device status of camera, microphone, capturing volume. All attributes are `ValueListenable` data type, support subscription listen.</td>
50
+ </tr>
51
+
52
+ <tr>
53
+ <td rowspan="1" colSpan="1" >[DeviceStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_device_store/DeviceStore-class.html)</td>
54
+
55
+ <td rowspan="1" colSpan="1" >`class`</td>
56
+
57
+ <td rowspan="1" colSpan="1" >Represents the **singleton data management class** of the device module. Through it you can call the API to operate camera and microphone. When you call the API, the appropriate `state` property will auto-update. You can subscribe to this state's responsive data to receive and listen for status updates.</td>
58
+ </tr>
59
+ </table>
60
+
61
+
62
+ ## Implementation Steps
63
+
64
+ ### Step 1: Integrating the Component
65
+ - **Live streaming**: Refer to [quick integration](https://write.woa.com/document/200455640177692672) to integrate **AtomicXCore** and complete service access.
66
+
67
+ - **Voice chat room**: Refer to [quick integration](https://write.woa.com/document/200555778169073664) to integrate **AtomicXCore** and complete service access.
68
+
69
+
70
+ ### Step 2: Obtain a Store Instance
71
+
72
+ `AudioEffectStore` and `DeviceStore` are singleton objects. You can directly get instance via the `shared` property in any location in the project. You can also refer to the [audio_effect_panel_widget.dart](https://github.com/Tencent-RTC/TUIKit_Flutter/blob/main/live/livekit/lib/component/audio_effect/audio_effect_panel_widget.dart) file in the TUILiveKit open-source UI demo project to learn about the complete implementation logic.
73
+ ``` java
74
+ import 'package:flutter/material.dart';
75
+ import 'package:atomic_x_core/atomicxcore.dart';
76
+
77
+ class _AudioEffectPanelWidgetState {
78
+ final _audioEffectStore = AudioEffectStore.shared;
79
+ final _deviceStore = DeviceStore.shared;
80
+ }
81
+ ```
82
+
83
+ ### Step 3: Implement the In-Ear Monitoring Feature
84
+
85
+ Ear monitoring function allows users to monitor their own microphone sound in real time. Calling the API introduced in this section can manage the ear monitoring function.
86
+
87
+ > **Note:**
88
+ >
89
+
90
+ > The in-ear monitoring feature typically needs to connect to headphones to work properly.
91
+ >
92
+
93
+
94
+ #### Implementation Method
95
+ 1. **Enable/Disable Ear Monitoring**: You can use the `Switch` control to implement the ear monitoring function.
96
+
97
+ 2. **Set the Volume of IEMs**: You can use the `Slider` control to implement the function of dragging the slider left and right to adjust volume, and map the `Slider` value to the volume value, then call `setVoiceEarMonitorVolume(volume)`. Please note, this API accepts a parameter range of `[0, 150]`, so you need to map the UI control value (such as the Slider's `0.0 - 1.0`) to the `0 - 150` range.
98
+
99
+ 3. **Listen for Status Updates to Update UI**: You can subscribe to real-time ear monitoring status value updates to refresh the UI.
100
+
101
+
102
+ #### Sample Code
103
+ ``` java
104
+ import 'package:flutter/material.dart';
105
+ import 'package:atomic_x_core/atomicxcore.dart';
106
+
107
+ /// Ear Monitoring Control Component
108
+ class EarMonitorWidget extends StatelessWidget {
109
+ const EarMonitorWidget({super.key});
110
+
111
+ @override
112
+ Widget build(BuildContext context) {
113
+ final audioEffectStore = AudioEffectStore.shared;
114
+
115
+ return Column(
116
+ crossAxisAlignment: CrossAxisAlignment.start,
117
+ children: [
118
+ // 1. Toggle ear monitoring
119
+ ValueListenableBuilder<bool>(
120
+ valueListenable: audioEffectStore.audioEffectState.isEarMonitorOpened,
121
+ builder: (context, isOpened, child) {
122
+ return SwitchListTile(
123
+ title: const Text('Ear Monitoring'),
124
+ subtitle: const Text('Insert a headset')
125
+ value: isOpened,
126
+ onChanged: (value) {
127
+ audioEffectStore.setVoiceEarMonitorEnable(value);
128
+ },
129
+ );
130
+ },
131
+ ),
132
+ // 2. Adjust ear return volume
133
+ ValueListenableBuilder<int>(
134
+ valueListenable: audioEffectStore.audioEffectState.earMonitorVolume,
135
+ builder: (context, volume, child) {
136
+ return ListTile(
137
+ title: const Text('Ear Monitoring Volume'),
138
+ subtitle: Slider(
139
+ value: volume.toDouble(),
140
+ min: 0,
141
+ max: 150,
142
+ divisions: 150,
143
+ onChanged: (value) {
144
+ audioEffectStore.setVoiceEarMonitorVolume(value.toInt());
145
+ },
146
+ ),
147
+ trailing: Text('$volume'),
148
+ );
149
+ },
150
+ ),
151
+ ],
152
+ );
153
+ }
154
+ }
155
+ ```
156
+
157
+ #### SetVoiceEarMonitorEnable API Parameter
158
+ <table>
159
+ <tr>
160
+ <td rowspan="1" colSpan="1" >**Parameter Name**</td>
161
+
162
+ <td rowspan="1" colSpan="1" >**Type**</td>
163
+
164
+ <td rowspan="1" colSpan="1" >**Description**</td>
165
+ </tr>
166
+
167
+ <tr>
168
+ <td rowspan="1" colSpan="1" >`enable`</td>
169
+
170
+ <td rowspan="1" colSpan="1" >`bool`</td>
171
+
172
+ <td rowspan="1" colSpan="1" >Enable earpiece feedback.<br>- true: Enable<br>- false: Disable</td>
173
+ </tr>
174
+ </table>
175
+
176
+
177
+ #### SetVoiceEarMonitorVolume API Parameter
178
+ <table>
179
+ <tr>
180
+ <td rowspan="1" colSpan="1" >**Parameter Name**</td>
181
+
182
+ <td rowspan="1" colSpan="1" >**Type**</td>
183
+
184
+ <td rowspan="1" colSpan="1" >**Description**</td>
185
+ </tr>
186
+
187
+ <tr>
188
+ <td rowspan="1" colSpan="1" >`volume`</td>
189
+
190
+ <td rowspan="1" colSpan="1" >`int`</td>
191
+
192
+ <td rowspan="1" colSpan="1" >Ear return volume.<br>- Value ranges from 0 to 150.<br>- Default value: 100.</td>
193
+ </tr>
194
+ </table>
195
+
196
+
197
+ ### Step 4: Implement Vocal Volume Adjustment
198
+
199
+ When the Anchor hopes to adjust their own uplink capturing volume, call the `DeviceStore`'s `setCaptureVolume(volume)` method to input the volume value.
200
+
201
+ #### Implementation Method
202
+ 1. **Set Capturing Volume**: You can use the `Slider` control to drag the slider left and right to adjust volume, and map the `Slider` value to the volume value before calling `setCaptureVolume(volume)`. Please note, this API accepts a parameter range of `[0, 150]`, so you need to map the UI control value (such as the Slider's `0.0 - 1.0`) to the `0 - 150` range.
203
+
204
+ 2. **Listen for Status Updates to Update UI**: You can subscribe to real-time volume level status value updates to refresh the UI.
205
+
206
+
207
+ #### Sample Code
208
+ ``` java
209
+ import 'package:flutter/material.dart';
210
+ import 'package:atomic_x_core/atomicxcore.dart';
211
+
212
+ /// Voice Volume Control Component
213
+ class CaptureVolumeWidget extends StatelessWidget {
214
+ const CaptureVolumeWidget({super.key});
215
+
216
+ @override
217
+ Widget build(BuildContext context) {
218
+ final deviceStore = DeviceStore.shared;
219
+
220
+ return ValueListenableBuilder<int>(
221
+ valueListenable: deviceStore.state.captureVolume,
222
+ builder: (context, volume, child) {
223
+ return ListTile(
224
+ title: const Text('Voice Volume'),
225
+ subtitle: Slider(
226
+ value: volume.toDouble(),
227
+ min: 0,
228
+ max: 150,
229
+ divisions: 150,
230
+ onChanged: (value) {
231
+ deviceStore.setCaptureVolume(value.toInt());
232
+ },
233
+ ),
234
+ trailing: Text('$volume'),
235
+ );
236
+ },
237
+ );
238
+ }
239
+ }
240
+ ```
241
+
242
+ #### SetCaptureVolume API Parameter
243
+ <table>
244
+ <tr>
245
+ <td rowspan="1" colSpan="1" >**Parameter Name**</td>
246
+
247
+ <td rowspan="1" colSpan="1" >**Type**</td>
248
+
249
+ <td rowspan="1" colSpan="1" >**Description**</td>
250
+ </tr>
251
+
252
+ <tr>
253
+ <td rowspan="1" colSpan="1" >`volume`</td>
254
+
255
+ <td rowspan="1" colSpan="1" >`int`</td>
256
+
257
+ <td rowspan="1" colSpan="1" >Capture volume size.<br>- Value ranges from 0 to 150.<br>- Default value: 100.</td>
258
+ </tr>
259
+ </table>
260
+
261
+
262
+ ### Step 5: Implement Voice-Changing Effects
263
+
264
+ When the Anchor hopes to change their own sound, you can call the `setAudioChangerType(type)` method, input the appropriate Type enumeration value to switch effect.
265
+
266
+ #### Sample Code
267
+ ``` java
268
+ import 'package:flutter/material.dart';
269
+ import 'package:atomic_x_core/atomicxcore.dart';
270
+
271
+ /// Voice changing effect selection component
272
+ class VoiceChangerWidget extends StatelessWidget {
273
+ const VoiceChangerWidget({super.key});
274
+
275
+ @override
276
+ Widget build(BuildContext context) {
277
+ final audioEffectStore = AudioEffectStore.shared;
278
+
279
+ return Column(
280
+ crossAxisAlignment: CrossAxisAlignment.start,
281
+ children: [
282
+ const Padding(
283
+ padding: EdgeInsets.all(16),
284
+ child: Text('Voice-changing effect', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
285
+ ),
286
+ ValueListenableBuilder<AudioChangerType>(
287
+ valueListenable: audioEffectStore.audioEffectState.audioChangerType,
288
+ builder: (context, changerType, child) {
289
+ return Padding(
290
+ padding: const EdgeInsets.symmetric(horizontal: 16),
291
+ child: Wrap(
292
+ spacing: 8,
293
+ runSpacing: 8,
294
+ children: AudioChangerType.values.map((type) {
295
+ return ChoiceChip(
296
+ label: Text(_getChangerTypeName(type)),
297
+ selected: changerType == type,
298
+ onSelected: (selected) {
299
+ if (selected) {
300
+ audioEffectStore.setAudioChangerType(type);
301
+ }
302
+ },
303
+ );
304
+ }).toList(),
305
+ ),
306
+ );
307
+ },
308
+ ),
309
+ ],
310
+ );
311
+ }
312
+
313
+ String _getChangerTypeName(AudioChangerType type) {
314
+ switch (type) {
315
+ case AudioChangerType.none:
316
+ return 'Disable';
317
+ case AudioChangerType.child:
318
+ return 'mischievous child';
319
+ case AudioChangerType.girl:
320
+ return 'loli';
321
+ case AudioChangerType.uncle:
322
+ return 'uncle';
323
+ case AudioChangerType.ethereal:
324
+ return 'ethereal';
325
+ }
326
+ }
327
+ }
328
+ ```
329
+
330
+ #### SetAudioChangerType API Parameter
331
+ <table>
332
+ <tr>
333
+ <td rowspan="1" colSpan="1" >**Parameter Name**</td>
334
+
335
+ <td rowspan="1" colSpan="1" >**Type**</td>
336
+
337
+ <td rowspan="1" colSpan="1" >**Description**</td>
338
+ </tr>
339
+
340
+ <tr>
341
+ <td rowspan="1" colSpan="1" >`type`</td>
342
+
343
+ <td rowspan="1" colSpan="1" >[AudioChangerType](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_audio_effect_store/AudioChangerType.html)</td>
344
+
345
+ <td rowspan="1" colSpan="1" >Voice-changing effects enumeration.</td>
346
+ </tr>
347
+ </table>
348
+
349
+
350
+ ### Step 6: Implement Reverb Effect
351
+
352
+ When the Anchor hopes to add reverb effect to their own sound, you can call the `setAudioReverbType(type)` method, input the appropriate Type enumeration value to switch effect.
353
+
354
+ #### Sample Code
355
+ ``` java
356
+ import 'package:flutter/material.dart';
357
+ import 'package:atomic_x_core/atomicxcore.dart';
358
+
359
+ /// Reverb effect selection component
360
+ class ReverbWidget extends StatelessWidget {
361
+ const ReverbWidget({super.key});
362
+
363
+ @override
364
+ Widget build(BuildContext context) {
365
+ final audioEffectStore = AudioEffectStore.shared;
366
+
367
+ return Column(
368
+ crossAxisAlignment: CrossAxisAlignment.start,
369
+ children: [
370
+ const Padding(
371
+ padding: EdgeInsets.all(16),
372
+ child: Text('Reverb effect', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
373
+ ),
374
+ ValueListenableBuilder<AudioReverbType>(
375
+ valueListenable: audioEffectStore.audioEffectState.audioReverbType,
376
+ builder: (context, reverbType, child) {
377
+ return Padding(
378
+ padding: const EdgeInsets.symmetric(horizontal: 16),
379
+ child: Wrap(
380
+ spacing: 8,
381
+ runSpacing: 8,
382
+ children: AudioReverbType.values.map((type) {
383
+ return ChoiceChip(
384
+ label: Text(_getReverbTypeName(type)),
385
+ selected: reverbType == type,
386
+ onSelected: (selected) {
387
+ if (selected) {
388
+ audioEffectStore.setAudioReverbType(type);
389
+ }
390
+ },
391
+ );
392
+ }).toList(),
393
+ ),
394
+ );
395
+ },
396
+ ),
397
+ ],
398
+ );
399
+ }
400
+
401
+ String _getReverbTypeName(AudioReverbType type) {
402
+ switch (type) {
403
+ case AudioReverbType.none:
404
+ return 'Disable';
405
+ case AudioReverbType.ktv:
406
+ return 'KTV';
407
+ case AudioReverbType.room:
408
+ return 'Small room';
409
+ case AudioReverbType.hall:
410
+ return 'Great hall';
411
+ case AudioReverbType.deep:
412
+ return 'deep';
413
+ case AudioReverbType.loud:
414
+ return 'resonant';
415
+ case AudioReverbType.metallic:
416
+ return 'metallic sound';
417
+ case AudioReverbType.magnetic:
418
+ return 'magnetic';
419
+ case AudioReverbType.recordingStudio:
420
+ return 'studio';
421
+ }
422
+ }
423
+ }
424
+ ```
425
+
426
+ #### SetAudioReverbType API Parameter
427
+ <table>
428
+ <tr>
429
+ <td rowspan="1" colSpan="1" >**Parameter Name**</td>
430
+
431
+ <td rowspan="1" colSpan="1" >**Type**</td>
432
+
433
+ <td rowspan="1" colSpan="1" >**Description**</td>
434
+ </tr>
435
+
436
+ <tr>
437
+ <td rowspan="1" colSpan="1" >`type`</td>
438
+
439
+ <td rowspan="1" colSpan="1" >[AudioReverbType](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_audio_effect_store/AudioReverbType.html)</td>
440
+
441
+ <td rowspan="1" colSpan="1" >Reverb effects enumeration.</td>
442
+ </tr>
443
+ </table>
444
+
445
+
446
+ ### Step 7: Reset Sound Effect Settings
447
+
448
+ > **Important:**
449
+ >
450
+
451
+ > AudioEffectStore and DeviceStore are singletons, so audio effects and device settings take effect globally. If you do not want the settings of the current live streaming room to affect other live streaming rooms created later, you need to reset the audio effects and device settings when the current live streaming room ends.
452
+ >
453
+
454
+
455
+ You may need to reset sound effect settings in the following two scenarios:
456
+ 1. **When the current live streaming room ends**, call the `store`'s `reset()` method to reset sound effects.
457
+
458
+ 2. **When you need to reset all devices and sound effect settings**, call the `store`'s `reset()` method to reset sound effects.
459
+
460
+ ``` java
461
+ import 'package:flutter/material.dart';
462
+ import 'package:atomic_x_core/atomicxcore.dart';
463
+
464
+ /// Sound effect reset component
465
+ class AudioEffectResetWidget extends StatelessWidget {
466
+ const AudioEffectResetWidget({super.key});
467
+
468
+ void _resetAudioEffect() {
469
+ AudioEffectStore.shared.reset();
470
+ DeviceStore.shared.reset();
471
+ }
472
+
473
+ @override
474
+ Widget build(BuildContext context) {
475
+ return ElevatedButton(
476
+ onPressed: _resetAudioEffect,
477
+ child: const Text('Reset sound effect settings'),
478
+ );
479
+ }
480
+ }
481
+ ```
482
+
483
+ ## Complete Example
484
+ ``` java
485
+ import 'package:flutter/material.dart';
486
+ import 'package:atomic_x_core/atomicxcore.dart';
487
+
488
+ /// Sound effect settings page
489
+ class AudioEffectPage extends StatelessWidget {
490
+ const AudioEffectPage({super.key});
491
+
492
+ @override
493
+ Widget build(BuildContext context) {
494
+ final audioEffectStore = AudioEffectStore.shared;
495
+ final deviceStore = DeviceStore.shared;
496
+
497
+ return Scaffold(
498
+ appBar: AppBar(title: const Text('Sound effect settings')),
499
+ body: ListView(
500
+ children: [
501
+ // Voice volume
502
+ const Padding(
503
+ padding: EdgeInsets.all(16),
504
+ child: Text('Voice volume', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
505
+ ),
506
+ ValueListenableBuilder<int>(
507
+ valueListenable: deviceStore.state.captureVolume,
508
+ builder: (context, volume, child) {
509
+ return ListTile(
510
+ title: const Text('Capture Volume'),
511
+ subtitle: Slider(
512
+ value: volume.toDouble(),
513
+ min: 0,
514
+ max: 150,
515
+ divisions: 150,
516
+ onChanged: (value) {
517
+ deviceStore.setCaptureVolume(value.toInt());
518
+ },
519
+ ),
520
+ trailing: Text('$volume'),
521
+ );
522
+ },
523
+ ),
524
+ const Divider(),
525
+
526
+ // Ear return settings
527
+ const Padding(
528
+ padding: EdgeInsets.all(16),
529
+ child: Text('Ear monitoring', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
530
+ ),
531
+ ValueListenableBuilder<bool>(
532
+ valueListenable: audioEffectStore.audioEffectState.isEarMonitorOpened,
533
+ builder: (context, isOpened, child) {
534
+ return SwitchListTile(
535
+ title: const Text('Enable Ear Monitoring'),
536
+ subtitle: const Text('Insert a headset')
537
+ value: isOpened,
538
+ onChanged: (value) {
539
+ audioEffectStore.setVoiceEarMonitorEnable(value);
540
+ },
541
+ );
542
+ },
543
+ ),
544
+ ValueListenableBuilder<int>(
545
+ valueListenable: audioEffectStore.audioEffectState.earMonitorVolume,
546
+ builder: (context, volume, child) {
547
+ return ListTile(
548
+ title: const Text('Ear Monitoring Volume'),
549
+ subtitle: Slider(
550
+ value: volume.toDouble(),
551
+ min: 0,
552
+ max: 150,
553
+ divisions: 150,
554
+ onChanged: (value) {
555
+ audioEffectStore.setVoiceEarMonitorVolume(value.toInt());
556
+ },
557
+ ),
558
+ trailing: Text('$volume'),
559
+ );
560
+ },
561
+ ),
562
+ const Divider(),
563
+
564
+ // Voice changing settings
565
+ const Padding(
566
+ padding: EdgeInsets.all(16),
567
+ child: Text('Voice-changing', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
568
+ ),
569
+ ValueListenableBuilder<AudioChangerType>(
570
+ valueListenable: audioEffectStore.audioEffectState.audioChangerType,
571
+ builder: (context, changerType, child) {
572
+ return Padding(
573
+ padding: const EdgeInsets.symmetric(horizontal: 16),
574
+ child: Wrap(
575
+ spacing: 8,
576
+ runSpacing: 8,
577
+ children: AudioChangerType.values.map((type) {
578
+ return ChoiceChip(
579
+ label: Text(_getChangerTypeName(type)),
580
+ selected: changerType == type,
581
+ onSelected: (selected) {
582
+ if (selected) {
583
+ audioEffectStore.setAudioChangerType(type);
584
+ }
585
+ },
586
+ );
587
+ }).toList(),
588
+ ),
589
+ );
590
+ },
591
+ ),
592
+ const SizedBox(height: 16),
593
+ const Divider(),
594
+
595
+ // Reverb settings
596
+ const Padding(
597
+ padding: EdgeInsets.all(16),
598
+ child: Text('Reverb', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
599
+ ),
600
+ ValueListenableBuilder<AudioReverbType>(
601
+ valueListenable: audioEffectStore.audioEffectState.audioReverbType,
602
+ builder: (context, reverbType, child) {
603
+ return Padding(
604
+ padding: const EdgeInsets.symmetric(horizontal: 16),
605
+ child: Wrap(
606
+ spacing: 8,
607
+ runSpacing: 8,
608
+ children: AudioReverbType.values.map((type) {
609
+ return ChoiceChip(
610
+ label: Text(_getReverbTypeName(type)),
611
+ selected: reverbType == type,
612
+ onSelected: (selected) {
613
+ if (selected) {
614
+ audioEffectStore.setAudioReverbType(type);
615
+ }
616
+ },
617
+ );
618
+ }).toList(),
619
+ ),
620
+ );
621
+ },
622
+ ),
623
+ const SizedBox(height: 24),
624
+
625
+ // reset button
626
+ Padding(
627
+ padding: const EdgeInsets.all(16),
628
+ child: ElevatedButton(
629
+ onPressed: () {
630
+ audioEffectStore.reset();
631
+ deviceStore.reset();
632
+ },
633
+ child: const Text('Reset sound effect settings'),
634
+ ),
635
+ ),
636
+ ],
637
+ ),
638
+ );
639
+ }
640
+
641
+ String _getChangerTypeName(AudioChangerType type) {
642
+ switch (type) {
643
+ case AudioChangerType.none:
644
+ return 'Disable';
645
+ case AudioChangerType.child:
646
+ return 'mischievous child';
647
+ case AudioChangerType.girl:
648
+ return 'loli';
649
+ case AudioChangerType.uncle:
650
+ return 'uncle';
651
+ case AudioChangerType.ethereal:
652
+ return 'ethereal';
653
+ }
654
+ }
655
+
656
+ String _getReverbTypeName(AudioReverbType type) {
657
+ switch (type) {
658
+ case AudioReverbType.none:
659
+ return 'Disable';
660
+ case AudioReverbType.ktv:
661
+ return 'KTV';
662
+ case AudioReverbType.room:
663
+ return 'Small room';
664
+ case AudioReverbType.hall:
665
+ return 'Great hall';
666
+ case AudioReverbType.deep:
667
+ return 'deep';
668
+ case AudioReverbType.loud:
669
+ return 'resonant';
670
+ case AudioReverbType.metallic:
671
+ return 'metallic sound';
672
+ case AudioReverbType.magnetic:
673
+ return 'magnetic';
674
+ case AudioReverbType.recordingStudio:
675
+ return 'studio';
676
+ }
677
+ }
678
+ }
679
+ ```
680
+
681
+ ## API documentation
682
+
683
+ For detailed information about all public interfaces and attributes of [AudioEffectStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_audio_effect_store/AudioEffectStore-class.html), [DeviceStore](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_device_store/DeviceStore-class.html) and its related classes, see the official API documentation of the [AtomicXCore](https://tencent-rtc.github.io/TUIKit_Flutter/index.html) framework.
684
+ <table>
685
+ <tr>
686
+ <td rowspan="1" colSpan="1" >**Store/Component**</td>
687
+
688
+ <td rowspan="1" colSpan="1" >**Feature Description**</td>
689
+
690
+ <td rowspan="1" colSpan="1" >**API Reference**</td>
691
+ </tr>
692
+
693
+ <tr>
694
+ <td rowspan="1" colSpan="1" >**AudioEffectStore**</td>
695
+
696
+ <td rowspan="1" colSpan="1" >Audio effect management: Perform audio effect settings and obtain real-time audio effect status.</td>
697
+
698
+ <td rowspan="1" colSpan="1" >[API documentation](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_audio_effect_store/AudioEffectStore-class.html)</td>
699
+ </tr>
700
+
701
+ <tr>
702
+ <td rowspan="1" colSpan="1" >**DeviceStore**</td>
703
+
704
+ <td rowspan="1" colSpan="1" >Device management: perform camera and microphone operations and obtain real-time device status.</td>
705
+
706
+ <td rowspan="1" colSpan="1" >[API documentation](https://tencent-rtc.github.io/TUIKit_Flutter/api_device_device_store/DeviceStore-class.html)</td>
707
+ </tr>
708
+ </table>
709
+
710
+
711
+ ## FAQs
712
+
713
+ ### Is There a Requirement for the Timing of Invocation of Sound Effects and Device Interfaces?
714
+
715
+ No limit. The settings of `AudioEffectStore` and `DeviceStore` take effect globally. You can call APIs (such as setting voice-changing, reverb, or ear monitoring) at any time before or after entering the live room. The settings will take effect immediately and be reserved.
716
+
717
+ ### What Is the Difference between Voice Volume and Ear Return Volume?
718
+
719
+ This is a very important and confusing concept. The difference is as follows:
720
+ - **Voice Volume (CaptureVolume):** Set via `DeviceStore.shared.setCaptureVolume()`. It determines the Anchor's sound level heard by the audience.
721
+
722
+ - **Ear Return Volume (EarMonitorVolume):** Set via `AudioEffectStore.shared.setVoiceEarMonitorVolume()`. It only determines the Anchor's headphone monitoring volume and **does not** impact the audience.
723
+
724
+
725
+ ### Why Does a Newly Created Live Streaming Room Have Sound Effects Directly or Issues Like Very High or Low Volume?
726
+
727
+ `AudioEffectStore` and `DeviceStore` are singletons, which means audio effects and device settings take effect globally. This situation probably occurs because you set audio effects earlier but did not reset them. You need to call the `reset()` method in an appropriate place.
728
+
729
+ ### Why Did I Enable "Ear Return" but Cannot Hear My Own Sound?
730
+
731
+ Please check by the following steps:
732
+ 1. **Whether to insert headphones**: The in-ear monitoring feature depends on headphones most of the time for the changes to take effect. Please ensure wired or Bluetooth headphones are connected.
733
+
734
+ 2. **Whether the volume is 0**: Check if the "ear return volume" is set to 0.
735
+
736
+ 3. **Is the microphone enabled**: Confirm that the microphone in `DeviceStore` is enabled (the `openLocalMicrophone()` call has been made).
737
+
738
+
739
+ ### Can Voice-Changing Effects and Reverb Effects Take Effect at the Same Time?
740
+
741
+ Yes. `AudioChangerType` and `AudioReverbType` can take effect in superposition. For example, you can simultaneously set `AudioChangerType.girl` voice-changing and `AudioReverbType.ktv` reverb.
742
+