Xamarin.Android中AudioTrack.Flush异常行为及原因咨询
嘿,这个问题我之前碰到过类似的场景,本质是Android AudioTrack的Flush()操作并非完全同步执行导致的,咱们拆解下背后的原因:
Android的AudioTrack.Flush()方法看起来是个同步调用,但实际上它只是给系统音频服务(AudioFlinger)发了一个刷新缓冲区的指令,真正的缓冲区清空、重置逻辑是在AudioFlinger的后台线程里完成的。
当你在一个线程调用Flush(),同时另一个线程不停调用write()写入数据时,写入操作会直接抢占AudioTrack的缓冲区资源——而此时Flush的后台逻辑还在处理,缓冲区被新数据覆盖,自然就被打断了。
至于你尝试的锁定AudioTrack对象,其实完全起不到作用:因为write()和Flush()的核心操作是跨进程和AudioFlinger交互的,普通的对象锁只能同步当前进程内的代码,管不住跨进程的异步操作,等于白锁了。
你用canwrite_to_buffer标记暂停写入,再加100ms休眠,刚好踩中了问题的要害:
- 暂停写入切断了新数据对缓冲区的抢占,给Flush的后台操作留出了专属的处理窗口
- 100ms的休眠时间足够大部分设备的AudioFlinger完成缓冲区的清空和重置,等Flush的异步逻辑彻底完成后再恢复写入,自然就不会被打断了
你提到写入的是单个采样的UDP持续数据,这种高频小数据的写入会让竞争问题更明显——因为写入操作几乎一直在抢占缓冲区,Flush需要的“安静处理窗口”本来就很小,稍有不慎就会被打断。
audioTrack = new AudioTrack(Android.Media.Stream.Music, 16000, ChannelOut.Mono, Android.Media.Encoding.Pcm16bit, 8, AudioTrackMode.Stream, 0); new Thread(() => { while(true) { Thread.Sleep(2000); canwrite_to_buffer = false; audioTrack.Flush(); Thread.Sleep(100); canwrite_to_buffer = true; } }).Start();
如果不想依赖固定的100ms休眠(不同设备的AudioFlinger处理速度有差异),可以尝试监听AudioTrack的状态来判断Flush是否完成:
调用Flush()后,循环检查audioTrack.PlayState是否回到你预期的稳定状态(比如PlayState.Paused或PlayState.Playing,根据你的播放逻辑),直到状态稳定后再恢复写入。记得加个超时判断,避免无限循环。
内容的提问来源于stack exchange,提问作者Lorenzo Tinfena

