|
|
|
@ -121,6 +121,8 @@ class OpusAudioManager { |
|
|
|
private var appContext: Context? = null |
|
|
|
private var leftPcmWavWriter: WavFileWriter? = null |
|
|
|
private var rightPcmWavWriter: WavFileWriter? = null |
|
|
|
// 上行(设备→手机)opus 解码后 PCM 的 WAV 调试文件:命名「翻译-上行」,opus_test 可直接播放听辨 |
|
|
|
private var decodePcmWavWriter: WavFileWriter? = null |
|
|
|
|
|
|
|
private val mainHandler = Handler(Looper.getMainLooper()) |
|
|
|
|
|
|
|
@ -281,10 +283,15 @@ class OpusAudioManager { |
|
|
|
|
|
|
|
Log.d(TAG, "准备开始Opus数据流解码, 参数: hasHeader=$hasHeader, channel=$channel, sampleRate=$sampleRate, packetSize=$packetSize") |
|
|
|
|
|
|
|
// 落地上行解码后 PCM 为 WAV,供 opus_test 直接播放听辨(参数与解码配置一致) |
|
|
|
openDecodePcmWavWriter(channel, sampleRate) |
|
|
|
|
|
|
|
try { |
|
|
|
decodeOpusManager?.startDecodeStream(decodeOption, object : OnDecodeStreamCallback { |
|
|
|
override fun onDecodeStream(data: ByteArray?) { |
|
|
|
if (data != null) { |
|
|
|
// 解码后 PCM 落地一份(每帧异步入队写盘,不阻塞解码线程) |
|
|
|
decodePcmWavWriter?.writePcmData(data) |
|
|
|
val channelCount = decodeOption?.getChannel() ?: 1 |
|
|
|
if (channelCount >= 1) { |
|
|
|
callback?.onAudioDataDecoded(data, channelCount) |
|
|
|
@ -314,6 +321,8 @@ class OpusAudioManager { |
|
|
|
return true |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "启动Opus解码流失败: ${e.message}", e) |
|
|
|
// 启动失败:关闭刚创建的上行 PCM WAV,避免留下空文件 |
|
|
|
closeDecodePcmWavWriter() |
|
|
|
callback?.onError("decode", -1, e.message) |
|
|
|
return false |
|
|
|
} |
|
|
|
@ -327,6 +336,9 @@ class OpusAudioManager { |
|
|
|
if (decodeOpusManager?.isDecodeStream == true) { |
|
|
|
decodeOpusManager?.stopDecodeStream() |
|
|
|
|
|
|
|
// 关闭上行解码 PCM 的 WAV 落地文件(补齐 WAV 头、无数据则删除) |
|
|
|
closeDecodePcmWavWriter() |
|
|
|
|
|
|
|
// 清理音频数据缓存 |
|
|
|
synchronized(audioDataBuffer) { |
|
|
|
audioDataBuffer.clear() |
|
|
|
@ -337,6 +349,8 @@ class OpusAudioManager { |
|
|
|
callback?.onDecodeStreamStateChanged(false) |
|
|
|
return true |
|
|
|
} |
|
|
|
// 即便未在解码(如启动失败后重复停止),也兜底关闭可能残留的写入器 |
|
|
|
closeDecodePcmWavWriter() |
|
|
|
Log.d(TAG, "Opus数据流未在解码或OpusManager未初始化") |
|
|
|
return false |
|
|
|
} |
|
|
|
@ -607,6 +621,32 @@ class OpusAudioManager { |
|
|
|
rightPcmWavWriter = null |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 打开上行(设备→手机)解码后 PCM 的 WAV 落地文件。 |
|
|
|
* 命名「翻译-上行」前缀,写到 getExternalFilesDir,opus_test 扫描到 .wav 直接播放听辨; |
|
|
|
* 采样率/声道与解码配置一致(通话翻译为 16k 立体声),16bit PCM。 |
|
|
|
*/ |
|
|
|
private fun openDecodePcmWavWriter(channel: Int, sampleRate: Int) { |
|
|
|
val ctx = appContext ?: return |
|
|
|
// 复用前先关掉可能残留的旧写入器 |
|
|
|
closeDecodePcmWavWriter() |
|
|
|
try { |
|
|
|
// createWavFile 内部会追加 _时间戳,这里只给前缀,最终名如「翻译-上行_20260707_153000.wav」 |
|
|
|
decodePcmWavWriter = WavFileWriter(ctx).also { |
|
|
|
val ok = it.createWavFile("翻译-上行", sampleRate, if (channel >= 1) channel else 1, 16) |
|
|
|
if (!ok) decodePcmWavWriter = null |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "创建上行解码 PCM WAV 调试文件失败: ${e.message}", e) |
|
|
|
decodePcmWavWriter = null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private fun closeDecodePcmWavWriter() { |
|
|
|
try { decodePcmWavWriter?.closeWavFile() } catch (e: Exception) { Log.e(TAG, "关闭上行解码 PCM WAV 失败", e) } |
|
|
|
decodePcmWavWriter = null |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 写入外部音频数据到Opus编码流 |
|
|
|
* 该函数用于将外部音频数据(如麦克风录音)写入到Opus编码器中 |
|
|
|
|