import 'dart:async'; import 'package:audioplayers/audio_cache.dart'; import 'package:audioplayers/audioplayers.dart'; import 'package:synchronized/synchronized.dart'; typedef void Stoppable(); /// An AudioPool is a provider of AudioPlayers that leaves them pre-loaded to minimize delays. /// /// All AudioPlayers loaded are for the same [sound]. If you want multiple sounds use multiple [AudioPool]. /// Use this class if you'd like have extremely quick firing, repetitive and simultaneous sounds, like shooting a laser in a fast-paced spaceship game. class AudioPool { AudioCache cache; Map currentPlayers = {}; List availablePlayers = []; String sound; bool repeating; int minPlayers, maxPlayers; Lock _lock = Lock(); AudioPool(this.sound, {this.repeating = false, this.maxPlayers = 1, this.minPlayers = 1, String prefix = 'audio/sfx/'}) { cache = AudioCache(prefix: prefix); } void init() async { for (int i = 0; i < minPlayers; i++) { availablePlayers.add(await _createNewAudioPlayer()); } } Future start({double volume = 1.0}) async { return _lock.synchronized(() async { if (availablePlayers.isEmpty) { availablePlayers.add(await _createNewAudioPlayer()); } AudioPlayer player = availablePlayers.removeAt(0); currentPlayers[player.playerId] = player; await player.setVolume(volume); await player.resume(); Stoppable stop = () { _lock.synchronized(() async { AudioPlayer p = currentPlayers.remove(player.playerId); p.completionHandler = null; await p.stop(); if (availablePlayers.length >= maxPlayers) { await p.release(); } else { availablePlayers.add(p); } }); }; if (repeating) { player.completionHandler = player.resume; } else { player.completionHandler = stop; } return stop; }); } Future _createNewAudioPlayer() async { AudioPlayer player = AudioPlayer(); String url = (await cache.load(sound)).path; await player.setUrl(url); await player.setReleaseMode(ReleaseMode.STOP); return player; } }