Plugin.Maui.Audio在Android平台播放超40个音频时无法发声
问题分析与解决方案
你遇到的问题大概率是Android系统音频轨道数量限制导致的。Android默认对同时活跃的音频轨道数量有上限(通常在40左右),你的代码会为每个音频创建一个AsyncAudioPlayer实例并长期保存在静态字典中,当实例数量达到系统上限后,新创建的播放器无法获取音频资源,因此出现无声现象且无异常抛出。
解决方案
1. 复用播放器实例
不需要为每个音频单独创建播放器,可复用同一个播放器加载不同音频流:
public static class Helper { // 复用单个播放器实例 private static AsyncAudioPlayer? _reusablePlayer; public static async Task PlaySound(string s) { var sndStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Chitaika.Resources.Sounds." + s + ".wav"); if (sndStream == null) return; if (_reusablePlayer == null) { _reusablePlayer = AudioManager.Current.CreateAsyncPlayer(sndStream); } else { // 重置播放器并加载新的音频流 await _reusablePlayer.StopAsync(); _reusablePlayer.Dispose(); _reusablePlayer = AudioManager.Current.CreateAsyncPlayer(sndStream); } await _reusablePlayer.PlayAsync(CancellationToken.None); } }
2. 按需释放不常用的播放器
如果必须保留多个播放器,可在达到数量阈值时清理不活跃的实例:
public static class Helper { public static Dictionary<string, AsyncAudioPlayer> players = []; // 设定最大播放器数量阈值(低于系统上限) private const int MaxPlayers = 35; public static async Task PlaySound(string s) { if (players.ContainsKey(s)) { await players[s].PlayAsync(CancellationToken.None); return; } // 达到阈值时移除最早添加的播放器 if (players.Count >= MaxPlayers) { var oldestKey = players.Keys.First(); players[oldestKey].Dispose(); players.Remove(oldestKey); } var snd = Assembly.GetExecutingAssembly().GetManifestResourceStream("Chitaika.Resources.Sounds." + s + ".wav"); if (snd == null) return; var p = AudioManager.Current.CreateAsyncPlayer(snd); players.Add(s, p); await p.PlayAsync(CancellationToken.None); } }
3. 播放完成后自动释放资源
如果音频播放完成后不再需要,可在播放结束时自动释放播放器:
public static class Helper { public static async Task PlaySound(string s) { var snd = Assembly.GetExecutingAssembly().GetManifestResourceStream("Chitaika.Resources.Sounds." + s + ".wav"); if (snd == null) return; var p = AudioManager.Current.CreateAsyncPlayer(snd); // 播放完成后自动释放资源 p.PlaybackEnded += (sender, args) => { (sender as AsyncAudioPlayer)?.Dispose(); }; await p.PlayAsync(CancellationToken.None); } }
关键注意事项
AsyncAudioPlayer实例持有系统音频资源,长期不释放会耗尽系统音频轨道配额。- 每次创建新播放器前,必须确保旧播放器已调用
Dispose()方法释放资源。 - 若需要频繁切换音频,复用单个播放器是资源效率最高的方案。
内容的提问来源于stack exchange,提问作者Mike Tsayper
相关产品推荐
相关产品推荐

