Skip to content
34 changes: 29 additions & 5 deletions packages/audioplayers/lib/src/audio_pool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,38 @@ class AudioPool {
/// returned to the pool.
final int maxPlayers;

/// Whether the players in this pool use low latency mode.
final PlayerMode playerMode;

/// Lock to synchronize access to the pool.
final Lock _lock = Lock();

AudioPool._({
required this.minPlayers,
required this.maxPlayers,
required this.source,
required this.audioContext,
this.playerMode = PlayerMode.mediaPlayer,
AudioCache? audioCache,
}) : audioCache = audioCache ?? AudioCache.instance;

/// Creates an [AudioPool] instance with the given parameters.
/// You will have to manage disposing the players if you choose
/// PlayerMode.lowLatency.
static Future<AudioPool> create({
required Source source,
required int maxPlayers,
AudioCache? audioCache,
AudioContext? audioContext,
int minPlayers = 1,
PlayerMode playerMode = PlayerMode.mediaPlayer,
}) async {
final instance = AudioPool._(
source: source,
audioCache: audioCache,
maxPlayers: maxPlayers,
minPlayers: minPlayers,
playerMode: playerMode,
audioContext: audioContext,
);

Expand All @@ -82,16 +91,19 @@ class AudioPool {
required int maxPlayers,
AudioCache? audioCache,
int minPlayers = 1,
PlayerMode playerMode = PlayerMode.mediaPlayer,
}) async {
return create(
source: AssetSource(path),
audioCache: audioCache,
minPlayers: minPlayers,
maxPlayers: maxPlayers,
playerMode: playerMode,
);
}

/// Starts playing the audio, returns a function that can stop the audio.
/// You must dispose the audio player yourself if using PlayerMode.lowLatency.
Future<StopFunction> start({double volume = 1.0}) async {
return _lock.synchronized(() async {
if (availablePlayers.isEmpty) {
Expand All @@ -102,13 +114,13 @@ class AudioPool {
await player.setVolume(volume);
await player.resume();

late StreamSubscription<void> subscription;
StreamSubscription<void>? subscription;

Future<void> stop() {
return _lock.synchronized(() async {
final removedPlayer = currentPlayers.remove(player.playerId);
if (removedPlayer != null) {
subscription.cancel();
subscription?.cancel();
await removedPlayer.stop();
if (availablePlayers.length >= maxPlayers) {
await removedPlayer.release();
Expand All @@ -119,14 +131,19 @@ class AudioPool {
});
}

subscription = player.onPlayerComplete.listen((_) => stop());
if (playerMode != PlayerMode.lowLatency) {
subscription = player.onPlayerComplete.listen((_) => stop());
}

return stop;
});
}

Future<AudioPlayer> _createNewAudioPlayer() async {
final player = AudioPlayer()..audioCache = audioCache;

await player.setPlayerMode(playerMode);

if (audioContext != null) {
await player.setAudioContext(audioContext!);
}
Expand All @@ -136,6 +153,13 @@ class AudioPool {
}

/// Disposes the audio pool. Then it cannot be used anymore.
Future<void> dispose() =>
Future.wait(availablePlayers.map((e) => e.dispose()));
Future<void> dispose() async {
// Dispose all players
await Future.wait([
...currentPlayers.values.map((e) => e.dispose()),
...availablePlayers.map((e) => e.dispose()),
]);
currentPlayers.clear();
availablePlayers.clear();
}
}
Loading