ardera / flutter-pi

A light-weight Flutter Engine Embedder for Raspberry Pi that runs without X.
MIT License
1.48k stars 153 forks source link

Audio Devices Quickly Being Exhausted #380

Open MatthewJones517 opened 4 months ago

MatthewJones517 commented 4 months ago

This is a follow-up to my previous issue #379. After the merging of PR #345 the audio does indeed work. However I'm getting a new issue.

I'm using Flame, and triggering a bunch of audio sfx in short succession. The first few work fine, then it goes silent and I get the following error:

AL lib: (EE) ALCplaybackAlsa_open: Could not open playback device 'default': Device or resource busy

Initially I thought Flame just wasn't releasing the device after playing the sfx, but it works fine on a variety of other devices. This includes my Ubuntu development box.

This makes me think that flutter-pi isn't properly releasing the audio resources when asked. I can provide a code sample if necessary.

ardera commented 4 months ago

Ah I see why, audioplayers ReleaseMode.release is not implemented in flutter-pi. So the native audio player is not disposed on end of playback, as it should. Though should not be hard to implement

MatthewJones517 commented 4 months ago

Thanks so much for looking at this! I was going to do more debugging tonight after work, but it appears you already found the root cause. :)

ardera commented 4 months ago

Okay, seems like iOS doesn't implement it either (https://github.com/bluefireteam/audioplayers/issues/56), still would be good to have in flutter-pi. But maybe you can work around for now using AudioPool: https://pub.dev/documentation/audioplayers/latest/audioplayers/AudioPool-class.html

MatthewJones517 commented 4 months ago

AudioPool was the next thing I was going to try. I suspect it will be successful, and is probably the right call for my use case regardless. :)

I unfortunately will be away for some family business for a week starting tomorrow, so I may or may not have time to test this theory. :/

Thanks for the suggestion!

MatthewJones517 commented 3 months ago

AudioPool does allow the clips to be played. That being said, any audio trigger generates the following warning:

plugins/audioplayers/player.c: Could not query current position.

The audio still plays correctly, but the warning doesn't appear on my Ubuntu devbox.

ardera commented 3 months ago

Interesting, in your test app, do you have a way to check the current playback position reported by the audio player? Can you verify if it matches the actual playback position of the audio?

MatthewJones517 commented 3 months ago

Unfortunately not. They're just sound effects being kicked off by my "game". (It uses flame and flame_audio, but calling this thing a game is too generous 😂)

In researching the error, it appears to happen when audio_players are used outside of a context. So is it possible that flutter-pi isn't properly providing context to audio_players?

DoumanAsh commented 3 months ago

plugins/audioplayers/player.c: Could not query current position.

This is often the case for short sound effecs because you effectively cannot get correction position when your overall duration is within second or two (by the time you get position, playback ended) I wouldn't consider it critical issue, but more to do with callback nature of player itself This is likely happens at the end of audio

This makes me think that flutter-pi isn't properly releasing the audio resources when asked. I can provide a code sample if necessary.

I'm not sure how flame works, but one way to clean up resources is to delete player via manual dispose call

To release resources, audioplayers make release call https://github.com/ardera/flutter-pi/blob/master/src/plugins/audioplayers/plugin.c#L78C9-L78C29

But this is to clean up whole player

The reason you get exhaust error is probably of incorrect usage of AudioPlayer within that flame thingy

I remember encountering this issue by constantly creating new player and playing sound one time. You obviously will reach issue because VM nature does not allow to quickly dispose of temporary player (especially on raspberry pi due to its constrained nature)

So the only proper solution is to make sure you either re-use player or call AudioPlayer::dispose every time you no longer need instance

https://github.com/flame-engine/flame/blob/4e6968a05c659aae09e9f613870c6e5b326f4b44/packages/flame_audio/lib/flame_audio.dart#L48-L63

I suspect this is problematic place so it is matter of where they use it and whether you have access to AudioPlayer instance to properly clean it up. (They actually have Bgm class that properly uses audio player so I would recommend to use it as inspiration)

Ah I see why, audioplayers ReleaseMode.release is not implemented in flutter-pi. So the native audio player is not disposed on end of playback, as it should. Though should not be hard to implement

Unfortunately it is the same as linux implementation 😄 release mode is really thing for android AFAIK I'm not familiar with gstreamer, but I would assume resources are supposed to be allocated to player instance and then you clean it up by destroying instance