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 englishVoice = "abby";
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
///
/// 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 是否初始化
private boolean isAsrInitialized = false;
// asr property
private MethodChannel channel;
// asr instance
private final NativeNui asrInstance = new NativeNui();
private Handler asrHandler;
private AsrCallBack asrCallBack;
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
public void onAttachedToEngine(FlutterPluginBinding flutterPluginBinding) {
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), CHANNEL);
@@ -69,9 +85,10 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
HandlerThread asrHandlerThread = new HandlerThread("process_thread");
asrHandlerThread.start();
asrHandler = new Handler(asrHandlerThread.getLooper());
asrCallBack = new AsrCallBack(channel);
asrInstance.initialize(asrCallBack, genAsrInitParams(),
Constants.LogLevel.LOG_LEVEL_NONE, false);
// 不能在这里初始化 asr, 初始化之后会占用麦克风
// asrCallBack = new AsrCallBack(channel);
// asrInstance.initialize(asrCallBack, genAsrInitParams(),
// Constants.LogLevel.LOG_LEVEL_NONE, false);
}
@Override
@@ -81,6 +98,16 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
ttsAudioTrack.releaseAudioTrack();
streamInputTtsInstance.stopStreamInputTts();
streamInputTtsInstance.release();
if (isAsrInitialized) {
asrInstance.release();
if (asrCallBack != null) {
asrCallBack.release();
asrCallBack = null;
}
isAsrInitialized = false;
}
// asrInstance.release();
// if (asrCallBack != null) {
// asrCallBack.release();
@@ -93,6 +120,7 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
Map<String, Object> args = call.arguments();
switch (call.method) {
case "startTts":
assert args != null;
Object isChinese = args.get("isChinese");
if (isChinese == null || isChinese.toString().isBlank()) {
return;
@@ -101,6 +129,7 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
result.success(isSuccess);
break;
case "sendTts":
assert args != null;
Object textArg = args.get("text");
if (textArg == null || textArg.toString().isBlank()) {
return;
@@ -140,6 +169,9 @@ public class AiAssistantPlugin implements FlutterPlugin, MethodCallHandler {
private void startAsr() {
asrHandler.post(() -> {
// 初始化
initAsrInstance();
// 启动
String setParamsString = genAsrParams();
Log.i(TAG, "nui set params " + setParamsString);
asrInstance.setParams(setParamsString);

View File

@@ -18,7 +18,7 @@ import io.flutter.plugin.common.MethodChannel;
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_WAVE_FRAM_SIZE = 20 * 2 * 1 * ASR_SAMPLE_RATE / 1000; //20ms audio for 16k/16bit/mono
private AudioRecord asrAudioRecorder = null;
@@ -38,7 +38,7 @@ public class AsrCallBack implements INativeNuiCallback {
if (event == Constants.NuiEvent.EVENT_TRANSCRIBER_STARTED) {
asrText = "";
} else if (event == Constants.NuiEvent.EVENT_TRANSCRIBER_COMPLETE) {
// complete
} else if (event == Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT) {
JSONObject jsonObject = JSON.parseObject(asrResult.allResponse);
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());
// AIChatAssistantManager.instance.setWakeWordDetection(true);
AIChatAssistantManager.instance.startVoskWakeword();
// AIChatAssistantManager.instance.startVoskWakeword();
}

View File

@@ -60,10 +60,15 @@ class MessageService extends ChangeNotifier {
Future<dynamic> _handleMethodCall(MethodCall call) async {
switch (call.method) {
case "onAsrResult":
{
debugPrint("ASR 结果: ${call.arguments}");
replaceMessage(
id: _latestUserMessageId!, text: call.arguments, status: MessageStatus.normal);
break;
}
case "onAsrStop":
{
debugPrint("ASR 停止: ${call.arguments}");
int index = findMessageIndexById(_latestUserMessageId!);
if (index == -1) {
return;
@@ -79,6 +84,7 @@ class MessageService extends ChangeNotifier {
break;
}
}
}
// final ChatSseService _chatSseService = ChatSseService(PlatformTtsService(aliSdkChannelName));
final Service.ChatSseService _chatSseService = Service.ChatSseService();