|
|
|
@ -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}") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|