Browse Source

修复部分手机不能回音消除的问题

newdev_shunjiawei
fdp 1 year ago
parent
commit
de4fc6f44d
  1. 98
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt

98
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 com.microsoft.cognitiveservices.speech.util.EventHandler
import android.media.AudioManager 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.PullAudioInputStreamCallback
import com.microsoft.cognitiveservices.speech.audio.AudioStreamFormat import com.microsoft.cognitiveservices.speech.audio.AudioStreamFormat
import java.util.concurrent.BlockingQueue import java.util.concurrent.BlockingQueue
@ -764,31 +768,23 @@ class AzureAsrHelper(private val context: Context) {
private fun runMicrophoneCapture() { private fun runMicrophoneCapture() {
try { try {
// 首先设置通话音频模式
setupCommunicationAudioMode()
val supportedSampleRates = intArrayOf(16000, 8000, 11025, 22050, 44100) val supportedSampleRates = intArrayOf(16000, 8000, 11025, 22050, 44100)
// 查找设备支持的最佳采样率
val sampleRate = supportedSampleRates.firstOrNull { rate -> val sampleRate = supportedSampleRates.firstOrNull { rate ->
val bufferSize = AudioRecord.getMinBufferSize( val bufferSize = AudioRecord.getMinBufferSize(rate, channelConfig, audioFormat)
rate, bufferSize > 0
channelConfig, } ?: 16000
audioFormat
)
bufferSize > 0 // 返回正值表示支持
} ?: 16000 // 默认回退值
val minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat)
// 计算最小缓冲区大小(避免出现音频欠载) // 使用VOICE_COMMUNICATION音频源(专为VoIP优化)
val minBufferSize = AudioRecord.getMinBufferSize(
sampleRate,
channelConfig,
audioFormat
)
// 创建录音对象
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { 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() val format = AudioFormat.Builder()
.setSampleRate(sampleRate) .setSampleRate(sampleRate)
.setEncoding(audioFormat) .setEncoding(audioFormat)
.setChannelMask(channelConfig) .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
.build() .build()
audioRecord = AudioRecord.Builder() audioRecord = AudioRecord.Builder()
@ -797,29 +793,27 @@ class AzureAsrHelper(private val context: Context) {
.setBufferSizeInBytes(minBufferSize * 2) .setBufferSizeInBytes(minBufferSize * 2)
.build() .build()
} else { } else {
// 创建 AudioRecord 对象
audioRecord = AudioRecord( audioRecord = AudioRecord(
MediaRecorder.AudioSource.VOICE_RECOGNITION, // 语音识别专用音源(自带降噪/回声消除) MediaRecorder.AudioSource.VOICE_COMMUNICATION,
sampleRate, sampleRate,
channelConfig, channelConfig,
audioFormat, audioFormat,
minBufferSize * 2 // 使用两倍缓冲区防止溢出 minBufferSize * 2
) )
} }
// 检查初始化状态
if (audioRecord?.state != AudioRecord.STATE_INITIALIZED) { if (audioRecord?.state != AudioRecord.STATE_INITIALIZED) {
throw IllegalStateException("AudioRecord初始化失败") throw IllegalStateException("AudioRecord初始化失败")
} }
// 4. 开始录音
audioRecord?.startRecording() audioRecord?.startRecording()
Log.d("TAG", "录音开始,采样率: $sampleRate Hz")
Log.d("TAG", "通话模式录音开始,采样率: $sampleRate Hz")
} catch (e: Exception) { } catch (e: Exception) {
Log.e("TAG", "音频捕获异常: ${e.message}") Log.e("TAG", "音频捕获异常: ${e.message}")
// 出错时恢复音频模式
restoreCommunicationAudioMode()
} }
} }
@ -981,5 +975,55 @@ class AzureAsrHelper(private val context: Context) {
fun onError(error: String) 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}")
}
}
} /**
* 恢复原始音频模式
*/
private fun restoreCommunicationAudioMode() {
try {
audioManager?.mode = originalAudioMode
audioManager?.isSpeakerphoneOn = false
// 释放音频焦点
Log.d("AudioMode", "音频模式已恢复")
} catch (e: Exception) {
Log.e("AudioMode", "恢复音频模式失败: ${e.message}")
}
}
}
Loading…
Cancel
Save