From 0f762529e050a564e9523b84623e143479dc42bd Mon Sep 17 00:00:00 2001 From: fdp <1286779656@qq.com> Date: Tue, 29 Jul 2025 20:53:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86=E6=89=8B?= =?UTF-8?q?=E6=9C=BA=E4=B8=8D=E8=83=BD=E5=9B=9E=E9=9F=B3=E6=B6=88=E9=99=A4?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../azure_speech/AzureAsrHelper.kt | 98 ++++++++++++++----- 1 file changed, 71 insertions(+), 27 deletions(-) diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt index 35fa385de..02d909d4a 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt @@ -13,6 +13,10 @@ import com.microsoft.cognitiveservices.speech.* import com.microsoft.cognitiveservices.speech.util.EventHandler import android.media.AudioManager +import android.media.AudioAttributes +import android.media.AudioFocusRequest +import android.os.Handler +import android.os.Looper import com.microsoft.cognitiveservices.speech.audio.PullAudioInputStreamCallback import com.microsoft.cognitiveservices.speech.audio.AudioStreamFormat import java.util.concurrent.BlockingQueue @@ -764,31 +768,23 @@ class AzureAsrHelper(private val context: Context) { private fun runMicrophoneCapture() { try { + // 首先设置通话音频模式 + setupCommunicationAudioMode() + val supportedSampleRates = intArrayOf(16000, 8000, 11025, 22050, 44100) - // 查找设备支持的最佳采样率 val sampleRate = supportedSampleRates.firstOrNull { rate -> - val bufferSize = AudioRecord.getMinBufferSize( - rate, - channelConfig, - audioFormat - ) - bufferSize > 0 // 返回正值表示支持 - } ?: 16000 // 默认回退值 + val bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat) + bufferSize > 0 + } ?: 16000 + val minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) - // 计算最小缓冲区大小(避免出现音频欠载) - val minBufferSize = AudioRecord.getMinBufferSize( - sampleRate, - channelConfig, - audioFormat - ) -// 创建录音对象 + // 使用VOICE_COMMUNICATION音频源(专为VoIP优化) if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { - Log.d("AzureASR", "android.os.Build.VERSION.SDK_INT") val format = AudioFormat.Builder() .setSampleRate(sampleRate) .setEncoding(audioFormat) - .setChannelMask(channelConfig) + .setChannelMask(AudioFormat.CHANNEL_IN_MONO) .build() audioRecord = AudioRecord.Builder() @@ -797,29 +793,27 @@ class AzureAsrHelper(private val context: Context) { .setBufferSizeInBytes(minBufferSize * 2) .build() } else { - // 创建 AudioRecord 对象 audioRecord = AudioRecord( - MediaRecorder.AudioSource.VOICE_RECOGNITION, // 语音识别专用音源(自带降噪/回声消除) + MediaRecorder.AudioSource.VOICE_COMMUNICATION, sampleRate, channelConfig, audioFormat, - minBufferSize * 2 // 使用两倍缓冲区防止溢出 + minBufferSize * 2 ) - } - // 检查初始化状态 + if (audioRecord?.state != AudioRecord.STATE_INITIALIZED) { throw IllegalStateException("AudioRecord初始化失败") } - - // 4. 开始录音 audioRecord?.startRecording() - Log.d("TAG", "录音开始,采样率: $sampleRate Hz") - + + Log.d("TAG", "通话模式录音开始,采样率: $sampleRate Hz") } catch (e: Exception) { Log.e("TAG", "音频捕获异常: ${e.message}") + // 出错时恢复音频模式 + restoreCommunicationAudioMode() } } @@ -981,5 +975,55 @@ class AzureAsrHelper(private val context: Context) { fun onError(error: String) } + /** + * 配置通话音频模式以优化回声消除 + */ + private fun setupCommunicationAudioMode() { + try { + audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager + + // 保存原始音频模式 + originalAudioMode = audioManager?.mode ?: AudioManager.MODE_NORMAL + + // 设置通话模式 - 这是关键! + audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION + + // 启用扬声器(如果需要外放) + audioManager?.isSpeakerphoneOn = true + + // 请求音频焦点 + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + val focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) + .setAudioAttributes( + AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) + .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) + .build() + ) + .build() + + audioManager?.requestAudioFocus(focusRequest) + } + + Log.d("AudioMode", "通话音频模式已设置: MODE_IN_COMMUNICATION") + + } catch (e: Exception) { + Log.e("AudioMode", "设置通话音频模式失败: ${e.message}") + } + } -} \ No newline at end of file + /** + * 恢复原始音频模式 + */ + private fun restoreCommunicationAudioMode() { + try { + audioManager?.mode = originalAudioMode + audioManager?.isSpeakerphoneOn = false + // 释放音频焦点 + Log.d("AudioMode", "音频模式已恢复") + } catch (e: Exception) { + Log.e("AudioMode", "恢复音频模式失败: ${e.message}") + } + } +} + \ No newline at end of file