bluefireteam / audioplayers

A Flutter package to play multiple audio files simultaneously (Android/iOS/web/Linux/Windows/macOS)
https://pub.dartlang.org/packages/audioplayers
MIT License
2.01k stars 845 forks source link

MediaPlayer throws (sometimes) IllegalStateException when playing sound #1331

Closed pitazzo closed 1 year ago

pitazzo commented 1 year ago

Checklist

Sometimes, at the time of playing a sound, a Platform exception regarding MediaPlayer is raised.

Current bug behaviour

At the time of playing a sound, following exception is thrown:

Fatal Exception: java.lang.IllegalStateException:
       at android.media.MediaPlayer._prepare(MediaPlayer.java)
       at android.media.MediaPlayer.prepare(MediaPlayer.java:1332)
       at xyz.luan.audioplayers.player.MediaPlayerPlayer.prepare(MediaPlayerPlayer.kt:89)
       at xyz.luan.audioplayers.player.WrappedPlayer.stop(WrappedPlayer.kt:185)
       at xyz.luan.audioplayers.player.WrappedPlayer.onCompletion(WrappedPlayer.kt:248)
       at xyz.luan.audioplayers.player.MediaPlayerPlayer.createMediaPlayer$lambda-5$lambda-1(MediaPlayerPlayer.kt:17)
       at xyz.luan.audioplayers.player.MediaPlayerPlayer.$r8$lambda$3fK1i48Yert5dbg2Q8ZiB5tiKHg(MediaPlayerPlayer.kt)
       at xyz.luan.audioplayers.player.MediaPlayerPlayer$$InternalSyntheticLambda$0$296514634a2b58642f47b4fbcf9ba89cf596f2246040028ce119ddff1b7069d4$1.onCompletion(MediaPlayerPlayer.java:2)
       at android.media.MediaPlayer$EventHandler.handleMessage(MediaPlayer.java:3521)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loop(Looper.java:236)
       at android.app.ActivityThread.main(ActivityThread.java:7912)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)

The stack trace was this:

#0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653)
#1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:296)
<asynchronous suspension>
#2      AudioPlayer.play (package:audioplayers/src/audioplayer.dart:123)
<asynchronous suspension>
#3      AudioplayersSoundService.play (package:mxa_flutter_core/services/sound/audioplayers_sound_service.dart:76)
<asynchronous suspension>

As it was reported by our remote crash reporting tool, we do not know whether the sound is actually played.

Expected behaviour

No exception should be thrown. Sound should play.

Steps to reproduce

Unfortunately, we have not been able to reproduce the issue at the office. From the metrics we get from our crash reporting tool, the issue is quite rare compared to the number of sounds played with no problems. I've attached the code of our real service in charge of playing the sound.

Code sample ```dart import 'package:audioplayers/audioplayers.dart'; import 'package:injectable/injectable.dart'; import 'package:mxa_flutter_core/services/logger/logger_service.dart'; import 'package:mxa_flutter_core/services/persistence/persistence_service.dart'; import 'package:mxa_flutter_core/services/sound/sound_config.dart'; import 'package:mxa_flutter_core/services/sound/sound_service.dart'; @Singleton(as: SoundService) class AudioplayersSoundService extends SoundService { final PersistenceService _persistenceService; final LoggerService _loggerService; final SoundConfig _soundConfig; final AudioPlayer _player = AudioPlayer(); final Map _sources = {}; AudioplayersSoundService( this._persistenceService, this._loggerService, this._soundConfig, ) : super(_soundConfig) { AudioPlayer.global.setGlobalAudioContext( AudioContext( iOS: AudioContextIOS( defaultToSpeaker: true, category: AVAudioSessionCategory.playback, options: [], ), android: AudioContextAndroid( isSpeakerphoneOn: true, stayAwake: true, contentType: AndroidContentType.sonification, usageType: AndroidUsageType.notificationCommunicationInstant, audioFocus: null, ), ), ); } @factoryMethod static Future setup( SoundConfig soundConfig, PersistenceService persistenceService, LoggerService loggerService, ) async { final service = AudioplayersSoundService( persistenceService, loggerService, soundConfig, ); await service._loadAssetSounds(); await service._loadLocalSounds(); return service; } @override Future play(String name, {bool loop = false, String? fallback}) async { if (!_sources.containsKey(name)) { _loggerService.error( 'AudioplayersSoundService', 'Trying to play unknown sound $name, will try playing $fallback', ); if (fallback != null) { play(fallback, loop: loop); } return; } await _player.stop(); _player.setReleaseMode(loop ? ReleaseMode.loop : ReleaseMode.stop); await _player.play( _sources[name]!, volume: 1, mode: PlayerMode.mediaPlayer, ); } @override Future reload() async { await _loadLocalSounds(); } @override Future stop(String name) async { await _player.stop(); } Future _loadAssetSounds() async { for (final sound in _soundConfig.assetSounds.entries) { final bytes = await AudioCache.instance.loadAsBytes( 'sounds/${sound.value}', ); _sources[sound.key] = BytesSource(bytes); } } Future _loadLocalSounds() async { for (final directory in _soundConfig.localSoundsDirectories) { final existsResult = await _persistenceService.existsDirectory(directory); if (!(existsResult.data ?? false)) { continue; } final pathsResult = await _persistenceService.filesAtDirectory(directory); if (pathsResult.isFailure) { _loggerService.error( 'AudioplayersSoundService', 'Unable to get the files at $directory due to ${pathsResult.error}', ); continue; } for (final path in pathsResult.data!) { final fileName = path.split('/').last; final dataResult = await _persistenceService.readFile( '$directory/$fileName', ); if (dataResult.isFailure) { _loggerService.error( 'AudioplayersSoundService', 'Unable to read file $path due to ${dataResult.error}', ); continue; } final soundName = fileName.split('.').first; _sources[soundName] = BytesSource(dataResult.data!); _loggerService.info( 'AudioplayersSoundService', 'Successfully loaded sound $soundName from $path', ); } } } } ```

Logs

Full Logs Flutter doctor: ``` [✓] Flutter (Channel stable, 3.3.4, on macOS 13.0.1 22A400 darwin-arm, locale es-ES) • Flutter version 3.3.4 on channel stable at /Users/pitazzo/SDKs/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision eb6d86ee27 (7 weeks ago), 2022-10-04 22:31:45 -0700 • Engine revision c08d7d5efc • Dart version 2.18.2 • DevTools version 2.15.0 [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) • Android SDK at /Users/pitazzo/SDKs/android • Platform android-33, build-tools 30.0.3 • ANDROID_HOME = /Users/pitazzo/SDKs/android • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 14.1) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 14B47b • CocoaPods version 1.11.2 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2021.2) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840) [✓] VS Code (version 1.73.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.52.0 [✓] Connected device (3 available) • M2006C3LG (mobile) • RWYDO7Z9IRAQMBDU • android-arm • Android 10 (API 29) • macOS (desktop) • macos • darwin-arm64 • macOS 13.0.1 22A400 darwin-arm • Chrome (web) • chrome • web-javascript • Google Chrome 106.0.5249.119 [✓] HTTP Host Availability • All required HTTP hosts are available • No issues found! ```

Environment information

Platform 1: android

Gustl22 commented 1 year ago

Thank you for your detailed report! Unfortunately I don't have the time to try until the error is thrown. If you have clear reproduction steps, when the error occurs, we can help you much better and fix it.

FYI: #1322

pitazzo commented 1 year ago

Yeah, I know that with no steps, this is like looking for a needle in a haystack. Will follow the other issue, as seems to be the same problem. I do not know how I did not find out that issue without opening this one. Thanks!

Zhengbledor commented 1 year ago

This error will be triggered when playing audio with play () for several times in a short time.

Gustl22 commented 1 year ago

This is most probably exactly the same issue I experienced here