Commit 1f5969b893ad45a1c3cb5c2d5a473e596844f433
1 parent
1ea75f04
修复 练习和绘本播放音频问题
Showing
2 changed files
with
81 additions
and
49 deletions
lib/pages/practice/bloc/topic_picture_bloc.dart
... | ... | @@ -24,16 +24,19 @@ part 'topic_picture_state.dart'; |
24 | 24 | enum VoicePlayState { |
25 | 25 | ///未知 |
26 | 26 | unKnow, |
27 | + | |
27 | 28 | ///播放中 |
28 | 29 | playing, |
30 | + | |
29 | 31 | ///播放完成 |
30 | 32 | completed, |
33 | + | |
31 | 34 | ///播放终止 |
32 | 35 | stop |
33 | 36 | } |
34 | 37 | |
35 | -class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureState> { | |
36 | - | |
38 | +class TopicPictureBloc | |
39 | + extends BaseSectionBloc<TopicPictureEvent, TopicPictureState> { | |
37 | 40 | final PageController pageController; |
38 | 41 | |
39 | 42 | final String courseLessonId; |
... | ... | @@ -68,7 +71,7 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
68 | 71 | |
69 | 72 | bool get isVoicing => _isVoicing; |
70 | 73 | |
71 | - VoicePlayState get voicePlayState => _voicePlayState; | |
74 | + VoicePlayState get voicePlayState => _voicePlayState; | |
72 | 75 | |
73 | 76 | late MethodChannel methodChannel; |
74 | 77 | |
... | ... | @@ -76,7 +79,8 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
76 | 79 | |
77 | 80 | final BuildContext context; |
78 | 81 | |
79 | - TopicPictureBloc(this.context, this.pageController, this.courseLessonId) : super(TopicPictureInitial()) { | |
82 | + TopicPictureBloc(this.context, this.pageController, this.courseLessonId) | |
83 | + : super(TopicPictureInitial()) { | |
80 | 84 | on<CurrentPageIndexChangeEvent>(_pageControllerChange); |
81 | 85 | on<VoicePlayStateChangeEvent>(_voicePlayStateChange); |
82 | 86 | on<XSVoiceResultEvent>(_voiceXsResult); |
... | ... | @@ -90,7 +94,8 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
90 | 94 | //音频播放器 |
91 | 95 | audioPlayer = AudioPlayer(); |
92 | 96 | audioPlayer.onPlayerStateChanged.listen((event) async { |
93 | - debugPrint('播放状态变化 _voicePlayState=$_voicePlayState event=$event _isResultSoundPlaying=$_isResultSoundPlaying _forbiddenWhenCorrect=$_forbiddenWhenCorrect'); | |
97 | + debugPrint( | |
98 | + '播放状态变化 _voicePlayState=$_voicePlayState event=$event _isResultSoundPlaying=$_isResultSoundPlaying _forbiddenWhenCorrect=$_forbiddenWhenCorrect'); | |
94 | 99 | if (_isResultSoundPlaying) { |
95 | 100 | if (event != PlayerState.playing) { |
96 | 101 | _isResultSoundPlaying = false; |
... | ... | @@ -131,28 +136,40 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
131 | 136 | } |
132 | 137 | }); |
133 | 138 | |
134 | - methodChannel = const MethodChannel('wow_english/sing_sound_method_channel'); | |
139 | + methodChannel = | |
140 | + const MethodChannel('wow_english/sing_sound_method_channel'); | |
135 | 141 | methodChannel.setMethodCallHandler((call) async { |
136 | - if (call.method == 'voiceResult') {//评测结果 | |
142 | + if (call.method == 'voiceResult') { | |
143 | + //评测结果 | |
144 | + await audioPlayer.setAudioContext(AudioContext()); | |
145 | + await audioPlayer.setBalance(0.0); | |
137 | 146 | add(XSVoiceResultEvent(call.arguments)); |
138 | 147 | return; |
139 | 148 | } |
140 | 149 | |
141 | - if (call.method == 'voiceStart') {//评测开始 | |
150 | + if (call.method == 'voiceStart') { | |
151 | + //评测开始 | |
142 | 152 | if (kDebugMode) { |
143 | 153 | print('评测开始'); |
144 | 154 | } |
145 | 155 | return; |
146 | 156 | } |
147 | 157 | |
148 | - if (call.method == 'voiceEnd') {//评测结束 | |
158 | + if (call.method == 'voiceEnd') { | |
159 | + await audioPlayer.setAudioContext(AudioContext()); | |
160 | + await audioPlayer.setBalance(0.0); | |
161 | + //评测结束 | |
149 | 162 | if (kDebugMode) { |
150 | 163 | print('评测结束'); |
151 | 164 | } |
152 | 165 | return; |
153 | 166 | } |
154 | 167 | |
155 | - if (call.method == 'voiceFail') {//评测失败 | |
168 | + if (call.method == 'voiceFail') { | |
169 | + //评测失败 | |
170 | + await audioPlayer.setAudioContext(AudioContext()); | |
171 | + await audioPlayer.setBalance(0.0); | |
172 | + | |
156 | 173 | EasyLoading.showToast('评测失败'); |
157 | 174 | return; |
158 | 175 | } |
... | ... | @@ -161,7 +178,7 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
161 | 178 | } |
162 | 179 | |
163 | 180 | @override |
164 | - Future<void> close(){ | |
181 | + Future<void> close() { | |
165 | 182 | pageController.dispose(); |
166 | 183 | audioPlayer.release(); |
167 | 184 | audioPlayer.dispose(); |
... | ... | @@ -172,7 +189,8 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
172 | 189 | } |
173 | 190 | |
174 | 191 | ///请求数据 |
175 | - void _requestData(RequestDataEvent event,Emitter<TopicPictureState> emitter) async { | |
192 | + void _requestData( | |
193 | + RequestDataEvent event, Emitter<TopicPictureState> emitter) async { | |
176 | 194 | try { |
177 | 195 | await loading(() async { |
178 | 196 | _entity = await ListenDao.process(courseLessonId); |
... | ... | @@ -180,13 +198,14 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
180 | 198 | }); |
181 | 199 | } catch (e) { |
182 | 200 | if (e is ApiException) { |
183 | - showToast(e.message??'请求失败,请检查网络连接'); | |
201 | + showToast(e.message ?? '请求失败,请检查网络连接'); | |
184 | 202 | } |
185 | 203 | } |
186 | 204 | } |
187 | 205 | |
188 | 206 | ///页面切换 |
189 | - void _pageControllerChange(CurrentPageIndexChangeEvent event,Emitter<TopicPictureState> emitter) async { | |
207 | + void _pageControllerChange(CurrentPageIndexChangeEvent event, | |
208 | + Emitter<TopicPictureState> emitter) async { | |
190 | 209 | await closePlayerResource(); |
191 | 210 | debugPrint('翻页 $_currentPage->${event.pageIndex}'); |
192 | 211 | if (_currentPage == _entity?.topics?.length) { |
... | ... | @@ -196,7 +215,7 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
196 | 215 | final topics = _entity?.topics?[_currentPage]; |
197 | 216 | if (topics?.type != 3 && topics?.type != 4) { |
198 | 217 | if (topics?.audioUrl != null) { |
199 | - final urlStr = topics?.audioUrl??''; | |
218 | + final urlStr = topics?.audioUrl ?? ''; | |
200 | 219 | if (urlStr.isNotEmpty) { |
201 | 220 | debugPrint(urlStr); |
202 | 221 | await audioPlayer.play(UrlSource(urlStr)); |
... | ... | @@ -208,13 +227,15 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
208 | 227 | } |
209 | 228 | |
210 | 229 | ///选择 |
211 | - void _selectItemLoad(SelectItemEvent event,Emitter<TopicPictureState> emitter) async { | |
230 | + void _selectItemLoad( | |
231 | + SelectItemEvent event, Emitter<TopicPictureState> emitter) async { | |
212 | 232 | if (_forbiddenWhenCorrect) { |
213 | 233 | return; |
214 | 234 | } |
215 | 235 | _selectItem = event.selectIndex; |
216 | 236 | CourseProcessTopics? topics = _entity?.topics?[_currentPage]; |
217 | - CourseProcessTopicsTopicAnswerList? answerList = topics?.topicAnswerList?[_selectItem]; | |
237 | + CourseProcessTopicsTopicAnswerList? answerList = | |
238 | + topics?.topicAnswerList?[_selectItem]; | |
218 | 239 | if (answerList?.correct == 0) { |
219 | 240 | _playResultSound(false); |
220 | 241 | // showToast('继续加油哦',duration: const Duration(seconds: 2)); |
... | ... | @@ -226,35 +247,32 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
226 | 247 | } |
227 | 248 | |
228 | 249 | ///初始化SDK |
229 | - _initVoiceSdk(XSVoiceInitEvent event,Emitter<TopicPictureState> emitter) async { | |
230 | - methodChannel.invokeMethod('initVoiceSdk',event.data); | |
250 | + _initVoiceSdk( | |
251 | + XSVoiceInitEvent event, Emitter<TopicPictureState> emitter) async { | |
252 | + methodChannel.invokeMethod('initVoiceSdk', event.data); | |
231 | 253 | } |
232 | 254 | |
233 | 255 | ///先声测试 |
234 | - void _voiceXsStart(XSVoiceStartEvent event,Emitter<TopicPictureState> emitter) async { | |
256 | + void _voiceXsStart( | |
257 | + XSVoiceStartEvent event, Emitter<TopicPictureState> emitter) async { | |
235 | 258 | await audioPlayer.stop(); |
236 | 259 | // 调用封装好的权限检查和请求方法 |
237 | - bool result = await permissionCheckAndRequest( | |
238 | - context, | |
239 | - Permission.microphone, | |
240 | - "录音" | |
241 | - ); | |
260 | + bool result = | |
261 | + await permissionCheckAndRequest(context, Permission.microphone, "录音"); | |
242 | 262 | if (result) { |
243 | - methodChannel.invokeMethod( | |
244 | - 'startVoice', | |
245 | - { | |
246 | - 'word': event.testWord, | |
247 | - 'type': event.type, | |
248 | - 'userId': event.userId.toString() | |
249 | - } | |
250 | - ); | |
263 | + methodChannel.invokeMethod('startVoice', { | |
264 | + 'word': event.testWord, | |
265 | + 'type': event.type, | |
266 | + 'userId': event.userId.toString() | |
267 | + }); | |
251 | 268 | _isVoicing = true; |
252 | 269 | emitter(XSVoiceTestState()); |
253 | 270 | } |
254 | 271 | } |
255 | 272 | |
256 | 273 | ///终止评测 |
257 | - void _voiceXsStop(XSVoiceStopEvent event,Emitter<TopicPictureState> emitter) async { | |
274 | + void _voiceXsStop( | |
275 | + XSVoiceStopEvent event, Emitter<TopicPictureState> emitter) async { | |
258 | 276 | methodChannel.invokeMethod('stopVoice'); |
259 | 277 | } |
260 | 278 | |
... | ... | @@ -264,11 +282,12 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
264 | 282 | } |
265 | 283 | |
266 | 284 | ///先声评测结果 |
267 | - void _voiceXsResult(XSVoiceResultEvent event,Emitter<TopicPictureState> emitter) async { | |
285 | + void _voiceXsResult( | |
286 | + XSVoiceResultEvent event, Emitter<TopicPictureState> emitter) async { | |
268 | 287 | final Map args = event.message as Map; |
269 | 288 | final result = args['result'] as Map; |
270 | 289 | final overall = result['overall'].toString(); |
271 | - showToast('测评成功,分数是$overall',duration: const Duration(seconds: 5)); | |
290 | + showToast('测评成功,分数是$overall', duration: const Duration(seconds: 5)); | |
272 | 291 | _isVoicing = false; |
273 | 292 | emitter(XSVoiceTestState()); |
274 | 293 | if (isLastPage()) { |
... | ... | @@ -277,20 +296,23 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
277 | 296 | } |
278 | 297 | |
279 | 298 | // 暂时没用上 |
280 | - void _voicePlayStateChange(VoicePlayStateChangeEvent event,Emitter<TopicPictureState> emitter) async { | |
299 | + void _voicePlayStateChange(VoicePlayStateChangeEvent event, | |
300 | + Emitter<TopicPictureState> emitter) async { | |
281 | 301 | emitter(VoicePlayStateChange()); |
282 | 302 | } |
283 | 303 | |
284 | 304 | // 题目音频播放 |
285 | - void _questionVoicePlay(VoicePlayEvent event,Emitter<TopicPictureState> emitter) async { | |
305 | + void _questionVoicePlay( | |
306 | + VoicePlayEvent event, Emitter<TopicPictureState> emitter) async { | |
286 | 307 | if (_forbiddenWhenCorrect) { |
287 | 308 | return; |
288 | 309 | } |
289 | 310 | _forbiddenWhenCorrect = false; |
290 | 311 | await closePlayerResource(); |
291 | 312 | final topics = _entity?.topics?[_currentPage]; |
292 | - final urlStr = topics?.audioUrl??''; | |
293 | - await audioPlayer.play(UrlSource(urlStr)); | |
313 | + final urlStr = topics?.audioUrl ?? ''; | |
314 | + await audioPlayer.play(UrlSource(urlStr), | |
315 | + balance: 0.0, ctx: AudioContext()); | |
294 | 316 | } |
295 | 317 | |
296 | 318 | Future<void> closePlayerResource() async { |
... | ... | @@ -302,7 +324,8 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
302 | 324 | ///播放选择结果音效 |
303 | 325 | void _playResultSound(bool isCorrect) async { |
304 | 326 | // await audioPlayer.stop(); |
305 | - if (audioPlayer.state == PlayerState.playing && _isResultSoundPlaying == false) { | |
327 | + if (audioPlayer.state == PlayerState.playing && | |
328 | + _isResultSoundPlaying == false) { | |
306 | 329 | _voicePlayState = VoicePlayState.stop; |
307 | 330 | } |
308 | 331 | debugPrint("_playResultSound isCorrect=$isCorrect"); |
... | ... | @@ -324,13 +347,12 @@ class TopicPictureBloc extends BaseSectionBloc<TopicPictureEvent, TopicPictureSt |
324 | 347 | void showStepPage() { |
325 | 348 | ///如果最后一页是语音问答题,评测完后自动翻页 |
326 | 349 | sectionComplete(() { |
327 | - popPage( | |
328 | - data:{ | |
329 | - 'currentStep':currentPage, | |
330 | - 'courseLessonId':courseLessonId, | |
331 | - 'isCompleted': true, | |
332 | - 'nextSection': true | |
333 | - }); | |
350 | + popPage(data: { | |
351 | + 'currentStep': currentPage, | |
352 | + 'courseLessonId': courseLessonId, | |
353 | + 'isCompleted': true, | |
354 | + 'nextSection': true | |
355 | + }); | |
334 | 356 | }, againSectionTap: () { |
335 | 357 | pageController.jumpToPage(0); |
336 | 358 | }); | ... | ... |
lib/pages/reading/bloc/reading_bloc.dart
... | ... | @@ -130,6 +130,9 @@ class ReadingPageBloc |
130 | 130 | "setMethodCallHandler method=${call.method} arguments=${call.arguments}"); |
131 | 131 | if (call.method == 'voiceResult') { |
132 | 132 | //评测结果 |
133 | + await audioPlayer.setAudioContext(AudioContext()); | |
134 | + await audioPlayer.setBalance(0.0); | |
135 | + | |
133 | 136 | add(XSVoiceResultEvent(call.arguments)); |
134 | 137 | return; |
135 | 138 | } |
... | ... | @@ -149,6 +152,9 @@ class ReadingPageBloc |
149 | 152 | if (kDebugMode) { |
150 | 153 | print(call.method == 'voiceEnd' ? '评测结束' : '评测取消'); |
151 | 154 | } |
155 | + await audioPlayer.setAudioContext(AudioContext()); | |
156 | + await audioPlayer.setBalance(0.0); | |
157 | + | |
152 | 158 | _isRecording = false; |
153 | 159 | add(OnXSVoiceStateChangeEvent()); |
154 | 160 | return; |
... | ... | @@ -157,6 +163,9 @@ class ReadingPageBloc |
157 | 163 | if (call.method == 'voiceFail') { |
158 | 164 | //评测失败 |
159 | 165 | _isRecording = false; |
166 | + await audioPlayer.setAudioContext(AudioContext()); | |
167 | + await audioPlayer.setBalance(0.0); | |
168 | + | |
160 | 169 | EasyLoading.showToast('评测失败'); |
161 | 170 | return; |
162 | 171 | } |
... | ... | @@ -276,7 +285,8 @@ class ReadingPageBloc |
276 | 285 | |
277 | 286 | Future<void> _playAudio(String? audioUrl) async { |
278 | 287 | if (audioUrl!.isNotEmpty) { |
279 | - await audioPlayer.play(UrlSource(audioUrl)); | |
288 | + await audioPlayer.play(UrlSource(audioUrl), | |
289 | + balance: 0.0, ctx: AudioContext()); | |
280 | 290 | } |
281 | 291 | } |
282 | 292 | ... | ... |