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 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}")
}
}
}
/**
* 恢复原始音频模式
*/
private fun restoreCommunicationAudioMode() {
try {
audioManager?.mode = originalAudioMode
audioManager?.isSpeakerphoneOn = false
// 释放音频焦点
Log.d("AudioMode", "音频模式已恢复")
} catch (e: Exception) {
Log.e("AudioMode", "恢复音频模式失败: ${e.message}")
}
}
}
Loading…
Cancel
Save