You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:30:11