Closed mountaindu closed 3 months ago
@mountaindu ,
Flutter Sound 9.4.14 is released. It fixes something inside method_channel_flutter_sound_player.dart and method_channel_flutter_sound_recorder.dart.
Please let me known if this fixes your problem or if not, send the new logs.
Yes that works, thanks for the patch!
I’m running into a separate similar issue now in the MethodChannelPlayer when closing the player. This happens when calling FlutterSoundPlayer.closePlayer()
both when the player is actively playing audio or inactive.
Here's the stack trace:
FlutterSoundPlayerPlatform.getSession (/Users/alexdu/.pub-cache/hosted/pub.dev/flutter_sound_platform_interface-9.4.14/lib/flutter_sound_player_platform_interface.dart:110)
MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (/Users/alexdu/.pub-cache/hosted/pub.dev/flutter_sound_platform_interface-9.4.14/lib/method_channel_flutter_sound_player.dart:53)
new Future.<anonymous closure> (/Users/alexdu/flutter/bin/cache/pkg/sky_engine/lib/async/future.dart:257)
Timer._createTimer.<anonymous closure> (/Users/alexdu/flutter/bin/cache/pkg/sky_engine/lib/_internal/vm/lib/timer_patch.dart:18)
_Timer._runTimers (/Users/alexdu/flutter/bin/cache/pkg/sky_engine/lib/_internal/vm/lib/timer_impl.dart:398)
_Timer._handleMessage (/Users/alexdu/flutter/bin/cache/pkg/sky_engine/lib/_internal/vm/lib/timer_impl.dart:429)
_RawReceivePort._handleMessage (/Users/alexdu/flutter/bin/cache/pkg/sky_engine/lib/_internal/vm/lib/isolate_patch.dart:184)
And logs prior to.
flutter: │ #0 FlutterSoundPlayer.log (package:flutter_sound/public/flutter_sound_player.dart:358:13)
flutter: │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:129:21)
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 iOS: invokeMethod stopPlayerCompleted - state=0
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 FlutterSoundPlayer.stopPlayerCompleted (package:flutter_sound/public/flutter_sound_player.dart:294:13)
flutter: │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:103:21)
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 ---> stopPlayerCompleted: true
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 FlutterSoundPlayer.stopPlayerCompleted (package:flutter_sound/public/flutter_sound_player.dart:309:13)
flutter: │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:103:21)
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 <--- stopPlayerCompleted: true
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 FlutterSoundPlayer.log (package:flutter_sound/public/flutter_sound_player.dart:358:13)
flutter: │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:129:21)
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 IOS:<-- stopPlayer
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 FlutterSoundPlayer.log (package:flutter_sound/public/flutter_sound_player.dart:358:13)
flutter: │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:129:21)
├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 IOS:<-- stopPlayer
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 FlutterSoundPlayer.log (package:flutter_sound/public/flutter_sound_player.dart:358:13)
flutter: │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:129:21)
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 iOS: invokeMethod needSomeFood - state=0
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
flutter: │ #0 FlutterSoundPlayer._closeAudioSession (package:flutter_sound/public/flutter_sound_player.dart:600:13)
flutter: │ #1 <asynchronous suspension>
flutter: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
flutter: │ 🐛 FS:<--- closeAudioSession
flutter: └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I am going to look at that tomorrow. Thank you for having sent the logs : this is really helpful for debugging.
No, this is not the same bug already fixed. I already fixed the bug for all API verbs, both for Player and Recorder in 9.4.14
Are you sure that you call stopPlayer() in the main Isolate ?
I'm not sure what you mean by "main Isolate" but i don't think the call to stopPlayer()
is relevant as it's the closePlayer
that's causing issues. I can repro by doing a simple call sequence of:
await _soundPlayer.openPlayer();
await _soundPlayer.startPlayerFromStream(...)
await _soundPlayer.closePlayer();
I will look tomorrow. The logs show that stopPlayer is called correctly by close player. Then stop player returns and then closePlayer returns. This seems ok. But I don’t like that iOS asks for some audio data just after it is closed. This is not correct.
Also I think that you have a timer that calls flutter sound. I want to be sure that this timer is fired in the main thread.
This is not really a crash. Flutter Sound throws an exception but you don't catch it. The problem is that someone is trying to access the player after it has been closed. It seems that it is from a timer.
Playback_with_backpressure
:
Future<void> feedHim(Uint8List buffer) async {
var lnData = 0;
var totalLength = buffer.length;
while (totalLength > 0 && !_mPlayer!.isStopped) {
var bsize = totalLength > blockSize ? blockSize : totalLength;
await _mPlayer!
.feedFromStream(buffer.sublist(lnData, lnData + bsize)); // await !!!!
lnData += bsize;
totalLength -= bsize;
}
}
playback without backpressure
:
void feedHim(Uint8List data) {
var start = 0;
var totalLength = data.length;
while (totalLength > 0 && !_mPlayer.isStopped) {
var ln = totalLength > tBlockSize ? tBlockSize : totalLength;
_mPlayer.foodSink!.add(FoodData(data.sublist(start, start + ln)));
totalLength -= ln;
start += ln;
}
}
_mPlayer.foodSink!.add(FoodData(someData));
?await _mPlayer!.feedFromStream(someData)); // await !!!!
?sky_engine/lib/ui/hooks.dart:344
in your code ?Thanks for the investigation, I'm using a StreamSubscription which I believe uses Timers under the hood so you're right that there could be a bad access there. Is there some check on the FlutterSoundPlayer object that I can use to tell whether it's been closed? Or should I manage that state myself.
While I'm here, two other things I'm curious about --
1) The backpressure variant .feedFromStream()
causes a native iOS crash. I can provide the stack trace here later.
2) When using the foodSink version, are the sinks opearting as a queue? When I add a stopPlayer event to the sink, my last audio chunk doesn't play.
Here is my rough code:
class AudioStreamPlayer {
final FlutterSoundPlayer _soundPlayer = FlutterSoundPlayer();
StreamSubscription<Uint8List?>? _audioSubscription;
bool _isInit = false;
Future<bool> init() async {
try {
await _soundPlayer.openPlayer();
_isInit = true;
return true;
} catch (e) {
FlutterError.reportError(FlutterErrorDetails(
exception: e,
stack: StackTrace.current,
library: "AudioStreamPlayer.init",
));
return false;
}
}
Future<void> start(ServerTypedJsonStreamWrapper streamWrapper,
Stream<Uint8List?> audioStream) async {
if (!_isInit) {
await init();
}
if (_soundPlayer.isStopped) {
await _soundPlayer.startPlayerFromStream(
codec: Codec.pcm16,
numChannels: 1,
sampleRate: 16000,
bufferSize: 20480,
);
}
_audioSubscription = audioStream.listen((audioBytes) {
if (audioBytes != null) {
int lnData = 0;
int totalLength = audioBytes.length;
while (totalLength > 0 && !_soundPlayer.isStopped) {
var bsize = totalLength > blockSize ? blockSize : totalLength;
// Not using backpressure. Should be using async .feedFromStream()
// instead of this foodSink thing but it crashed when I try.
_soundPlayer.foodSink!
.add(FoodData(audioBytes.sublist(lnData, lnData + bsize)));
lnData += bsize;
totalLength -= bsize;
}
}
}, onDone: () {
// Hm this cuts off the last audiobyte chunk from playing:
// _soundPlayer.foodSink!.add(FoodEvent(() {
// _soundPlayer.stopPlayer();
// }));
});
}
void close() {
_soundPlayer.closePlayer();
}
Future<void> dispose() async {
await _soundPlayer.closePlayer();
if (_audioSubscription != null) {
await _audioSubscription!.cancel();
}
}
}
I looked to your code very rapidly. My first answer without having looked seriously to your code:
I am actually rewriting all the code for streams. First on iOS. This is a major work, and I am very slow. And difficult for me to code this v10.0 because I spend too much time on flutter sound maintenance.
@mountaindu : Please, could you try new version 9.4.19 of Flutter Sound ? I protect the internal feed()
function against a stopPlayer()
during the loop.
@mountaindu : Please, could you try new version 9.4.19 of Flutter Sound ? I protect the internal
feed()
function against astopPlayer()
during the loop.
It seems that this patch fixed also the Play From Stream With Back-pressure()
. You are not concerned but I wanted to let you know that this patch seems OK.
Has the patch updated the underlying min iOS version for flutter_sound_core? I'm getting the following error when trying to upgrade to the new version:
[!] CocoaPods could not find compatible versions for pod "flutter_sound_core":
In snapshot (Podfile.lock):
flutter_sound_core (= 9.4.14)
In Podfile:
flutter_sound (from `.symlinks/plugins/flutter_sound/ios`) was resolved to 9.4.19, which
depends on
flutter_sound_core (= 9.4.19)
Specs satisfying the `flutter_sound_core (= 9.4.14), flutter_sound_core (= 9.4.19)` dependency were
found, but they required a higher minimum deployment target.
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:317:in
`raise_error_unless_state'
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:299:in `block in
unwind_for_conflict'
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:297:in `tap'
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:297:in
`unwind_for_conflict'
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:257:in
`process_topmost_state'
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:182:in `resolve'
/Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolver.rb:43:in `resolve'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/resolver.rb:94:in `resolve'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:1082:in `block
in resolve_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/user_interface.rb:64:in `section'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:1080:in
`resolve_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer/analyzer.rb:125:in `analyze'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:422:in `analyze'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:244:in `block in
resolve_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/user_interface.rb:64:in `section'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:243:in
`resolve_dependencies'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/installer.rb:162:in `install!'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/command/install.rb:52:in `run'
/Library/Ruby/Gems/2.6.0/gems/claide-1.1.0/lib/claide/command.rb:334:in `run'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/lib/cocoapods/command.rb:52:in `run'
/Library/Ruby/Gems/2.6.0/gems/cocoapods-1.15.2/bin/pod:55:in `<top (required)>'
/usr/local/bin/pod:23:in `load'
/usr/local/bin/pod:23:in `<main>'
Error output from CocoaPods:
↳
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin23/rbconf
ig.rb:21: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/universal-darwin23/rbconf
ig.rb:21: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777
Error: The pod "flutter_sound_core" required by the plugin "flutter_sound" requires a higher minimum
iOS deployment version than the plugin's reported minimum version.
To build, remove the plugin "flutter_sound", or contact the plugin's developers for assistance.
Error running pod install
No, I did not do that intentionally. I am going to fix that immediately. Just wait an hour or so.
[!] CocoaPods could not find compatible versions for pod "flutter_sound_core": In snapshot (Podfile.lock): flutter_sound_core (= 9.4.14)
This is not good. Do you use your own version of flutter_sound_core ? it should be 9.4.19. Flutter_sound_core version and Flutter_sound version are synchronised to simplify the maintenance
Ah needed to delete some stale iOS artifacts, all is fixed now thank you!
Feel free to close this issue out but one more small request while I’m here: it'd be really great if there was some "isActivelyPlaying" listener for the streaming use case (i.e. when there's no more Food
events playing). This seems like it’d be relatively simple change and would be a great feature addition. In my particular use case, we want to render a UI element only when audio is playing.
Not sure that it will answer to your need, but there is something which can be useful when working with PlayFromStreamWithoutBackpressure : You add audio data to the stream without waiting that the player is ready. So the data are buffered by the stream. But you don’t know when the data are really played. With Flutter sound, you can insert in your sink not only audio data, but also "events". Those events are put into the stream, and will be consumed by flutter sound when all the previous audio data are also consumed (played). Then Flutter sound call a playback to the app, to tell it that it is now synchronized with your checkpoint.
The example uses this mechanism to know that all the previous data are consumed (played) and that it is ok to close the player.
_mPlayer.foodSink!.add(FoodEvent(() async {
await _mPlayer.stopPlayer();
setState(() {});
}));
My explanation is hard, but the mechanism is really simple. The stream is composed with several data, and checkpoints in the middle. When the checkpoint is consumed your callback is fired.
If you have questions, don’t hesitate to tell me.
Note that the events (the markers) that you insert into your stream are not played. This are just indicators to fire a callback when consumed
Not also that when you receive your callback, it does not mean that the stream is empty because you could have posted new data after the marker. If you need to know that, I can implement it. Simple.
I think a little bit more on your needs. I could implement a back stream. I will post an event each time the device is ready to play something. You will receive on this stream many events during the playback. If the playback stop (because all the data has been played and the app has not sent new data), then the stream will be quiet until the app send new data.
Is it something useful ?
If the foodevent executes after the last audio has been played, that'd fit my needs but I think there's a bug/edge case. The problem I saw (you can see it commented out in my code here) is that adding the stopPlayer()
call in the food event ends up cutting the last audio chunk.
Without diving into the code, my guess is that it's because the last audio element gets popped from the Food
stream to start playing and then the stopPlayer()
event gets popped as well, but executes async before the last audio element finishes playing.
I could implement a back stream. I will post an event each time the device is ready to play something. You will receive on this stream many events during the playback. If the playback stop (because all the data has been played and the app has not sent new data), then the stream will be quiet until the app send new data.
This wouldn't be quite ideal. The problem is the as a listener to the stream, I don't know how frequently events are coming back or if there's any guarantees there: the stream could be quiet for a while but maybe there's been something wrong downstream.
I think I basically want a callback once the underlying buffer finishes playing in this callback:
Yes, I think that the actual API is enough for you. Yes, there is a problem with the last buffer: I call the callback before it is really played. This is bad and I am going to try to find a solution for that.
@mountaindu : I added a new parameter for Start Player From Stream in Flutter Sound 9.6.0
: whenFinished:
.
This call back is called when our own buffers are empty.
Unfortunately I cannot do anything for the buffers managed by the device itself.
Eventually you can diminish the buffer size, but be careful : if too small you may loose some audio packets, and it will increase the CPU load.
I did some tests and it seems to work correctly but the code is tricky and you will have to test that it works well. Please let me know if it is OK for you.
Just did a little testing and it works great, exactly what I need -- thanks again!
@Larpoux ah actually the whenFinished
callback doesn't seem to be working on Android, seeing this both on sim and on device. iOS works well.
Another Android-specific issue I'm seeing is that replaying after closing (specifically init
or startPlayerFromStream
) is a no-op with no debug logs printed. Does having a singleton sound player object not work on Android?
final FlutterSoundPlayer _soundPlayer = FlutterSoundPlayer()
await _soundPlayer.openPlayer();
await _soundPlayer.startPlayerFromStream(...)
_soundPlayer.foodSink!.add(...) // This plays audio normally
await _soundPlayer.closePlayer();
// Both of these actions do nothing on Android
await _soundPlayer.openPlayer();
await _soundPlayer.startPlayerFromStream(...)
Some logs from the closeplayer call.
I/flutter ( 5307): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5307): │ #0 FlutterSoundPlayer.stopPlayerCompleted (package:flutter_sound/public/flutter_sound_player.dart:313:13)
I/flutter ( 5307): │ #1 MethodChannelFlutterSoundPlayer.channelMethodCallHandler.<anonymous closure> (package:flutter_sound_platform_interface/method_channel_flutter_sound_player.dart:103:21)
I/flutter ( 5307): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 5307): │ 🐛 ---> stopPlayerCompleted: true
I/flutter ( 5307): └────────────────────────────────────────────────────────I/flutter ( 5307): ┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I/flutter ( 5307): │ #0 FlutterSoundPlayer._closeAudioSession (package:flutter_sound/public/flutter_sound_player.dart:619:13)
I/flutter ( 5307): │ #1 <asynchronous suspension>
I/flutter ( 5307): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
I/flutter ( 5307): │ 🐛 FS:<--- closeAudioSession
I/flutter ( 5307): └───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
I am going to look to that. I am not surprised that the things are not going for Android. Thank you for your tests.
OK : there is a bug on closePlayer(). At least on Android.
I am going to fix it.
But, I think that your code can be improved :
Do not close the player if you don't have finished everything with it.
Just do some startPlayer()
and stopPlayer()
When you have finished with your player (probably in dispose() ) you can close it.
@override
void dispose() {
_mPlayer.stopPlayer();
_mPlayer.closePlayer();
super.dispose();
}
Do not close the player if you don't have finished everything with it. Just do some
startPlayer()
andstopPlayer()
When you have finished with your player (probably in dispose() ) you can close it.
Hey is this still a problem? I also have problems with closePlayer
. When i call this in another method, then the method will stop at this line, e.g.:
Future<void> disableAudio() async {
await _audioPlayer?.stopPlayer();
await _audioPlayer?.closePlayer();
// The following code is never reached
await _audioRecorder?.stopRecorder();
await _audioRecorder?.closeRecorder();
}
Recently, I modified closePlayer()
and closeRecorder()
so they will not stick ont the semaphore.
I suggest to close this issue, and you will create a new issue if you still have problems in 9.10.4
Flutter Sound Version :
FULL or LITE flavor ? Full
Important: Result of the command :
flutter pub deps | grep flutter_sound
├── flutter_sound 9.4.13 │ ├── flutter_sound_platform_interface 9.4.13 │ ├── flutter_sound_web 9.4.13 │ │ ├── flutter_sound_platform_interface...Severity
Crash ? Yes
Result is not what expected ? Yes
Cannot build my App ? No
Minor issue ? No
Platforms you faced the error
iOS ? Yes
Android ? Yes
Flutter Web ? N/A
Emulator ? Yes
Real device ? Yes
Describe the bug Simply calling
openPlayer()
causes an exception: "Null check operator used on a null value"Call stack:
My code is quite straightforward:
To Reproduce Steps to reproduce the behavior:
See error
Logs!!!!