import 'package:flutter/services.dart'; import 'chivox_aiengine_platform_interface.dart'; class ChivoxAiengineResult { /// 本次评测唯一标识 String tokenId = ""; /// 是否是本次评测的最后一个结果 bool isLast = false; /// 文本结果。当结果类型是EvalResult、Error、Vad、SoundIntensity、Other时,使用本字段获取文本结果。 String? text; /// 二进制结果。当结果类型是BinaryResult时,使用本字段获取二进制数据。 Uint8List? data; /// 如果录音文件保存成功,返回录音文件的路径,否则返回null。 String? recFilePath; } class ChivoxAiengineResultListener { ChivoxAiengineResultListener( {void Function(ChivoxAiengineResult result)? onEvalResult, void Function(ChivoxAiengineResult result)? onBinaryResult, void Function(ChivoxAiengineResult result)? onError, void Function(ChivoxAiengineResult result)? onVad, void Function(ChivoxAiengineResult result)? onSoundIntensity, void Function(ChivoxAiengineResult result)? onOther}) { if (onEvalResult != null) this.onEvalResult = onEvalResult; if (onBinaryResult != null) this.onBinaryResult = onBinaryResult; if (onError != null) this.onError = onError; if (onVad != null) this.onVad = onVad; if (onSoundIntensity != null) this.onSoundIntensity = onSoundIntensity; if (onOther != null) this.onOther = onOther; } /// 用于接收评测分数结果 void Function(ChivoxAiengineResult result) onEvalResult = (result) {}; /// 用于接收二进制结果 void Function(ChivoxAiengineResult result) onBinaryResult = (result) {}; /// 用于接收错误 void Function(ChivoxAiengineResult result) onError = (result) {}; /// 用于接收语音活动检测结果 void Function(ChivoxAiengineResult result) onVad = (result) {}; /// 用于结果音强结果 void Function(ChivoxAiengineResult result) onSoundIntensity = (result) {}; /// 其他未处理的结果,在SDK正确实现的情况下,不会产生此结果 void Function(ChivoxAiengineResult result) onOther = (result) {}; } class ChivoxAiengine { static int _callbackCnt = 0; static String _nextCallbackId() { _callbackCnt++; final cnt = _callbackCnt; final unixTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; return "${unixTime}_$cnt"; } static bool _staticInited = false; static const _callbackChannel = MethodChannel("com.chivox.aiengine/callback"); static final Map)> _callbacks = {}; static void staticInit() { if (_staticInited) return; _staticInited = true; _callbackChannel.setMethodCallHandler((MethodCall call) async { if (call.method == "aiengine_callback") { String callbackId = call.arguments[0]; _callbacks[callbackId]?.call(call.arguments); } }); } bool _loadingOrLoaded = false; String? _engineId; ChivoxAiengine._() { staticInit(); } /// 无用。忽略本接口 static Future getPlatformVersion() async { return await ChivoxAienginePlatform.instance.getPlatformVersion(); } /// 创建引擎 /// 参数cfg:引擎配置,json字符串(同ios或android端sdk) /// 抛出异常:PlatformException static Future create(String cfg) async { final engine = ChivoxAiengine._(); await engine._load(cfg); return engine; } Future _load(String cfg) async { if (_loadingOrLoaded) { throw PlatformException( code: "-1", message: "don't repeatedly load the engine"); } _loadingOrLoaded = true; _engineId = await ChivoxAienginePlatform.instance.aiengineNew(cfg); } /// 销毁引擎 /// 当应用程序不再需要使用评测引擎时,须销毁,否则引擎内部资源不会得到释放 /// 抛出异常:PlatformException Future destroy() async { final engineId = _engineId; if (engineId == null) return; _engineId = null; await ChivoxAienginePlatform.instance.aiengineDelete(engineId); } /// 启动一次评测 /// 参数audioSrc: 选择录音模式。其格式如下: /// { /// "srcType": string, // [必填项] 音频源:可填"innerRecorder"-sdk内部录音, "outerFeed"-用于外部输入音频 /// "innerRecorderParam": { // [可选项] 内部录音参数 /// "duration": int, // [可选项] 录音时长,默认永久 /// "channel": int, // [可选项] 通道数,默认1 /// "sampleBytes": int, // [可选项] 采样字节,默认2 /// "sampleRate": int, // [可选项] 采样率,默认16000 /// "saveFile": string, // [可选项] 保存录音文件的路径,默认不保存 /// } /// } /// 参数param: 语音评测参数,json字符串(同ios或android端sdk) /// 参数listener: 用于接收评测结果的listener对象 /// 抛出异常:PlatformException /// /// 注意:对于ios平台,sdk内部并没有设置AudioSessionCategory,应用层须自行设置其为一个支持录音的值。 Future start(Map audioSrc, String param, ChivoxAiengineResultListener listener) async { final engineId = _engineId; if (engineId == null) { throw PlatformException( code: "-1", message: "the engine has not been loaded yet"); } final callbackId = _nextCallbackId(); _callbacks[callbackId] = (List args) { var result = ChivoxAiengineResult(); String type = args[1]; result.isLast = args[2]; result.tokenId = args[3]; result.text = args[4]; result.data = args[5]; result.recFilePath = args[6]; if (type == "evalResult") { listener.onEvalResult(result); } else if (type == "binResult") { listener.onBinaryResult(result); } else if (type == "error") { listener.onError(result); } else if (type == "vad") { listener.onVad(result); } else if (type == "soundIntensity") { listener.onSoundIntensity(result); } else { listener.onOther(result); } if (result.isLast || type == "error") { _callbacks.remove(callbackId); } // TODO 超过一定时间没有回调,则强行移除回调 }; await ChivoxAienginePlatform.instance .aiengineStart(engineId, audioSrc, param, callbackId); return; } /// 输入音频数据 (仅outerFeed模式可使用) /// 抛出异常:PlatformException Future feed(Uint8List bytes, int length) async { final engineId = _engineId; if (engineId == null) { throw PlatformException( code: "-1", message: "the engine has not been loaded yet"); } await ChivoxAienginePlatform.instance.aiengineFeed(engineId, bytes, length); } /// 结束录音 (或结束音频数据) /// 本方法调用后将会进入等待评测结果状态,一旦评测结果产生后,将通过start方法的listener参数回调给应用层。 /// 抛出异常:PlatformException Future stop() async { final engineId = _engineId; if (engineId == null) { throw PlatformException( code: "-1", message: "the engine has not been loaded yet"); } await ChivoxAienginePlatform.instance.aiengineStop(engineId); } /// 取消全部评测 /// 本方法调用后,sdk内部取消所有正在进行的评测 /// 抛出异常:PlatformException Future cancel() async { final engineId = _engineId; if (engineId == null) { throw PlatformException( code: "-1", message: "the engine has not been loaded yet"); } await ChivoxAienginePlatform.instance.aiengineCancel(engineId); } static Future getDeviceId() async { return await ChivoxAienginePlatform.instance.getDeviceId(); } /// 激活设备,并返回序列号 /// 本方法调用后,sdk会把序列号存储在文件系统中。 /// 应用层下次调用本方法sdk会直接从文件系统中取出该值返回给应用层。 /// 应用层可调用clearSavedSerialNumber方法清除sdk存储的序列号。 /// 参数input: 结构同ios或android端sdk /// 返回: 结构同ios或andorid端sdk /// 抛出异常:PlatformException static Future getSerialNumber( ChivoxAiengine? engine, Map input) async { return await ChivoxAienginePlatform.instance .getSerialNumber(engine?._engineId, input); } /// 清除sdk在文件系统中存储的序列号 /// 抛出异常:PlatformException static Future clearSavedSerialNumber(String appKey) async { return await ChivoxAienginePlatform.instance.clearSavedSerialNumber(appKey); } /// 某些appkey支持二次授权功能,本方法提供该功能 /// 抛出异常:PlatformException static Future getProvision(ChivoxAiengine? engine, Map input) async { return await ChivoxAienginePlatform.instance .getProvision(engine?._engineId, input); } /// 工具方法:提取sdk离线资源包到一个目录中 /// 参数assetPrefix: 离线资源包在flutter assets中的前缀 /// 参数assetNames: 需要提取的资源包的名称列表 /// 参数targetDir: 目标目录,资源包会解压于此 /// 参数progressHint: 解压进度回调 /// 抛出异常:PlatformException static Future extractRes(String assetPrefix, List assetNames, String targetDir, Function(double) progressHint) async { staticInit(); final callbackId = _nextCallbackId(); _callbacks[callbackId] = (List args) { progressHint(args[1]); }; await ChivoxAienginePlatform.instance .extractRes(assetPrefix, assetNames, targetDir, callbackId); _callbacks.remove(callbackId); } /// 工具方法:根据传入的资源根目录和资源名称列表,加载离线资源配置 /// 参数resRootDir: 离线资源包的根目录 /// 参数resNames: 指定需要哪些离线资源包 /// 返回: 一个json字符串,描述了离线资源配置信息。该json用于引擎加载时提供离线配置信息。 /// 抛出异常:PlatformException static Future loadNativeCfg( String resRootDir, List resNames) { return ChivoxAienginePlatform.instance.loadNativeCfg(resRootDir, resNames); } }