fix: 修复asr 启动就初始化的问题

asrInstance.initialize 这个方法的作用是初始化阿里云 NUI SDK 的 ASR 实例。根据阿里云 SDK 的设计,这个初始化过程不仅仅是加载配置,它还会立即建立与云端的长连接(WebSocket),并进入一个“待命”状态。SDK 会请求打开音频设备。

延迟初始化,只在第一次需要时才进行初始化
This commit is contained in:
2025-09-30 11:43:40 +08:00
parent a7ed838c92
commit c29a3f665a
5 changed files with 727 additions and 26 deletions

View File

@@ -35,13 +35,14 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
private static final String chineseVoice = "zhitian_emo"; private static final String chineseVoice = "zhitian_emo";
private static final String englishVoice = "abby"; private static final String englishVoice = "abby";
private final NativeNui streamInputTtsInstance = new NativeNui(Constants.ModeType.MODE_STREAM_INPUT_TTS); private final NativeNui streamInputTtsInstance = new NativeNui(Constants.ModeType.MODE_STREAM_INPUT_TTS);
private final NativeNui asrInstance = new NativeNui();
/// The MethodChannel that will the communication between Flutter and native Android // asr 是否初始化
/// private boolean isAsrInitialized = false;
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity // asr property
private MethodChannel channel; private MethodChannel channel;
// asr instance
private final NativeNui asrInstance = new NativeNui();
private Handler asrHandler; private Handler asrHandler;
private AsrCallBack asrCallBack; private AsrCallBack asrCallBack;
private Handler handler = new Handler(Looper.getMainLooper()); private Handler handler = new Handler(Looper.getMainLooper());
@@ -62,6 +63,21 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
} }
}); });
void initAsrInstance() {
if (!isAsrInitialized) {
Log.i(TAG, "Initializing ASR for the first time...");
asrCallBack = new AsrCallBack(channel);
int initResult = asrInstance.initialize(asrCallBack, genAsrInitParams(),
Constants.LogLevel.LOG_LEVEL_NONE, false);
Log.i(TAG, "ASR initialization result: " + initResult);
if (initResult != Constants.NuiResultCode.SUCCESS) {
Log.i(TAG, "ASR initialization failed with error code: " + initResult);
return;
}
isAsrInitialized = true;
}
}
@Override @Override
public void onAttachedToEngine(FlutterPluginBinding flutterPluginBinding) { public void onAttachedToEngine(FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL); channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL);
@@ -69,9 +85,10 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
HandlerThread asrHandlerThread = new HandlerThread("process_thread"); HandlerThread asrHandlerThread = new HandlerThread("process_thread");
asrHandlerThread.start(); asrHandlerThread.start();
asrHandler = new Handler(asrHandlerThread.getLooper()); asrHandler = new Handler(asrHandlerThread.getLooper());
asrCallBack = new AsrCallBack(channel); // 不能在这里初始化 asr, 初始化之后会占用麦克风
asrInstance.initialize(asrCallBack, genAsrInitParams(), // asrCallBack = new AsrCallBack(channel);
Constants.LogLevel.LOG_LEVEL_NONE, false); // asrInstance.initialize(asrCallBack, genAsrInitParams(),
// Constants.LogLevel.LOG_LEVEL_NONE, false);
} }
@Override @Override
@@ -81,6 +98,16 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
ttsAudioTrack.releaseAudioTrack(); ttsAudioTrack.releaseAudioTrack();
streamInputTtsInstance.stopStreamInputTts(); streamInputTtsInstance.stopStreamInputTts();
streamInputTtsInstance.release(); streamInputTtsInstance.release();
if (isAsrInitialized) {
asrInstance.release();
if (asrCallBack != null) {
asrCallBack.release();
asrCallBack = null;
}
isAsrInitialized = false;
}
// asrInstance.release(); // asrInstance.release();
// if (asrCallBack != null) { // if (asrCallBack != null) {
// asrCallBack.release(); // asrCallBack.release();
@@ -93,6 +120,7 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
Map<String, Object> args = call.arguments(); Map<String, Object> args = call.arguments();
switch (call.method) { switch (call.method) {
case "startTts": case "startTts":
assert args != null;
Object isChinese = args.get("isChinese"); Object isChinese = args.get("isChinese");
if (isChinese == null || isChinese.toString().isBlank()) { if (isChinese == null || isChinese.toString().isBlank()) {
return; return;
@@ -101,6 +129,7 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
result.success(isSuccess); result.success(isSuccess);
break; break;
case "sendTts": case "sendTts":
assert args != null;
Object textArg = args.get("text"); Object textArg = args.get("text");
if (textArg == null || textArg.toString().isBlank()) { if (textArg == null || textArg.toString().isBlank()) {
return; return;
@@ -140,6 +169,9 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
private void startAsr() { private void startAsr() {
asrHandler.post(() -> { asrHandler.post(() -> {
// 初始化
initAsrInstance();
// 启动
String setParamsString = genAsrParams(); String setParamsString = genAsrParams();
Log.i(TAG, "nui set params " + setParamsString); Log.i(TAG, "nui set params " + setParamsString);
asrInstance.setParams(setParamsString); asrInstance.setParams(setParamsString);

View File

@@ -18,7 +18,7 @@ import io.flutter.plugin.common.MethodChannel;
public class AsrCallBack implements INativeNuiCallback { public class AsrCallBack implements INativeNuiCallback {
private static final String TAG = "AliAsr"; private static final String TAG = "AliAsr-Callbask";
private final static int ASR_SAMPLE_RATE = 16000; private final static int ASR_SAMPLE_RATE = 16000;
private final static int ASR_WAVE_FRAM_SIZE = 20 * 2 * 1 * ASR_SAMPLE_RATE / 1000; //20ms audio for 16k/16bit/mono private final static int ASR_WAVE_FRAM_SIZE = 20 * 2 * 1 * ASR_SAMPLE_RATE / 1000; //20ms audio for 16k/16bit/mono
private AudioRecord asrAudioRecorder = null; private AudioRecord asrAudioRecorder = null;
@@ -38,7 +38,7 @@ public class AsrCallBack implements INativeNuiCallback {
if (event == Constants.NuiEvent.EVENT_TRANSCRIBER_STARTED) { if (event == Constants.NuiEvent.EVENT_TRANSCRIBER_STARTED) {
asrText = ""; asrText = "";
} else if (event == Constants.NuiEvent.EVENT_TRANSCRIBER_COMPLETE) { } else if (event == Constants.NuiEvent.EVENT_TRANSCRIBER_COMPLETE) {
// complete
} else if (event == Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT) { } else if (event == Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT) {
JSONObject jsonObject = JSON.parseObject(asrResult.allResponse); JSONObject jsonObject = JSON.parseObject(asrResult.allResponse);
JSONObject payload = jsonObject.getJSONObject("payload"); JSONObject payload = jsonObject.getJSONObject("payload");

File diff suppressed because one or more lines are too long

View File

@@ -67,7 +67,7 @@ void main() async {
runApp(const MyApp()); runApp(const MyApp());
// AIChatAssistantManager.instance.setWakeWordDetection(true); // AIChatAssistantManager.instance.setWakeWordDetection(true);
AIChatAssistantManager.instance.startVoskWakeword(); // AIChatAssistantManager.instance.startVoskWakeword();
} }

View File

@@ -60,23 +60,29 @@ class MessageService extends ChangeNotifier {
Future<dynamic> _handleMethodCall(MethodCall call) async { Future<dynamic> _handleMethodCall(MethodCall call) async {
switch (call.method) { switch (call.method) {
case "onAsrResult": case "onAsrResult":
replaceMessage( {
id: _latestUserMessageId!, text: call.arguments, status: MessageStatus.normal); debugPrint("ASR 结果: ${call.arguments}");
break; replaceMessage(
id: _latestUserMessageId!, text: call.arguments, status: MessageStatus.normal);
break;
}
case "onAsrStop": case "onAsrStop":
int index = findMessageIndexById(_latestUserMessageId!); {
if (index == -1) { debugPrint("ASR 停止: ${call.arguments}");
return; int index = findMessageIndexById(_latestUserMessageId!);
if (index == -1) {
return;
}
final message = _messages[index];
if (message.text.isEmpty) {
removeMessageById(_latestUserMessageId!);
return;
}
if (_asrCompleter != null && !_asrCompleter!.isCompleted) {
_asrCompleter!.complete(messages.last.text);
}
break;
} }
final message = _messages[index];
if (message.text.isEmpty) {
removeMessageById(_latestUserMessageId!);
return;
}
if (_asrCompleter != null && !_asrCompleter!.isCompleted) {
_asrCompleter!.complete(messages.last.text);
}
break;
} }
} }