Flutter实时音频播放崩溃:Fatal Signal 6(SIGABRT)问题排查
问题描述
我正在开发一款帮助听障人士的Flutter应用,核心功能是将麦克风采集的音频实时播放到扬声器。实现方式是通过录音器采集音频流,再用播放器实时播放,但应用运行一段时间后会崩溃,崩溃日志如下:
崩溃日志
F/libc (16368): Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 16693 (Thread-21), pid 16368 (corise.hearmate)
error is App crash:
pid: 16368, tid: 16693, name: Thread-21 >>> com.corise.hearmate <<<
uid: 10270
signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
Abort message: 'releaseBuffer: mUnreleased out of range, !(stepCount:78 <= mUnreleased:0 <= mFrameCount:4096), BufferSizeInFrames:4096'
已实现的核心代码
启动录音与流播放的函数代码如下:
Future<void> startRecording(BuildContext context) async { checkBluetoothPermission(); log("Start recording"); getMacAccountDate(); allowed(); if (isRecording) return; final String connectedDevice = await MethodChannel('com.example.settings/bluetoothState') .invokeMethod('isHeadsetConnected'); log(connectedDevice); if (connectedDevice == "none") { showDialog( context: context, builder: (context) => CustomDialog( headline: "No Headset", red: () {}, green: () { Navigator.pop(context); }, redButton: "", greenButton: "Try Again", animation: "assets/animations/inf.json", subline: "To use listening feature of this app you must connect some headset with the device for best results "), ); } else { try { _audioStreamController = StreamController<Uint8List>(); log("BitRate: " + bitrate.toString()); // Start recording with initial settings await _recorder!.startRecorder( codec: Codec.pcm16WAV, bitRate: bitrate.toInt(), toStream: _audioStreamController!.sink, numChannels: 1, enableVoiceProcessing: true, sampleRate: frequency.toInt(), // Initial frequency (from slider) ); // Listen for audio data and handle it _audioStreamController!.stream.listen( (audioData) async { try { // Apply noise cancellation if enabled if (_player != null && !_player!.isPlaying) { await _player!.startPlayerFromStream( codec: Codec.pcm16, numChannels: 1, sampleRate: frequency.toInt() // Apply frequency to player ); } if (_player != null && _player!.isPlaying) { await _player!.feedFromStream(audioData); } } catch (e) { log("Error during feed: $e"); } }, onError: (error) { log("Stream error: $error"); }, onDone: () { log("Stream closed"); }, ); final prefs = await SharedPreferences.getInstance(); final isEnabled = prefs.getBool('notification_toggle') ?? false; if (isEnabled) { showNotification("HearMate", "Hear Mate app is running . . . "); } isRecording = true; notifyListeners(); } catch (e) { log("Error starting recording: $e"); isRecording = false; notifyListeners(); } } }
复现步骤
- 启动应用并开启实时音频录播功能;
- 让应用运行一段时间(几秒到几分钟不等);
- 应用出现上述崩溃。
咨询问题
- 崩溃日志中的
releaseBuffer: mUnreleased out of range是什么含义? - 当前的录音/播放器实现是否存在缓冲区相关问题导致崩溃?
- 是否需要调整Flutter或Android原生设置(如缓冲区大小、采样率)来解决该问题?
解答
1. releaseBuffer: mUnreleased out of range的含义
这是Android底层音频系统的断言错误,表明音频缓冲区的释放逻辑异常:
mUnreleased是当前未被释放的缓冲区帧数,此处为0;stepCount是尝试释放的帧数(78);mFrameCount是缓冲区总帧数(4096);
错误本质是:尝试释放的帧数超过了实际未被释放的帧数,触发底层音频缓冲区管理的断言检查,直接导致应用崩溃。
2. 当前实现的缓冲区问题
从代码看,存在多个触发缓冲区异常的风险点:
- 编码格式不匹配:录音使用
Codec.pcm16WAV(带WAV文件头),但播放器使用Codec.pcm16(纯PCM数据),WAV头会被当作音频数据喂给播放器,导致解析错误,破坏缓冲区状态; - 播放器重复启动:流回调中每次都检查
_player!.isPlaying并尝试启动播放器,可能触发多次startPlayerFromStream调用,造成播放器内部缓冲区状态混乱; - 异步竞态堆积:流回调是异步函数,
await _player!.feedFromStream(audioData)会阻塞回调执行,导致音频数据在流中堆积,播放器缓冲区无法及时处理,最终引发释放逻辑错误。
3. 解决方案与调整建议
代码层面修复
- 统一编码格式:将录音的
Codec.pcm16WAV改为Codec.pcm16,避免WAV头干扰播放器解析:await _recorder!.startRecorder( codec: Codec.pcm16, // 替换为纯PCM编码 bitRate: bitrate.toInt(), toStream: _audioStreamController!.sink, numChannels: 1, enableVoiceProcessing: true, sampleRate: frequency.toInt(), ); - 固定播放器启动时机:将播放器启动逻辑移到录音启动之后,而非流回调中,确保只启动一次:
// 启动录音后立即初始化播放器 await _player!.startPlayerFromStream( codec: Codec.pcm16, numChannels: 1, sampleRate: frequency.toInt() ); // 监听流并喂数据,去掉await避免阻塞 _audioStreamController!.stream.listen( (audioData) { if (_player != null && _player!.isPlaying) { _player!.feedFromStream(audioData); } }, onError: (error) => log("Stream error: $error"), onDone: () => log("Stream closed"), ); - 避免异步阻塞:流回调中不要使用
await,防止音频数据堆积;可添加状态标记确保播放器操作的原子性。
系统与配置调整
- 调整缓冲区大小:如果使用
record或audioplayers插件,尝试设置更小的缓冲区帧数(如从4096改为2048),减少数据堆积概率; - 固定采样率:避免运行中动态修改
frequency(滑块调整),若需调整需先停止录音/播放器,重启时同步新参数; - Android原生优化:在
AndroidManifest.xml中添加低延迟音频配置:
并在音频初始化时启用低延迟模式,降低缓冲区异常风险。<uses-feature android:name="android.hardware.audio.low_latency" />
资源管理优化
- 及时释放资源:停止录音时,务必关闭
_audioStreamController、停止播放器并释放资源,避免缓冲区残留数据干扰后续启动; - 添加错误恢复:捕获播放器缓冲区异常,出现错误时重启录音/播放器流程,避免直接崩溃。
内容的提问来源于stack exchange,提问作者Haroon
相关产品推荐
相关产品推荐

