Browse Source

修复ios通话奔溃问题,语言不播报问题

weicu
fdp 1 year ago
parent
commit
fab2286cdf
  1. 152
      lib/data/services/language_manager.dart
  2. 11
      local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrToAsr.kt
  3. 33
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/IntegratedSpeechTranslationService.swift
  4. 56
      local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/VolcanoTranslationServiceImpl.swift

152
lib/data/services/language_manager.dart

@ -5,22 +5,22 @@ import '../../core/utils/logger.dart';
class LanguageInfo { class LanguageInfo {
/// 短代码,如 'zh', 'en' /// 短代码,如 'zh', 'en'
final String shortCode; final String shortCode;
/// 中文名称 /// 中文名称
final String chineseName; final String chineseName;
/// 英文名称 /// 英文名称
final String englishName; final String englishName;
/// Azure ASR 语言代码,如 'zh-CN', 'en-US' /// Azure ASR 语言代码,如 'zh-CN', 'en-US'
final String asrCode; final String asrCode;
/// Azure TTS 语音名称 /// Azure TTS 语音名称
final String ttsVoiceName; final String ttsVoiceName;
/// 备注信息 /// 备注信息
final String? note; final String? note;
LanguageInfo({ LanguageInfo({
required this.shortCode, required this.shortCode,
required this.chineseName, required this.chineseName,
@ -35,30 +35,30 @@ class LanguageInfo {
class LanguageManager extends GetxService { class LanguageManager extends GetxService {
// 单例实例 // 单例实例
static LanguageManager? _instance; static LanguageManager? _instance;
// 单例工厂方法 // 单例工厂方法
factory LanguageManager() { factory LanguageManager() {
_instance ??= LanguageManager._internal(); _instance ??= LanguageManager._internal();
return _instance!; return _instance!;
} }
// 私有构造函数 // 私有构造函数
LanguageManager._internal() { LanguageManager._internal() {
_initLanguageMap(); _initLanguageMap();
} }
// 语言信息映射表,以 ASR 代码为键 // 语言信息映射表,以 ASR 代码为键
final Map<String, LanguageInfo> _languageMap = {}; final Map<String, LanguageInfo> _languageMap = {};
// 中文名称到 ASR 代码的映射 // 中文名称到 ASR 代码的映射
final Map<String, String> _chineseNameToAsrCodeMap = {}; final Map<String, String> _chineseNameToAsrCodeMap = {};
// 英文名称到 ASR 代码的映射 // 英文名称到 ASR 代码的映射
final Map<String, String> _englishNameToAsrCodeMap = {}; final Map<String, String> _englishNameToAsrCodeMap = {};
// 短代码到 ASR 代码的映射 // 短代码到 ASR 代码的映射
final Map<String, String> _shortCodeToAsrCodeMap = {}; final Map<String, String> _shortCodeToAsrCodeMap = {};
/// 初始化语言映射表 /// 初始化语言映射表
void _initLanguageMap() { void _initLanguageMap() {
// 中文相关 // 中文相关
@ -69,7 +69,7 @@ class LanguageManager extends GetxService {
asrCode: 'zh-CN', asrCode: 'zh-CN',
ttsVoiceName: 'zh-CN-XiaoxiaoNeural', ttsVoiceName: 'zh-CN-XiaoxiaoNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'zh-Hant', shortCode: 'zh-Hant',
chineseName: '中文(繁体)', chineseName: '中文(繁体)',
@ -77,7 +77,7 @@ class LanguageManager extends GetxService {
asrCode: 'zh-TW', asrCode: 'zh-TW',
ttsVoiceName: 'zh-TW-HsiaoChenNeural', ttsVoiceName: 'zh-TW-HsiaoChenNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'zh-Hant-hk', shortCode: 'zh-Hant-hk',
chineseName: '中文(香港繁体)', chineseName: '中文(香港繁体)',
@ -85,7 +85,7 @@ class LanguageManager extends GetxService {
asrCode: 'zh-HK', asrCode: 'zh-HK',
ttsVoiceName: 'zh-HK-HiuMaanNeural', ttsVoiceName: 'zh-HK-HiuMaanNeural',
); );
// 英语相关 // 英语相关
_addLanguage( _addLanguage(
shortCode: 'en', shortCode: 'en',
@ -94,7 +94,7 @@ class LanguageManager extends GetxService {
asrCode: 'en-US', asrCode: 'en-US',
ttsVoiceName: 'en-US-AriaNeural', ttsVoiceName: 'en-US-AriaNeural',
); );
// 日语相关 // 日语相关
_addLanguage( _addLanguage(
shortCode: 'ja', shortCode: 'ja',
@ -103,7 +103,7 @@ class LanguageManager extends GetxService {
asrCode: 'ja-JP', asrCode: 'ja-JP',
ttsVoiceName: 'ja-JP-NanamiNeural', ttsVoiceName: 'ja-JP-NanamiNeural',
); );
// 韩语相关 // 韩语相关
_addLanguage( _addLanguage(
shortCode: 'ko', shortCode: 'ko',
@ -112,7 +112,7 @@ class LanguageManager extends GetxService {
asrCode: 'ko-KR', asrCode: 'ko-KR',
ttsVoiceName: 'ko-KR-SunHiNeural', ttsVoiceName: 'ko-KR-SunHiNeural',
); );
// 欧洲语言 // 欧洲语言
_addLanguage( _addLanguage(
shortCode: 'fr', shortCode: 'fr',
@ -121,7 +121,7 @@ class LanguageManager extends GetxService {
asrCode: 'fr-FR', asrCode: 'fr-FR',
ttsVoiceName: 'fr-FR-DeniseNeural', ttsVoiceName: 'fr-FR-DeniseNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'es', shortCode: 'es',
chineseName: '西班牙语', chineseName: '西班牙语',
@ -129,7 +129,7 @@ class LanguageManager extends GetxService {
asrCode: 'es-ES', asrCode: 'es-ES',
ttsVoiceName: 'es-ES-ElviraNeural', ttsVoiceName: 'es-ES-ElviraNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'pt', shortCode: 'pt',
chineseName: '葡萄牙语', chineseName: '葡萄牙语',
@ -137,7 +137,7 @@ class LanguageManager extends GetxService {
asrCode: 'pt-BR', asrCode: 'pt-BR',
ttsVoiceName: 'pt-BR-FranciscaNeural', ttsVoiceName: 'pt-BR-FranciscaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'it', shortCode: 'it',
chineseName: '意大利语', chineseName: '意大利语',
@ -145,7 +145,7 @@ class LanguageManager extends GetxService {
asrCode: 'it-IT', asrCode: 'it-IT',
ttsVoiceName: 'it-IT-ElsaNeural', ttsVoiceName: 'it-IT-ElsaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'de', shortCode: 'de',
chineseName: '德语', chineseName: '德语',
@ -153,7 +153,7 @@ class LanguageManager extends GetxService {
asrCode: 'de-DE', asrCode: 'de-DE',
ttsVoiceName: 'de-DE-KatjaNeural', ttsVoiceName: 'de-DE-KatjaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'ru', shortCode: 'ru',
chineseName: '俄语', chineseName: '俄语',
@ -161,7 +161,7 @@ class LanguageManager extends GetxService {
asrCode: 'ru-RU', asrCode: 'ru-RU',
ttsVoiceName: 'ru-RU-SvetlanaNeural', ttsVoiceName: 'ru-RU-SvetlanaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'pl', shortCode: 'pl',
chineseName: '波兰语', chineseName: '波兰语',
@ -169,7 +169,7 @@ class LanguageManager extends GetxService {
asrCode: 'pl-PL', asrCode: 'pl-PL',
ttsVoiceName: 'pl-PL-AgnieszkaNeural', ttsVoiceName: 'pl-PL-AgnieszkaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'nl', shortCode: 'nl',
chineseName: '荷兰语', chineseName: '荷兰语',
@ -177,7 +177,7 @@ class LanguageManager extends GetxService {
asrCode: 'nl-NL', asrCode: 'nl-NL',
ttsVoiceName: 'nl-NL-ColetteNeural', ttsVoiceName: 'nl-NL-ColetteNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'sv', shortCode: 'sv',
chineseName: '瑞典语', chineseName: '瑞典语',
@ -185,7 +185,7 @@ class LanguageManager extends GetxService {
asrCode: 'sv-SE', asrCode: 'sv-SE',
ttsVoiceName: 'sv-SE-SofieNeural', ttsVoiceName: 'sv-SE-SofieNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'cs', shortCode: 'cs',
chineseName: '捷克语', chineseName: '捷克语',
@ -193,7 +193,7 @@ class LanguageManager extends GetxService {
asrCode: 'cs-CZ', asrCode: 'cs-CZ',
ttsVoiceName: 'cs-CZ-VlastaNeural', ttsVoiceName: 'cs-CZ-VlastaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'el', shortCode: 'el',
chineseName: '现代希腊语', chineseName: '现代希腊语',
@ -201,7 +201,7 @@ class LanguageManager extends GetxService {
asrCode: 'el-GR', asrCode: 'el-GR',
ttsVoiceName: 'el-GR-AthinaNeural', ttsVoiceName: 'el-GR-AthinaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'ro', shortCode: 'ro',
chineseName: '罗马尼亚语', chineseName: '罗马尼亚语',
@ -209,7 +209,7 @@ class LanguageManager extends GetxService {
asrCode: 'ro-RO', asrCode: 'ro-RO',
ttsVoiceName: 'ro-RO-AlinaNeural', ttsVoiceName: 'ro-RO-AlinaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'hu', shortCode: 'hu',
chineseName: '匈牙利语', chineseName: '匈牙利语',
@ -217,7 +217,7 @@ class LanguageManager extends GetxService {
asrCode: 'hu-HU', asrCode: 'hu-HU',
ttsVoiceName: 'hu-HU-NoemiNeural', ttsVoiceName: 'hu-HU-NoemiNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'uk', shortCode: 'uk',
chineseName: '乌克兰语', chineseName: '乌克兰语',
@ -225,7 +225,7 @@ class LanguageManager extends GetxService {
asrCode: 'uk-UA', asrCode: 'uk-UA',
ttsVoiceName: 'uk-UA-PolinaNeural', ttsVoiceName: 'uk-UA-PolinaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'da', shortCode: 'da',
chineseName: '丹麦语', chineseName: '丹麦语',
@ -233,7 +233,7 @@ class LanguageManager extends GetxService {
asrCode: 'da-DK', asrCode: 'da-DK',
ttsVoiceName: 'da-DK-ChristelNeural', ttsVoiceName: 'da-DK-ChristelNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'fi', shortCode: 'fi',
chineseName: '芬兰语', chineseName: '芬兰语',
@ -241,7 +241,7 @@ class LanguageManager extends GetxService {
asrCode: 'fi-FI', asrCode: 'fi-FI',
ttsVoiceName: 'fi-FI-NooraNeural', ttsVoiceName: 'fi-FI-NooraNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'no', shortCode: 'no',
chineseName: '挪威语', chineseName: '挪威语',
@ -249,7 +249,7 @@ class LanguageManager extends GetxService {
asrCode: 'nb-NO', asrCode: 'nb-NO',
ttsVoiceName: 'nb-NO-IselinNeural', ttsVoiceName: 'nb-NO-IselinNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'hr', shortCode: 'hr',
chineseName: '克罗地亚语', chineseName: '克罗地亚语',
@ -257,7 +257,7 @@ class LanguageManager extends GetxService {
asrCode: 'hr-HR', asrCode: 'hr-HR',
ttsVoiceName: 'hr-HR-GabrijelaNeural', ttsVoiceName: 'hr-HR-GabrijelaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'ca', shortCode: 'ca',
chineseName: '加泰隆语', chineseName: '加泰隆语',
@ -265,7 +265,7 @@ class LanguageManager extends GetxService {
asrCode: 'ca-ES', asrCode: 'ca-ES',
ttsVoiceName: 'ca-ES-JoanaNeural', ttsVoiceName: 'ca-ES-JoanaNeural',
); );
// 亚洲语言 // 亚洲语言
_addLanguage( _addLanguage(
shortCode: 'ar', shortCode: 'ar',
@ -274,7 +274,7 @@ class LanguageManager extends GetxService {
asrCode: 'ar-EG', asrCode: 'ar-EG',
ttsVoiceName: 'ar-EG-SalmaNeural', ttsVoiceName: 'ar-EG-SalmaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'th', shortCode: 'th',
chineseName: '泰语', chineseName: '泰语',
@ -282,7 +282,7 @@ class LanguageManager extends GetxService {
asrCode: 'th-TH', asrCode: 'th-TH',
ttsVoiceName: 'th-TH-PremwadeeNeural', ttsVoiceName: 'th-TH-PremwadeeNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'vi', shortCode: 'vi',
chineseName: '越南语', chineseName: '越南语',
@ -290,7 +290,7 @@ class LanguageManager extends GetxService {
asrCode: 'vi-VN', asrCode: 'vi-VN',
ttsVoiceName: 'vi-VN-HoaiMyNeural', ttsVoiceName: 'vi-VN-HoaiMyNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'id', shortCode: 'id',
chineseName: '印尼语', chineseName: '印尼语',
@ -298,7 +298,7 @@ class LanguageManager extends GetxService {
asrCode: 'id-ID', asrCode: 'id-ID',
ttsVoiceName: 'id-ID-GadisNeural', ttsVoiceName: 'id-ID-GadisNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'hi', shortCode: 'hi',
chineseName: '印地语', chineseName: '印地语',
@ -306,7 +306,7 @@ class LanguageManager extends GetxService {
asrCode: 'hi-IN', asrCode: 'hi-IN',
ttsVoiceName: 'hi-IN-SwaraNeural', ttsVoiceName: 'hi-IN-SwaraNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'tr', shortCode: 'tr',
chineseName: '土耳其语', chineseName: '土耳其语',
@ -314,7 +314,7 @@ class LanguageManager extends GetxService {
asrCode: 'tr-TR', asrCode: 'tr-TR',
ttsVoiceName: 'tr-TR-EmelNeural', ttsVoiceName: 'tr-TR-EmelNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'ms', shortCode: 'ms',
chineseName: '马来语', chineseName: '马来语',
@ -322,7 +322,7 @@ class LanguageManager extends GetxService {
asrCode: 'ms-MY', asrCode: 'ms-MY',
ttsVoiceName: 'ms-MY-YasminNeural', ttsVoiceName: 'ms-MY-YasminNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'bn', shortCode: 'bn',
chineseName: '孟加拉语', chineseName: '孟加拉语',
@ -330,7 +330,7 @@ class LanguageManager extends GetxService {
asrCode: 'bn-IN', asrCode: 'bn-IN',
ttsVoiceName: 'bn-IN-TanishaaNeural', ttsVoiceName: 'bn-IN-TanishaaNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'ta', shortCode: 'ta',
chineseName: '泰米尔语', chineseName: '泰米尔语',
@ -338,7 +338,7 @@ class LanguageManager extends GetxService {
asrCode: 'ta-IN', asrCode: 'ta-IN',
ttsVoiceName: 'ta-IN-PallaviNeural', ttsVoiceName: 'ta-IN-PallaviNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'te', shortCode: 'te',
chineseName: '泰卢固语', chineseName: '泰卢固语',
@ -346,7 +346,7 @@ class LanguageManager extends GetxService {
asrCode: 'te-IN', asrCode: 'te-IN',
ttsVoiceName: 'te-IN-ShrutiNeural', ttsVoiceName: 'te-IN-ShrutiNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'mr', shortCode: 'mr',
chineseName: '马拉提语', chineseName: '马拉提语',
@ -354,7 +354,7 @@ class LanguageManager extends GetxService {
asrCode: 'mr-IN', asrCode: 'mr-IN',
ttsVoiceName: 'mr-IN-AarohiNeural', ttsVoiceName: 'mr-IN-AarohiNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'ur', shortCode: 'ur',
chineseName: '乌尔都语', chineseName: '乌尔都语',
@ -362,7 +362,7 @@ class LanguageManager extends GetxService {
asrCode: 'ur-IN', asrCode: 'ur-IN',
ttsVoiceName: 'ur-IN-GulNeural', ttsVoiceName: 'ur-IN-GulNeural',
); );
_addLanguage( _addLanguage(
shortCode: 'fa', shortCode: 'fa',
chineseName: '波斯语', chineseName: '波斯语',
@ -370,7 +370,7 @@ class LanguageManager extends GetxService {
asrCode: 'fa-IR', asrCode: 'fa-IR',
ttsVoiceName: 'fa-IR-DilaraNeural', ttsVoiceName: 'fa-IR-DilaraNeural',
); );
// 非洲语言 // 非洲语言
_addLanguage( _addLanguage(
shortCode: 'sw', shortCode: 'sw',
@ -379,10 +379,10 @@ class LanguageManager extends GetxService {
asrCode: 'sw-KE', asrCode: 'sw-KE',
ttsVoiceName: 'sw-KE-ZuriNeural', ttsVoiceName: 'sw-KE-ZuriNeural',
); );
Logger.info('语言管理器初始化完成,共加载 ${_languageMap.length} 种语言'); Logger.info('语言管理器初始化完成,共加载 ${_languageMap.length} 种语言');
} }
/// 添加语言信息到映射表 /// 添加语言信息到映射表
void _addLanguage({ void _addLanguage({
required String shortCode, required String shortCode,
@ -400,133 +400,133 @@ class LanguageManager extends GetxService {
ttsVoiceName: ttsVoiceName, ttsVoiceName: ttsVoiceName,
note: note, note: note,
); );
_languageMap[asrCode] = languageInfo; _languageMap[asrCode] = languageInfo;
_chineseNameToAsrCodeMap[chineseName] = asrCode; _chineseNameToAsrCodeMap[chineseName] = asrCode;
_englishNameToAsrCodeMap[englishName] = asrCode; _englishNameToAsrCodeMap[englishName] = asrCode;
_shortCodeToAsrCodeMap[shortCode] = asrCode; _shortCodeToAsrCodeMap[shortCode] = asrCode;
} }
/// 获取所有支持的语言信息 /// 获取所有支持的语言信息
Map<String, LanguageInfo> getAllLanguages() { Map<String, LanguageInfo> getAllLanguages() {
return Map.from(_languageMap); return Map.from(_languageMap);
} }
/// 获取所有支持的语言的中文名称 /// 获取所有支持的语言的中文名称
List<String> getAllChineseNames() { List<String> getAllChineseNames() {
return _chineseNameToAsrCodeMap.keys.toList(); return _chineseNameToAsrCodeMap.keys.toList();
} }
/// 获取所有支持的语言的英文名称 /// 获取所有支持的语言的英文名称
List<String> getAllEnglishNames() { List<String> getAllEnglishNames() {
return _englishNameToAsrCodeMap.keys.toList(); return _englishNameToAsrCodeMap.keys.toList();
} }
/// 根据 ASR 代码获取语言信息 /// 根据 ASR 代码获取语言信息
LanguageInfo? getLanguageByAsrCode(String asrCode) { LanguageInfo? getLanguageByAsrCode(String asrCode) {
return _languageMap[asrCode]; return _languageMap[asrCode];
} }
/// 根据中文名称获取语言信息 /// 根据中文名称获取语言信息
LanguageInfo? getLanguageByChineseName(String chineseName) { LanguageInfo? getLanguageByChineseName(String chineseName) {
final asrCode = _chineseNameToAsrCodeMap[chineseName]; final asrCode = _chineseNameToAsrCodeMap[chineseName];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]; return _languageMap[asrCode];
} }
/// 根据英文名称获取语言信息 /// 根据英文名称获取语言信息
LanguageInfo? getLanguageByEnglishName(String englishName) { LanguageInfo? getLanguageByEnglishName(String englishName) {
final asrCode = _englishNameToAsrCodeMap[englishName]; final asrCode = _englishNameToAsrCodeMap[englishName];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]; return _languageMap[asrCode];
} }
/// 根据短代码获取语言信息 /// 根据短代码获取语言信息
LanguageInfo? getLanguageByShortCode(String shortCode) { LanguageInfo? getLanguageByShortCode(String shortCode) {
final asrCode = _shortCodeToAsrCodeMap[shortCode]; final asrCode = _shortCodeToAsrCodeMap[shortCode];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]; return _languageMap[asrCode];
} }
/// 根据中文名称获取 ASR 代码 /// 根据中文名称获取 ASR 代码
String? getAsrCodeByChineseName(String chineseName) { String? getAsrCodeByChineseName(String chineseName) {
return _chineseNameToAsrCodeMap[chineseName]; return _chineseNameToAsrCodeMap[chineseName];
} }
/// 根据英文名称获取 ASR 代码 /// 根据英文名称获取 ASR 代码
String? getAsrCodeByEnglishName(String englishName) { String? getAsrCodeByEnglishName(String englishName) {
return _englishNameToAsrCodeMap[englishName]; return _englishNameToAsrCodeMap[englishName];
} }
/// 根据短代码获取 ASR 代码 /// 根据短代码获取 ASR 代码
String? getAsrCodeByShortCode(String shortCode) { String? getAsrCodeByShortCode(String shortCode) {
return _shortCodeToAsrCodeMap[shortCode]; return _shortCodeToAsrCodeMap[shortCode];
} }
/// 根据 ASR 代码获取中文名称 /// 根据 ASR 代码获取中文名称
String? getChineseNameByAsrCode(String asrCode) { String? getChineseNameByAsrCode(String asrCode) {
final languageInfo = _languageMap[asrCode]; final languageInfo = _languageMap[asrCode];
return languageInfo?.chineseName; return languageInfo?.chineseName;
} }
/// 根据 ASR 代码获取英文名称 /// 根据 ASR 代码获取英文名称
String? getEnglishNameByAsrCode(String asrCode) { String? getEnglishNameByAsrCode(String asrCode) {
final languageInfo = _languageMap[asrCode]; final languageInfo = _languageMap[asrCode];
return languageInfo?.englishName; return languageInfo?.englishName;
} }
/// 根据 ASR 代码获取短代码 /// 根据 ASR 代码获取短代码
String? getShortCodeByAsrCode(String asrCode) { String? getShortCodeByAsrCode(String asrCode) {
final languageInfo = _languageMap[asrCode]; final languageInfo = _languageMap[asrCode];
return languageInfo?.shortCode; return languageInfo?.shortCode;
} }
/// 根据 ASR 代码获取 TTS 语音名称 /// 根据 ASR 代码获取 TTS 语音名称
String? getTtsVoiceNameByAsrCode(String asrCode) { String? getTtsVoiceNameByAsrCode(String asrCode) {
final languageInfo = _languageMap[asrCode]; final languageInfo = _languageMap[asrCode];
return languageInfo?.ttsVoiceName; return languageInfo?.ttsVoiceName;
} }
/// 根据中文名称获取 TTS 语音名称 /// 根据中文名称获取 TTS 语音名称
String? getTtsVoiceNameByChineseName(String chineseName) { String? getTtsVoiceNameByChineseName(String chineseName) {
final asrCode = _chineseNameToAsrCodeMap[chineseName]; final asrCode = _chineseNameToAsrCodeMap[chineseName];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]?.ttsVoiceName; return _languageMap[asrCode]?.ttsVoiceName;
} }
/// 根据短代码获取中文名称 /// 根据短代码获取中文名称
String? getChineseNameByShortCode(String shortCode) { String? getChineseNameByShortCode(String shortCode) {
final asrCode = _shortCodeToAsrCodeMap[shortCode]; final asrCode = _shortCodeToAsrCodeMap[shortCode];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]?.chineseName; return _languageMap[asrCode]?.chineseName;
} }
/// 根据短代码获取英文名称 /// 根据短代码获取英文名称
String? getEnglishNameByShortCode(String shortCode) { String? getEnglishNameByShortCode(String shortCode) {
final asrCode = _shortCodeToAsrCodeMap[shortCode]; final asrCode = _shortCodeToAsrCodeMap[shortCode];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]?.englishName; return _languageMap[asrCode]?.englishName;
} }
/// 根据短代码获取 TTS 语音名称 /// 根据短代码获取 TTS 语音名称
String? getTtsVoiceNameByShortCode(String shortCode) { String? getTtsVoiceNameByShortCode(String shortCode) {
final asrCode = _shortCodeToAsrCodeMap[shortCode]; final asrCode = _shortCodeToAsrCodeMap[shortCode];
if (asrCode == null) return null; if (asrCode == null) return null;
return _languageMap[asrCode]?.ttsVoiceName; return _languageMap[asrCode]?.ttsVoiceName;
} }
/// 获取中文名称到 ASR 代码的映射 /// 获取中文名称到 ASR 代码的映射
Map<String, String> getChineseNameToAsrCodeMap() { Map<String, String> getChineseNameToAsrCodeMap() {
return Map.from(_chineseNameToAsrCodeMap); return Map.from(_chineseNameToAsrCodeMap);
} }
/// 获取英文名称到 ASR 代码的映射 /// 获取英文名称到 ASR 代码的映射
Map<String, String> getEnglishNameToAsrCodeMap() { Map<String, String> getEnglishNameToAsrCodeMap() {
return Map.from(_englishNameToAsrCodeMap); return Map.from(_englishNameToAsrCodeMap);
} }
/// 获取短代码到 ASR 代码的映射 /// 获取短代码到 ASR 代码的映射
Map<String, String> getShortCodeToAsrCodeMap() { Map<String, String> getShortCodeToAsrCodeMap() {
return Map.from(_shortCodeToAsrCodeMap); return Map.from(_shortCodeToAsrCodeMap);
} }
} }

11
local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrToAsr.kt

@ -1315,7 +1315,16 @@ class VolcanoTranslationServiceImpl :
"ms-MY" to "ms", // 马来语(马来西亚) "ms-MY" to "ms", // 马来语(马来西亚)
"id-ID" to "id", // 印尼语(印尼) "id-ID" to "id", // 印尼语(印尼)
"fil-PH" to "tl", // 菲律宾语(菲律宾) "fil-PH" to "tl", // 菲律宾语(菲律宾)
"sv-SE" to "sv", // 瑞典语(瑞典)
"ro-RO" to "ro", // 罗马尼亚语(罗马尼亚)
"hu-HU" to "hu", // 匈牙利语(匈牙利)
"da-DK" to "da", // 丹麦语(丹麦)
"fi-FI" to "fi", // 芬兰语(芬兰)
"nb-NO" to "nb", // 挪威语(挪威)
"hr-HR" to "hr", // 克罗地亚语(克罗地亚)
"ca-ES" to "ca", // 加泰隆语
"mr-IN" to "mr", // 马拉地语(印度)
"ur-IN" to "ur", // 乌尔都语(印度)
// 欧洲 // 欧洲
"en-US" to "en", // 英语(美国) "en-US" to "en", // 英语(美国)
"en-GB" to "en", // 英语(英国) "en-GB" to "en", // 英语(英国)

33
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/IntegratedSpeechTranslationService.swift

@ -605,13 +605,36 @@ import os.log
audioProcessor?.stopMicrophoneCapture() audioProcessor?.stopMicrophoneCapture()
recordFile?.closeFile(isSave: true) recordFile?.closeFile(isSave: true)
// 等待当前处理完成 // 使用后台队列等待当前处理完成,避免阻塞主线程
while serviceState.isTranslating || serviceState.isSynthesizing { DispatchQueue.global(qos: .userInitiated).async { [weak self] in
Thread.sleep(forTimeInterval: 0.1) guard let self = self else { return }
// 设置超时时间,避免无限等待
let timeout = DispatchTime.now() + .seconds(5)
while (self.serviceState.isTranslating || self.serviceState.isSynthesizing) && DispatchTime.now() < timeout {
Thread.sleep(forTimeInterval: 0.1)
}
// 强制停止合成器(如果仍在运行)
if self.serviceState.isSynthesizing {
do {
try self.synthesizer?.stopSpeaking()
} catch {
os_log("停止语音合成失败: %@", log: self.log, type: .error, error.localizedDescription)
}
self.serviceState.isSynthesizing = false
DispatchQueue.main.async {
self.eventCallback?.onStateChanged(component: "Synthesis", isActive: false)
}
}
DispatchQueue.main.async {
os_log("停止连续语音翻译", log: self.log, type: .info)
}
} }
os_log("停止连续语音翻译", log: log, type: .info)
} catch { } catch {
os_log("停止翻译失败: %@", log: log, type: .error, error.localizedDescription) os_log("停止翻译失败: %@", log: log, type: .error, error.localizedDescription)
eventCallback?.onError(component: "Service", error: "停止失败: \(error.localizedDescription)") eventCallback?.onError(component: "Service", error: "停止失败: \(error.localizedDescription)")

56
local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/VolcanoTranslationServiceImpl.swift

@ -24,6 +24,8 @@ public class VolcanoTranslationServiceImpl: IntegratedSpeechTranslationService.T
private var region = "cn-north-1" private var region = "cn-north-1"
private var maxRetryAttempts = 3 private var maxRetryAttempts = 3
private var timeout: TimeInterval = 10.0 private var timeout: TimeInterval = 10.0
private var isDisposed = false // 添加释放状态标志
private let disposeLock = NSLock() // 添加线程安全锁
// HTTP客户端 // HTTP客户端
private lazy var urlSession: URLSession = { private lazy var urlSession: URLSession = {
@ -52,7 +54,16 @@ public class VolcanoTranslationServiceImpl: IntegratedSpeechTranslationService.T
"ms-MY": "ms", // 马来语(马来西亚) "ms-MY": "ms", // 马来语(马来西亚)
"id-ID": "id", // 印尼语(印尼) "id-ID": "id", // 印尼语(印尼)
"fil-PH": "tl", // 菲律宾语(菲律宾) "fil-PH": "tl", // 菲律宾语(菲律宾)
"sv-SE": "sv", // 瑞典语(瑞典)
"ro-RO": "ro", // 罗马尼亚语(罗马尼亚)
"hu-HU": "hu", // 匈牙利语(匈牙利)
"da-DK": "da", // 丹麦语(丹麦)
"fi-FI": "fi", // 芬兰语(芬兰)
"nb-NO": "nb", // 挪威语(挪威)
"hr-HR": "hr", // 克罗地亚语(克罗地亚)
"ca-ES": "ca", // 加泰隆语
"mr-IN": "mr", // 马拉地语(印度)
"ur-IN": "ur", // 乌尔都语(印度)
// 欧洲 // 欧洲
"en-US": "en", // 英语(美国) "en-US": "en", // 英语(美国)
"en-GB": "en", // 英语(英国) "en-GB": "en", // 英语(英国)
@ -150,11 +161,25 @@ public class VolcanoTranslationServiceImpl: IntegratedSpeechTranslationService.T
/** /**
* 释放资源 * 释放资源
* 添加线程安全保护,防止重复释放
*/ */
public func dispose() { public func dispose() {
disposeLock.lock()
defer { disposeLock.unlock() }
if isDisposed {
os_log("翻译服务已经释放,跳过重复释放", log: log, type: .info)
return
}
os_log("开始释放翻译服务资源", log: log, type: .info)
isDisposed = true
isInitialized = false isInitialized = false
// 取消并失效URLSession
urlSession.invalidateAndCancel() urlSession.invalidateAndCancel()
os_log("火山翻译服务已释放", log: log, type: .info)
os_log("翻译服务资源释放完成", log: log, type: .info)
} }
// MARK: - Private Methods // MARK: - Private Methods
@ -203,6 +228,7 @@ public class VolcanoTranslationServiceImpl: IntegratedSpeechTranslationService.T
/** /**
* 执行翻译 * 执行翻译
* 添加服务状态检查,防止在已释放的会话中创建任务
*/ */
private func performTranslation( private func performTranslation(
text: String, text: String,
@ -210,6 +236,19 @@ public class VolcanoTranslationServiceImpl: IntegratedSpeechTranslationService.T
targetLanguage: String targetLanguage: String
) async -> IntegratedSpeechTranslationService.TranslationResult { ) async -> IntegratedSpeechTranslationService.TranslationResult {
// 检查服务是否已被释放
disposeLock.lock()
let disposed = isDisposed
disposeLock.unlock()
if disposed {
os_log("翻译服务已释放,取消翻译请求", log: log, type: .error)
return IntegratedSpeechTranslationService.TranslationResult(
success: false,
error: "翻译服务已释放"
)
}
do { do {
// 转换语言代码 // 转换语言代码
let sourceCode = getLanguageCode(languageCode: sourceLanguage) let sourceCode = getLanguageCode(languageCode: sourceLanguage)
@ -263,6 +302,19 @@ public class VolcanoTranslationServiceImpl: IntegratedSpeechTranslationService.T
os_log("发送翻译请求到: %@", log: log, type: .debug, url.absoluteString) os_log("发送翻译请求到: %@", log: log, type: .debug, url.absoluteString)
// 再次检查服务状态,防止在请求构建过程中被释放
disposeLock.lock()
let stillDisposed = isDisposed
disposeLock.unlock()
if stillDisposed {
os_log("翻译服务在请求过程中被释放,取消网络请求", log: log, type: .error)
return IntegratedSpeechTranslationService.TranslationResult(
success: false,
error: "翻译服务已释放"
)
}
// 发送请求 // 发送请求
let (data, response) = try await urlSession.data(for: request) let (data, response) = try await urlSession.data(for: request)

Loading…
Cancel
Save