製品アップデート情報
Tencent Cloudオーディオビデオ端末SDKの再生アップグレードおよび承認チェック追加に関するお知らせ
TRTCアプリケーションのサブスクリプションパッケージサービスのリリースに関する説明について
AudioEffectStore and DeviceStore modules from the AtomicXCore framework to quickly add audio effect controls to your live streaming app. With these modules, you can implement features like microphone volume adjustment, in-ear monitoring, and a range of engaging voice changer and reverb effects.
AudioEffectStore and DeviceStore, you can enable the following features in your live streaming app:Core Concept | Type | Key Responsibilities & Description |
class | Tracks the current state of the audio effects module, typically for UI rendering. Includes voice changer status, reverb status, in-ear monitor enabled status, and in-ear monitor volume. All properties are ValueListenable and support state change subscriptions. | |
class | Singleton data manager for the audio effects module. Use this to call audio effect APIs. After you call an API, the relevant audioEffectState property updates automatically; subscribe to this reactive state for real-time updates. | |
class | Tracks the current state of the device module, typically for UI rendering. Key properties include camera and microphone device status, capture volume, and more. All properties are ValueListenable and support state change subscriptions. | |
class | Singleton data manager for the device module. Use this to control camera and microphone APIs. After you call an API, the relevant state property updates automatically; subscribe to this reactive state for real-time updates. |
AudioEffectStore and DeviceStore are singletons. You can access their instances anywhere in your project using the shared property. For a full implementation example, refer to the audio_effect_panel_widget.dart file in the TUILiveKit open-source UI demo project.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';class _AudioEffectPanelWidgetState {final _audioEffectStore = AudioEffectStore.shared;final _deviceStore = DeviceStore.shared;}
setVoiceEarMonitorVolume(volume). The valid range is [0, 150], so map your UI control's value (e.g., slider 0.0 - 1.0) to 0 - 150.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// Ear Monitoring Control Componentclass EarMonitorWidget extends StatelessWidget {const EarMonitorWidget({super.key});@overrideWidget build(BuildContext context) {final audioEffectStore = AudioEffectStore.shared;return Column(crossAxisAlignment: CrossAxisAlignment.start,children: [// 1. Toggle ear monitoringValueListenableBuilder<bool>(valueListenable: audioEffectStore.audioEffectState.isEarMonitorOpened,builder: (context, isOpened, child) {return SwitchListTile(title: const Text('Ear Monitoring'),subtitle: const Text('Insert a headset')value: isOpened,onChanged: (value) {audioEffectStore.setVoiceEarMonitorEnable(value);},);},),// 2. Adjust ear return volumeValueListenableBuilder<int>(valueListenable: audioEffectStore.audioEffectState.earMonitorVolume,builder: (context, volume, child) {return ListTile(title: const Text('Ear Monitoring Volume'),subtitle: Slider(value: volume.toDouble(),min: 0,max: 150,divisions: 150,onChanged: (value) {audioEffectStore.setVoiceEarMonitorVolume(value.toInt());},),trailing: Text('$volume'),);},),],);}}
Parameter Name | Type | Description |
enable | bool | Enable in-ear monitor: true: Enable.false: Disable. |
Parameter Name | Type | Description |
volume | int | Ear return volume. Value ranges from 0 to 150. Default value: 100. |
DeviceStore.setCaptureVolume(volume) with your desired value.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.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// Voice Volume Control Componentclass CaptureVolumeWidget extends StatelessWidget {const CaptureVolumeWidget({super.key});@overrideWidget build(BuildContext context) {final deviceStore = DeviceStore.shared;return ValueListenableBuilder<int>(valueListenable: deviceStore.state.captureVolume,builder: (context, volume, child) {return ListTile(title: const Text('Voice Volume'),subtitle: Slider(value: volume.toDouble(),min: 0,max: 150,divisions: 150,onChanged: (value) {deviceStore.setCaptureVolume(value.toInt());},),trailing: Text('$volume'),);},);}}
Parameter Name | Type | Description |
volume | int | Capture volume size. Value ranges from 0 to 150. Default value: 100. |
setAudioChangerType(type) and pass the desired enum value.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// Voice changing effect selection componentclass VoiceChangerWidget extends StatelessWidget {const VoiceChangerWidget({super.key});@overrideWidget build(BuildContext context) {final audioEffectStore = AudioEffectStore.shared;return Column(crossAxisAlignment: CrossAxisAlignment.start,children: [const Padding(padding: EdgeInsets.all(16),child: Text('Voice-changing effect', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),),ValueListenableBuilder<AudioChangerType>(valueListenable: audioEffectStore.audioEffectState.audioChangerType,builder: (context, changerType, child) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 16),child: Wrap(spacing: 8,runSpacing: 8,children: AudioChangerType.values.map((type) {return ChoiceChip(label: Text(_getChangerTypeName(type)),selected: changerType == type,onSelected: (selected) {if (selected) {audioEffectStore.setAudioChangerType(type);}},);}).toList(),),);},),],);}String _getChangerTypeName(AudioChangerType type) {switch (type) {case AudioChangerType.none:return 'Disable';case AudioChangerType.child:return 'mischievous child';case AudioChangerType.girl:return 'loli';case AudioChangerType.uncle:return 'uncle';case AudioChangerType.ethereal:return 'ethereal';}}}
Parameter Name | Type | Description |
type | Voice-changing effects enumeration. |
setAudioReverbType(type) and pass the desired enum value.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// Reverb effect selection componentclass ReverbWidget extends StatelessWidget {const ReverbWidget({super.key});@overrideWidget build(BuildContext context) {final audioEffectStore = AudioEffectStore.shared;return Column(crossAxisAlignment: CrossAxisAlignment.start,children: [const Padding(padding: EdgeInsets.all(16),child: Text('Reverb effect', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),),ValueListenableBuilder<AudioReverbType>(valueListenable: audioEffectStore.audioEffectState.audioReverbType,builder: (context, reverbType, child) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 16),child: Wrap(spacing: 8,runSpacing: 8,children: AudioReverbType.values.map((type) {return ChoiceChip(label: Text(_getReverbTypeName(type)),selected: reverbType == type,onSelected: (selected) {if (selected) {audioEffectStore.setAudioReverbType(type);}},);}).toList(),),);},),],);}String _getReverbTypeName(AudioReverbType type) {switch (type) {case AudioReverbType.none:return 'Disable';case AudioReverbType.ktv:return 'KTV';case AudioReverbType.room:return 'Small room';case AudioReverbType.hall:return 'Great hall';case AudioReverbType.deep:return 'deep';case AudioReverbType.loud:return 'resonant';case AudioReverbType.metallic:return 'metallic sound';case AudioReverbType.magnetic:return 'magnetic';case AudioReverbType.recordingStudio:return 'studio';}}}
Parameter Name | Type | Description |
type | Reverb effects enumeration. |
store's reset() method to reset sound effects.store's reset() method to reset sound effects.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// Sound effect reset componentclass AudioEffectResetWidget extends StatelessWidget {const AudioEffectResetWidget({super.key});void _resetAudioEffect() {AudioEffectStore.shared.reset();DeviceStore.shared.reset();}@overrideWidget build(BuildContext context) {return ElevatedButton(onPressed: _resetAudioEffect,child: const Text('Reset sound effect settings'),);}}
import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// Sound effect settings pageclass AudioEffectPage extends StatelessWidget {const AudioEffectPage({super.key});@overrideWidget build(BuildContext context) {final audioEffectStore = AudioEffectStore.shared;final deviceStore = DeviceStore.shared;return Scaffold(appBar: AppBar(title: const Text('Sound effect settings')),body: ListView(children: [// Voice volumeconst Padding(padding: EdgeInsets.all(16),child: Text('Voice volume', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),),ValueListenableBuilder<int>(valueListenable: deviceStore.state.captureVolume,builder: (context, volume, child) {return ListTile(title: const Text('Capture Volume'),subtitle: Slider(value: volume.toDouble(),min: 0,max: 150,divisions: 150,onChanged: (value) {deviceStore.setCaptureVolume(value.toInt());},),trailing: Text('$volume'),);},),const Divider(),// Ear return settingsconst Padding(padding: EdgeInsets.all(16),child: Text('Ear monitoring', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),),ValueListenableBuilder<bool>(valueListenable: audioEffectStore.audioEffectState.isEarMonitorOpened,builder: (context, isOpened, child) {return SwitchListTile(title: const Text('Enable Ear Monitoring'),subtitle: const Text('Insert a headset')value: isOpened,onChanged: (value) {audioEffectStore.setVoiceEarMonitorEnable(value);},);},),ValueListenableBuilder<int>(valueListenable: audioEffectStore.audioEffectState.earMonitorVolume,builder: (context, volume, child) {return ListTile(title: const Text('Ear Monitoring Volume'),subtitle: Slider(value: volume.toDouble(),min: 0,max: 150,divisions: 150,onChanged: (value) {audioEffectStore.setVoiceEarMonitorVolume(value.toInt());},),trailing: Text('$volume'),);},),const Divider(),// Voice changing settingsconst Padding(padding: EdgeInsets.all(16),child: Text('Voice-changing', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),),ValueListenableBuilder<AudioChangerType>(valueListenable: audioEffectStore.audioEffectState.audioChangerType,builder: (context, changerType, child) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 16),child: Wrap(spacing: 8,runSpacing: 8,children: AudioChangerType.values.map((type) {return ChoiceChip(label: Text(_getChangerTypeName(type)),selected: changerType == type,onSelected: (selected) {if (selected) {audioEffectStore.setAudioChangerType(type);}},);}).toList(),),);},),const SizedBox(height: 16),const Divider(),// Reverb settingsconst Padding(padding: EdgeInsets.all(16),child: Text('Reverb', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),),ValueListenableBuilder<AudioReverbType>(valueListenable: audioEffectStore.audioEffectState.audioReverbType,builder: (context, reverbType, child) {return Padding(padding: const EdgeInsets.symmetric(horizontal: 16),child: Wrap(spacing: 8,runSpacing: 8,children: AudioReverbType.values.map((type) {return ChoiceChip(label: Text(_getReverbTypeName(type)),selected: reverbType == type,onSelected: (selected) {if (selected) {audioEffectStore.setAudioReverbType(type);}},);}).toList(),),);},),const SizedBox(height: 24),// reset buttonPadding(padding: const EdgeInsets.all(16),child: ElevatedButton(onPressed: () {audioEffectStore.reset();deviceStore.reset();},child: const Text('Reset sound effect settings'),),),],),);}String _getChangerTypeName(AudioChangerType type) {switch (type) {case AudioChangerType.none:return 'Disable';case AudioChangerType.child:return 'mischievous child';case AudioChangerType.girl:return 'loli';case AudioChangerType.uncle:return 'uncle';case AudioChangerType.ethereal:return 'ethereal';}}String _getReverbTypeName(AudioReverbType type) {switch (type) {case AudioReverbType.none:return 'Disable';case AudioReverbType.ktv:return 'KTV';case AudioReverbType.room:return 'Small room';case AudioReverbType.hall:return 'Great hall';case AudioReverbType.deep:return 'deep';case AudioReverbType.loud:return 'resonant';case AudioReverbType.metallic:return 'metallic sound';case AudioReverbType.magnetic:return 'magnetic';case AudioReverbType.recordingStudio:return 'studio';}}}
Store/Component | Feature Description | API Reference |
AudioEffectStore | Audio effect management: Perform audio effect settings and obtain real-time audio effect status. | |
DeviceStore | Device management: perform camera and microphone operations and obtain real-time device status. |
AudioEffectStore and DeviceStore are global. You can call related APIs (such as setting voice changer, reverb, or in-ear monitor) at any time before or after joining a live room. Changes take effect immediately and persist.DeviceStore.shared.setCaptureVolume(). Controls how loud the host sounds to the audience.AudioEffectStore.shared.setVoiceEarMonitorVolume(). Controls only how loud the host hears themselves in their headphones and does not affect the audience.AudioEffectStore and DeviceStore are singletons, audio effect and device settings are global. This usually happens if you previously set audio effects and didn't reset them. Be sure to call reset() when appropriate.AudioChangerType and AudioReverbType can be used together. For example, you can apply both AudioChangerType.girl and AudioReverbType.ktv simultaneously.フィードバック