join_channel_audio.dart 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import 'dart:async';
  2. import 'dart:developer';
  3. import 'package:agora_rtc_engine/agora_rtc_engine.dart';
  4. import 'package:agora_rtc_engine_example/config/agora.config.dart' as config;
  5. import 'package:flutter/foundation.dart';
  6. import 'package:flutter/material.dart';
  7. import 'package:permission_handler/permission_handler.dart';
  8. /// JoinChannelAudio Example
  9. class JoinChannelAudio extends StatefulWidget {
  10. @override
  11. State<StatefulWidget> createState() => _State();
  12. }
  13. class _State extends State<JoinChannelAudio> {
  14. late final RtcEngine _engine;
  15. String channelId = config.channelId;
  16. bool isJoined = false,
  17. openMicrophone = true,
  18. enableSpeakerphone = true,
  19. playEffect = false;
  20. bool _enableInEarMonitoring = false;
  21. double _recordingVolume = 0, _playbackVolume = 0, _inEarMonitoringVolume = 0;
  22. TextEditingController? _controller;
  23. @override
  24. void initState() {
  25. super.initState();
  26. _controller = TextEditingController(text: channelId);
  27. this._initEngine();
  28. }
  29. @override
  30. void dispose() {
  31. super.dispose();
  32. _engine.destroy();
  33. }
  34. _initEngine() async {
  35. _engine = await RtcEngine.createWithContext(RtcEngineContext(config.appId));
  36. this._addListeners();
  37. await _engine.enableAudio();
  38. await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
  39. await _engine.setClientRole(ClientRole.Broadcaster);
  40. }
  41. _addListeners() {
  42. _engine.setEventHandler(RtcEngineEventHandler(
  43. joinChannelSuccess: (channel, uid, elapsed) {
  44. log('joinChannelSuccess $channel $uid $elapsed');
  45. setState(() {
  46. isJoined = true;
  47. });
  48. },
  49. leaveChannel: (stats) async {
  50. log('leaveChannel ${stats.toJson()}');
  51. setState(() {
  52. isJoined = false;
  53. });
  54. },
  55. ));
  56. }
  57. _joinChannel() async {
  58. if (defaultTargetPlatform == TargetPlatform.android) {
  59. await Permission.microphone.request();
  60. }
  61. await _engine
  62. .joinChannel(config.token, config.channelId, null, config.uid)
  63. .catchError((onError) {
  64. print('error ${onError.toString()}');
  65. });
  66. }
  67. _leaveChannel() async {
  68. await _engine.leaveChannel();
  69. }
  70. _switchMicrophone() {
  71. _engine.enableLocalAudio(!openMicrophone).then((value) {
  72. setState(() {
  73. openMicrophone = !openMicrophone;
  74. });
  75. }).catchError((err) {
  76. log('enableLocalAudio $err');
  77. });
  78. }
  79. _switchSpeakerphone() {
  80. _engine.setEnableSpeakerphone(!enableSpeakerphone).then((value) {
  81. setState(() {
  82. enableSpeakerphone = !enableSpeakerphone;
  83. });
  84. }).catchError((err) {
  85. log('setEnableSpeakerphone $err');
  86. });
  87. }
  88. _switchEffect() async {
  89. if (playEffect) {
  90. _engine.stopEffect(1).then((value) {
  91. setState(() {
  92. playEffect = false;
  93. });
  94. }).catchError((err) {
  95. log('stopEffect $err');
  96. });
  97. } else {
  98. _engine
  99. .playEffect(
  100. 1,
  101. await (_engine.getAssetAbsolutePath("assets/Sound_Horizon.mp3")
  102. as FutureOr<String>),
  103. -1,
  104. 1,
  105. 1,
  106. 100,
  107. true)
  108. .then((value) {
  109. setState(() {
  110. playEffect = true;
  111. });
  112. }).catchError((err) {
  113. log('playEffect $err');
  114. });
  115. }
  116. }
  117. _onChangeInEarMonitoringVolume(double value) {
  118. setState(() {
  119. _inEarMonitoringVolume = value;
  120. });
  121. _engine.setInEarMonitoringVolume(value.toInt());
  122. }
  123. _toggleInEarMonitoring(value) {
  124. setState(() {
  125. _enableInEarMonitoring = value;
  126. });
  127. _engine.enableInEarMonitoring(value);
  128. }
  129. @override
  130. Widget build(BuildContext context) {
  131. return Stack(
  132. children: [
  133. Column(
  134. children: [
  135. TextField(
  136. controller: _controller,
  137. decoration: InputDecoration(hintText: 'Channel ID'),
  138. onChanged: (text) {
  139. setState(() {
  140. channelId = text;
  141. });
  142. },
  143. ),
  144. Row(
  145. children: [
  146. Expanded(
  147. flex: 1,
  148. child: ElevatedButton(
  149. onPressed:
  150. isJoined ? this._leaveChannel : this._joinChannel,
  151. child: Text('${isJoined ? 'Leave' : 'Join'} channel'),
  152. ),
  153. )
  154. ],
  155. ),
  156. ],
  157. ),
  158. Align(
  159. alignment: Alignment.bottomRight,
  160. child: Padding(
  161. child: Column(
  162. mainAxisSize: MainAxisSize.min,
  163. crossAxisAlignment: CrossAxisAlignment.end,
  164. children: [
  165. ElevatedButton(
  166. onPressed: this._switchMicrophone,
  167. child: Text('Microphone ${openMicrophone ? 'on' : 'off'}'),
  168. ),
  169. ElevatedButton(
  170. onPressed: this._switchSpeakerphone,
  171. child:
  172. Text(enableSpeakerphone ? 'Speakerphone' : 'Earpiece'),
  173. ),
  174. ElevatedButton(
  175. onPressed: this._switchEffect,
  176. child: Text('${playEffect ? 'Stop' : 'Play'} effect'),
  177. ),
  178. Row(
  179. mainAxisAlignment: MainAxisAlignment.end,
  180. children: [
  181. Text('RecordingVolume:'),
  182. Slider(
  183. value: _recordingVolume,
  184. min: 0,
  185. max: 400,
  186. divisions: 5,
  187. label: 'RecordingVolume',
  188. onChanged: (double value) {
  189. setState(() {
  190. _recordingVolume = value;
  191. });
  192. _engine.adjustRecordingSignalVolume(value.toInt());
  193. },
  194. )
  195. ],
  196. ),
  197. Row(
  198. mainAxisAlignment: MainAxisAlignment.end,
  199. children: [
  200. Text('PlaybackVolume:'),
  201. Slider(
  202. value: _playbackVolume,
  203. min: 0,
  204. max: 400,
  205. divisions: 5,
  206. label: 'PlaybackVolume',
  207. onChanged: (double value) {
  208. setState(() {
  209. _playbackVolume = value;
  210. });
  211. _engine.adjustPlaybackSignalVolume(value.toInt());
  212. },
  213. )
  214. ],
  215. ),
  216. Column(
  217. mainAxisSize: MainAxisSize.min,
  218. crossAxisAlignment: CrossAxisAlignment.end,
  219. children: [
  220. Row(mainAxisSize: MainAxisSize.min, children: [
  221. Text('InEar Monitoring Volume:'),
  222. Switch(
  223. value: _enableInEarMonitoring,
  224. onChanged: _toggleInEarMonitoring,
  225. activeTrackColor: Colors.grey[350],
  226. activeColor: Colors.white,
  227. )
  228. ]),
  229. if (_enableInEarMonitoring)
  230. Container(
  231. width: 300,
  232. child: Slider(
  233. value: _inEarMonitoringVolume,
  234. min: 0,
  235. max: 100,
  236. divisions: 5,
  237. label: 'InEar Monitoring Volume',
  238. onChanged: _onChangeInEarMonitoringVolume,
  239. ))
  240. ],
  241. ),
  242. ],
  243. ),
  244. padding: EdgeInsets.symmetric(vertical: 20, horizontal: 0),
  245. ))
  246. ],
  247. );
  248. }
  249. }