|
|
|
@ -38,6 +38,7 @@ class AzureAsrHelper(private val context: Context) { |
|
|
|
private var speechConfig: SpeechConfig? = null |
|
|
|
private var recognizer: SpeechRecognizer? = null |
|
|
|
private var audioConfig: AudioConfig? = null |
|
|
|
private var continuousCallback: ContinuousRecognizeCallback? = null |
|
|
|
|
|
|
|
// 状态管理 |
|
|
|
private var isContinuousRecognitionActive = false |
|
|
|
@ -145,22 +146,24 @@ class AzureAsrHelper(private val context: Context) { |
|
|
|
// 录音文件类 |
|
|
|
recordfile = RecordFile; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(tag, "初始化失败: ${e.message}") |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
private fun isRecognizerValid(): Boolean { |
|
|
|
return recognizer != null |
|
|
|
} |
|
|
|
|
|
|
|
private fun isRecognizerValid(): Boolean { |
|
|
|
return recognizer != null |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 设置识别器 |
|
|
|
*/ |
|
|
|
private fun setupRecognizer(): Boolean { |
|
|
|
try { |
|
|
|
// 如果正在进行连续识别,先停止 |
|
|
|
// 如果正在进行连续识别,先停止 |
|
|
|
if (isContinuousRecognitionActive) { |
|
|
|
// 直接停止,不等待结果 |
|
|
|
recognizer?.stopContinuousRecognitionAsync() |
|
|
|
@ -192,7 +195,7 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
private fun setupMicrophoneStream() { |
|
|
|
try { |
|
|
|
Log.d(tag, "设置麦克风流 - 使用拉流方式: }") |
|
|
|
|
|
|
|
|
|
|
|
if (audioStream == null) { |
|
|
|
// 创建外部音频拉流对象 |
|
|
|
audioStream = AudioStream() |
|
|
|
@ -222,7 +225,7 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
callback.onError("语音服务未初始化") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.audioSourceType = audioSourceType |
|
|
|
// 确保不在连续识别中 |
|
|
|
if (isContinuousRecognitionActive) { |
|
|
|
@ -270,26 +273,26 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
return true |
|
|
|
} |
|
|
|
if (!isRecognizerValid()) { |
|
|
|
Log.w(tag, "识别器已失效,正在重新创建...") |
|
|
|
if (!setupRecognizer()) { |
|
|
|
Log.e(tag, "重新创建识别器失败") |
|
|
|
return false |
|
|
|
Log.w(tag, "识别器已失效,正在重新创建...") |
|
|
|
if (!setupRecognizer()) { |
|
|
|
Log.e(tag, "重新创建识别器失败") |
|
|
|
return false |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
this.audioSourceType = audioSourceType |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Log.d(tag, "startContinuousRecognition: ") |
|
|
|
// 启动音频处理 |
|
|
|
//startAudioProcessing() |
|
|
|
// 开始连续识别 |
|
|
|
|
|
|
|
|
|
|
|
// 启动音频处理 |
|
|
|
audioStream!!.startAudioRecord() |
|
|
|
recognizer?.startContinuousRecognitionAsync() |
|
|
|
recognizer?.startContinuousRecognitionAsync() |
|
|
|
isContinuousRecognitionActive = true |
|
|
|
|
|
|
|
|
|
|
|
@ -306,19 +309,20 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
* 设置事件监听器 |
|
|
|
*/ |
|
|
|
fun setupEventListeners(callback: ContinuousRecognizeCallback): Boolean { |
|
|
|
Log.d(tag, "设置ssssss监听器:${speechConfig} ") |
|
|
|
Log.d(tag, "设置ssssss监听器:${speechConfig} ") |
|
|
|
if (speechConfig == null) { |
|
|
|
callback.onError("语音服务未初始化") |
|
|
|
return false |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重设识别器 |
|
|
|
if (!setupRecognizer()) { |
|
|
|
Log.d(tag, "初始化失败: ") |
|
|
|
return false |
|
|
|
} |
|
|
|
try { |
|
|
|
Log.d(tag, "设置ssssss监听器: ") |
|
|
|
continuousCallback = callback; |
|
|
|
Log.d(tag, "设置ssssss监听器: ") |
|
|
|
// 优化:识别中事件 - 添加文本长度检查 |
|
|
|
recognizer?.recognizing?.addEventListener( |
|
|
|
EventHandler<SpeechRecognitionEventArgs> { _, event -> |
|
|
|
@ -367,7 +371,7 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
|
|
|
|
callback.onSessionStopped() |
|
|
|
isContinuousRecognitionActive = false |
|
|
|
// stopAudioProcessing() |
|
|
|
// stopAudioProcessing() |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
@ -378,10 +382,10 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
val errorDetails = event.errorDetails ?: "未知错误" |
|
|
|
val reason = event.reason.toString() |
|
|
|
callback.onCanceled(reason, errorDetails) |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
} catch (e: Exception) { |
|
|
|
callback.onError("启动连续识别失败: ${e.message}") |
|
|
|
return false |
|
|
|
@ -414,7 +418,7 @@ private fun isRecognizerValid(): Boolean { |
|
|
|
} |
|
|
|
Log.d(tag, "停止连续语音识别: ") |
|
|
|
// 直接停止连续识别(SDK内部已是异步操作) |
|
|
|
recognizer?.stopContinuousRecognitionAsync()?.get(1000, TimeUnit.MILLISECONDS) |
|
|
|
recognizer?.stopContinuousRecognitionAsync()?.get(1000, TimeUnit.MILLISECONDS) |
|
|
|
|
|
|
|
// 停止音频处理 |
|
|
|
audioStream!!.stopMicrophoneCapture() |
|
|
|
@ -424,7 +428,7 @@ recognizer?.stopContinuousRecognitionAsync()?.get(1000, TimeUnit.MILLISECONDS) |
|
|
|
// 强制重置状态 |
|
|
|
isContinuousRecognitionActive = false |
|
|
|
Log.e(tag, "停止连续识别失败: ${e.message}") |
|
|
|
recognizer?.stopContinuousRecognitionAsync() |
|
|
|
recognizer?.stopContinuousRecognitionAsync() |
|
|
|
// 停止音频处理 |
|
|
|
audioStream!!.stopMicrophoneCapture() |
|
|
|
// 尝试强制关闭识别器 |
|
|
|
@ -455,7 +459,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
recognizer?.stopContinuousRecognitionAsync() |
|
|
|
isContinuousRecognitionActive = false |
|
|
|
} |
|
|
|
// recognizer?.stopContinuousRecognitionAsync()?.get(1000, TimeUnit.MILLISECONDS) |
|
|
|
// recognizer?.stopContinuousRecognitionAsync()?.get(1000, TimeUnit.MILLISECONDS) |
|
|
|
// 停止音频处理 |
|
|
|
stopAudioProcessing() |
|
|
|
// 停止录音 |
|
|
|
@ -499,7 +503,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
private fun stopAudioProcessing() { |
|
|
|
audioStream?.let { |
|
|
|
try { |
|
|
|
Log.e(tag, "停止音频处理: }") |
|
|
|
Log.e(tag, "停止音频处理: }") |
|
|
|
it.releaseAudioResources() |
|
|
|
|
|
|
|
it.pushAudioStream?.close() |
|
|
|
@ -695,7 +699,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
// 情况2:不在录制但队列有数据 -> 从队列获取 |
|
|
|
else if (writeQueue.isNotEmpty()) { |
|
|
|
data = writeQueue.poll() |
|
|
|
Log.d("tag", "写入数据: ${ data?.size}") |
|
|
|
Log.d("tag", "写入数据: ${data?.size}") |
|
|
|
bytesToWrite = data?.size ?: 0 |
|
|
|
} |
|
|
|
|
|
|
|
@ -706,6 +710,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
if (bytesToWrite < data.size) data.copyOf(bytesToWrite) else data |
|
|
|
|
|
|
|
try { |
|
|
|
continuousCallback?.onAudio(finalData) |
|
|
|
pushAudioStream?.write(finalData) |
|
|
|
recordfile?.saveAudioDataToWav(finalData) |
|
|
|
} catch (e: Exception) { |
|
|
|
@ -732,7 +737,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
* 外部音频输入 |
|
|
|
*/ |
|
|
|
fun saveAudioDataTo(buffer: ByteArray) { |
|
|
|
|
|
|
|
|
|
|
|
if (audioSourceType == AudioSourceType.MICROPHONE) return |
|
|
|
// 放入队列,由写线程写入 |
|
|
|
writeQueue.offer(buffer.copyOf()) |
|
|
|
@ -817,7 +822,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
try { // TODO: 实现外部音频源捕获逻辑 |
|
|
|
// 停止录音 |
|
|
|
if (audioRecord?.recordingState == AudioRecord.STATE_INITIALIZED) { |
|
|
|
Log.d("TAG", "外部音频捕获启动 释放audioRecord") |
|
|
|
Log.d("TAG", "外部音频捕获启动 释放audioRecord") |
|
|
|
audioRecord?.stop() |
|
|
|
// 释放录音实例 |
|
|
|
audioRecord?.release() |
|
|
|
@ -826,7 +831,7 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e("TAG", "外部音频捕获异常: ${e.message}") |
|
|
|
} finally { |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -947,6 +952,13 @@ recognizer?.stopContinuousRecognitionAsync() |
|
|
|
*/ |
|
|
|
fun onSessionStopped() |
|
|
|
|
|
|
|
/** |
|
|
|
* 返回音频 |
|
|
|
* |
|
|
|
* @param data 识别的音频 |
|
|
|
*/ |
|
|
|
fun onAudio(data: ByteArray) |
|
|
|
|
|
|
|
/** |
|
|
|
* 识别取消时调用 |
|
|
|
* |
|
|
|
|