import 'dart:async'; import 'package:flutter/services.dart'; /// ASR 事件类型 enum AsrEventType { /// 会话开始 sessionStarted, /// 会话结束 sessionStopped, /// 正在识别(中间结果) recognizing, /// 识别结果(最终结果) result, /// 音量变化 volumeChanged, /// 错误 error } /// TTS 工作模式 enum TtsWorkMode { /// 在线合成 online, /// 离线合成 offline, /// 同时在线离线 both, /// 先在线再离线(网络不好时自动切换) alternate, /// 文件模式 file } /// TTS 文本类型 enum TtsTextType { /// 纯文本 plain, /// SSML格式 ssml } /// 协议类型 enum ProtocolType { /// 默认协议 defaultProtocol, /// Seed协议(用于大模型) seed } /// TTS 播放进度事件 class TtsProgressEvent { /// 播放进度 0.0-1.0 final double progress; /// 请求ID final String reqId; const TtsProgressEvent({ required this.progress, required this.reqId, }); @override String toString() { return 'TtsProgressEvent{progress: $progress, reqId: $reqId}'; } } /// ASR 事件 class AsrEvent { /// 事件类型 final AsrEventType type; /// 识别文本(仅在recognizing和result类型时有效) final String? text; /// 识别语言(仅在recognizing和result类型时有效) final String? language; /// 音量值(仅在volumeChanged类型时有效) final int? volume; /// 错误信息(仅在error类型时有效) final String? errorMessage; const AsrEvent({ required this.type, this.text, this.language, this.volume, this.errorMessage, }); factory AsrEvent.fromMap(Map map) { final typeStr = map['type'] as String; AsrEventType type; switch (typeStr) { case 'sessionStarted': type = AsrEventType.sessionStarted; break; case 'sessionStopped': type = AsrEventType.sessionStopped; break; case 'recognizing': type = AsrEventType.recognizing; break; case 'result': type = AsrEventType.result; break; case 'volumeChanged': type = AsrEventType.volumeChanged; break; case 'error': type = AsrEventType.error; break; default: throw ArgumentError('未知的事件类型: $typeStr'); } return AsrEvent( type: type, text: map['text'] as String?, language: map['language'] as String?, volume: map['volume'] as int?, errorMessage: map['message'] as String?, ); } @override String toString() { return 'AsrEvent{type: $type, text: $text, language: $language, volume: $volume, errorMessage: $errorMessage}'; } } /// 火山引擎语音服务插件 class VolcanoSpeech { static final VolcanoSpeechAsr asr = VolcanoSpeechAsr._(); static final VolcanoSpeechTts tts = VolcanoSpeechTts._(); /// 释放资源 static Future dispose() async { await asr.dispose(); await tts.dispose(); } } /// 火山引擎语音识别服务 class VolcanoSpeechAsr { static const MethodChannel _channel = MethodChannel('volcano_speech/asr'); static const EventChannel _eventChannel = EventChannel('volcano_speech/asr_events'); /// ASR事件流控制器 static final StreamController _eventStreamController = StreamController.broadcast(); /// ASR事件流 Stream get events => _eventStreamController.stream; /// 是否已初始化事件监听 bool _eventListenerInitialized = false; VolcanoSpeechAsr._() { _initEventListener(); } /// 初始化ASR事件监听 void _initEventListener() { if (_eventListenerInitialized) return; _eventChannel.receiveBroadcastStream().listen((dynamic event) { if (event is Map) { _eventStreamController.add(AsrEvent.fromMap(event)); } }); _eventListenerInitialized = true; } /// 获取平台版本信息 Future getPlatformVersion() async { return await _channel.invokeMethod('getPlatformVersion'); } /// 初始化语音识别引擎 /// /// [appId] 火山引擎AppID /// [apiKey] 火山引擎ApiKey /// [supportedLanguages] 支持的语言列表 /// [useBigModel] 是否使用大模型识别 /// [resourceId] 大模型资源ID(仅当useBigModel为true时有效) Future initialize({ required String appId, required String apiKey, List supportedLanguages = const ['zh-CN'], bool useBigModel = false, String resourceId = '', }) async { return await _channel.invokeMethod('initialize', { 'appId': appId, 'apiKey': apiKey, 'supportedLanguages': supportedLanguages, 'useBigModel': useBigModel, 'resourceId': resourceId, }) ?? false; } /// 设置识别语言 /// /// [language] 语言代码,例如 zh-CN、en-US Future setLanguage(String language) async { return await _channel.invokeMethod('setLanguage', { 'language': language, }) ?? false; } /// 设置热词 /// /// [hotWords] 热词JSON字符串,例如 {"hotwords":[{"word":"快速入门","scale":2.0}]} Future setHotWords(String hotWords) async { return await _channel.invokeMethod('setHotWords', { 'hotWords': hotWords, }) ?? false; } /// 设置ASR请求参数 /// /// [params] 请求参数JSON字符串 Future setRequestParams(String params) async { return await _channel.invokeMethod('setRequestParams', { 'params': params, }) ?? false; } /// 启用语音停顿、分句、分词信息输出 /// /// [enable] 是否启用 Future setShowUtterances(bool enable) async { return await _channel.invokeMethod('setShowUtterances', { 'enable': enable, }) ?? false; } /// 一次性识别(直到说话结束) /// /// 返回识别结果文本和语言 Future> recognizeOnce() async { final result = await _channel.invokeMethod('recognizeOnce'); return { 'text': result['text'] ?? '', 'language': result['language'] ?? 'zh-CN', }; } /// 开始连续识别 /// /// 通过[events]流监听识别结果 Future startContinuousRecognition() async { return await _channel.invokeMethod('startContinuousRecognition') ?? false; } /// 停止连续识别 Future stopContinuousRecognition() async { return await _channel.invokeMethod('stopContinuousRecognition') ?? false; } /// 检查是否正在连续识别 Future isContinuousRecognitionActive() async { return await _channel.invokeMethod('isContinuousRecognitionActive') ?? false; } /// 开始长按识别(按下开始,抬起结束) /// /// 通过[events]流监听识别结果 Future startListening() async { return await _channel.invokeMethod('startListening') ?? false; } /// 停止长按识别 Future stopListening() async { return await _channel.invokeMethod('stopListening') ?? false; } /// 释放ASR资源 Future dispose() async { return await _channel.invokeMethod('dispose') ?? false; } } /// 火山引擎语音合成服务 class VolcanoSpeechTts { static const MethodChannel _channel = MethodChannel('volcano_speech/tts'); static const EventChannel _eventChannel = EventChannel('volcano_speech/tts_events'); /// TTS进度事件流控制器 static final StreamController _progressStreamController = StreamController.broadcast(); /// TTS进度事件流 Stream get progressEvents => _progressStreamController.stream; /// 是否已初始化事件监听 bool _eventListenerInitialized = false; VolcanoSpeechTts._() { _initEventListener(); } /// 初始化TTS事件监听 void _initEventListener() { if (_eventListenerInitialized) return; _eventChannel.receiveBroadcastStream().listen((dynamic event) { if (event is Map) { final progress = event['progress'] as double?; final reqId = event['reqId'] as String?; if (progress != null && reqId != null) { _progressStreamController.add(TtsProgressEvent( progress: progress, reqId: reqId, )); } } }); _eventListenerInitialized = true; } /// 获取平台版本信息 Future getPlatformVersion() async { return await _channel.invokeMethod('getPlatformVersion'); } /// 启用大模型TTS /// /// [enable] 是否启用大模型TTS /// [resourceId] 资源ID Future enableBigModelTts({ required bool enable, String resourceId = '', }) async { return await _channel.invokeMethod('enableBigModelTts', { 'enable': enable, 'resourceId': resourceId, }) ?? false; } /// 初始化语音合成引擎 /// /// [appId] 火山引擎AppID /// [apiKey] 火山引擎ApiKey Future initialize({ required String appId, required String apiKey, }) async { return await _channel.invokeMethod('initialize', { 'appId': appId, 'apiKey': apiKey, }) ?? false; } /// 设置音色 /// /// [voiceName] 音色名称 /// [voiceType] 音色类型,默认 qingxin Future setVoice({ required String voiceName, String voiceType = 'qingxin', }) async { return await _channel.invokeMethod('setVoice', { 'voiceName': voiceName, 'voiceType': voiceType, }) ?? false; } /// 设置离线音色 /// /// [voiceName] 音色名称 /// [voiceType] 音色类型,默认 qingxin Future setOfflineVoice({ required String voiceName, String voiceType = 'qingxin', }) async { return await _channel.invokeMethod('setOfflineVoice', { 'voiceName': voiceName, 'voiceType': voiceType, }) ?? false; } /// 设置大模型声音ID /// /// [voiceId] 声音ID Future setBigModelVoiceId(String voiceId) async { return await _channel.invokeMethod('setBigModelVoiceId', { 'voiceId': voiceId, }) ?? false; } /// 设置大模型请求参数 /// /// [params] 请求参数,JSON字符串 Future setBigModelRequestParams(String params) async { return await _channel.invokeMethod('setBigModelRequestParams', { 'params': params, }) ?? false; } /// 设置工作模式 /// /// [mode] 工作模式 Future setWorkMode(TtsWorkMode mode) async { String modeStr; switch (mode) { case TtsWorkMode.online: modeStr = 'online'; break; case TtsWorkMode.offline: modeStr = 'offline'; break; case TtsWorkMode.both: modeStr = 'both'; break; case TtsWorkMode.alternate: modeStr = 'alternate'; break; case TtsWorkMode.file: modeStr = 'file'; break; } return await _channel.invokeMethod('setWorkMode', { 'mode': modeStr, }) ?? false; } /// 设置文本类型 /// /// [type] 文本类型,plain或ssml Future setTextType(TtsTextType type) async { String typeStr; switch (type) { case TtsTextType.plain: typeStr = 'plain'; break; case TtsTextType.ssml: typeStr = 'ssml'; break; } return await _channel.invokeMethod('setTextType', { 'type': typeStr, }) ?? false; } /// 设置是否启用缓存 /// /// [enable] 是否启用 Future setEnableCache(bool enable) async { return await _channel.invokeMethod('setEnableCache', { 'enable': enable, }) ?? false; } /// 设置情感 /// /// [emotion] 情感,例如 neutral、happy、angry、sad等 Future setEmotion(String emotion) async { return await _channel.invokeMethod('setEmotion', { 'emotion': emotion, }) ?? false; } /// 设置是否启用情感预测 /// /// [enable] 是否启用 Future setEnableEmotionPredict(bool enable) async { return await _channel.invokeMethod('setEnableEmotionPredict', { 'enable': enable, }) ?? false; } /// 设置是否启用声音克隆 /// /// [enable] 是否启用 /// [backendCluster] 后端集群 Future setEnableVoiceClone({ required bool enable, String backendCluster = '', }) async { return await _channel.invokeMethod('setEnableVoiceClone', { 'enable': enable, 'backendCluster': backendCluster, }) ?? false; } /// 设置是否启用回声消除 /// /// [enable] 是否启用 Future setEnableAEC(bool enable) async { return await _channel.invokeMethod('setEnableAEC', { 'enable': enable, }) ?? false; } /// 下载离线资源 /// /// [voiceTypes] 音色类型列表 /// [languages] 语言列表 Future downloadOfflineResource({ List voiceTypes = const ['qingxin'], List languages = const ['zh-CN'], }) async { return await _channel.invokeMethod('downloadOfflineResource', { 'voiceTypes': voiceTypes, 'languages': languages, }) ?? false; } /// 设置语音参数 /// /// [rate] 语速 -500~500 /// [volume] 音量 0~100 /// [pitch] 音调 -500~500 /// [silenceDuration] 静音时长,毫秒 Future setSpeechParams({ int rate = 0, int volume = 100, int pitch = 0, int silenceDuration = 0, }) async { return await _channel.invokeMethod('setSpeechParams', { 'rate': rate, 'volume': volume, 'pitch': pitch, 'silenceDuration': silenceDuration, }) ?? false; } /// 设置音频输出类型 /// /// [outputType] 输出类型,speaker(扬声器),earpiece(听筒),auto(自动) Future setAudioOutputType(String outputType) async { return await _channel.invokeMethod('setAudioOutputType', { 'outputType': outputType, }) ?? false; } /// 合成并播放文本 /// /// [text] 待合成的文本 Future speakText(String text) async { return await _channel.invokeMethod('speakText', { 'text': text, }) ?? false; } /// 使用大模型合成并播放文本 /// /// [text] 待合成的文本 /// [voiceId] 声音ID /// [params] 额外参数,JSON字符串 Future speakWithBigModel({ required String text, required String voiceId, String params = '', }) async { return await _channel.invokeMethod('speakWithBigModel', { 'text': text, 'voiceId': voiceId, 'params': params, }) ?? false; } /// 暂停播放 Future pausePlayback() async { return await _channel.invokeMethod('pausePlayback') ?? false; } /// 恢复播放 Future resumePlayback() async { return await _channel.invokeMethod('resumePlayback') ?? false; } /// 停止播放 Future stopSpeaking() async { return await _channel.invokeMethod('stopSpeaking') ?? false; } /// 释放TTS资源 Future dispose() async { return await _channel.invokeMethod('dispose') ?? false; } }