diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index 25867c571..963f22c25 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -156,16 +156,21 @@ class BleManager extends GetxService { /// 设置BLE事件监听 void _setupBleListener() { + Logger.info('lxm--_setupBleListener被调用,开始设置BLE事件监听'); _statusSubscription?.cancel(); _dataSubscription?.cancel(); try { + Logger.info('lxm--开始监听BLE状态更新流'); // 监听BLE状态更新 _statusSubscription = _bleService.onStatusUpdated.listen( (event) { + Logger.info('lxm--收到BLE状态更新事件: $event'); if (event is Map) { + Logger.info('lxm--事件是Map类型,开始处理'); // 处理连接状态更新 if (event['type'] == 'connectionStateChanged') { + Logger.info('lxm--处理连接状态变化事件'); final state = event['state'] as int; final oldState = _connectionState.value; _connectionState.value = state; @@ -175,21 +180,23 @@ class BleManager extends GetxService { // 连接状态转换 if (state == BleConnectionState.connected) { - Logger.info('BLE设备已连接'); + Logger.info('lxm--BLE设备已连接'); _isConnected.value = true; // 在连接成功后延迟 300 毫秒获取设备信息(可根据需要调整时间) Future.delayed(const Duration(milliseconds: 300), () { // 可选:检查是否仍处于连接状态 if (_isConnected.value) { + Logger.info('lxm--连接后延迟获取设备信息(当前被注释)'); // fetchDeviceInfo(); } }); } else if (state == BleConnectionState.disconnected || state == BleConnectionState.error) { - Logger.info('BLE设备已断开或发生错误'); + Logger.info('lxm--BLE设备已断开或发生错误'); _isConnected.value = false; // 更新设备信息Add commentMore actions + Logger.info('lxm--断开连接时重置设备信息为0'); _updateDeviceInfoIfNeeded( batteryLevel: 0, leftEarBattery: 0, @@ -207,71 +214,99 @@ class BleManager extends GetxService { } } + Logger.info('lxm--准备调用_processDeviceInfo处理设备信息'); // 处理设备信息 _processDeviceInfo(event); + } else { + Logger.info('lxm--事件不是Map类型: ${event.runtimeType}'); } }, onError: (error) { - Logger.error('BLE状态事件流错误: $error'); + Logger.error('lxm--BLE状态事件流错误: $error'); }, ); + Logger.info('lxm--BLE状态监听器设置完成'); // 监听BLE数据流 } catch (e) { - Logger.error('设置BLE事件监听器失败: ${e.toString()}'); + Logger.error('lxm--设置BLE事件监听器失败: ${e.toString()}'); } } /// 处理来自原生层的设备信息 void _processDeviceInfo(Map event) { try { + Logger.info('lxm--_processDeviceInfo被调用'); + Logger.info('lxm--接收到的事件数据: $event'); + // 检查是否是设备信息响应 if (event.containsKey('command') && event.containsKey('success')) { + Logger.info('lxm--事件包含command和success字段'); final bool success = event['success'] as bool; + Logger.info('lxm--命令执行成功状态: $success'); + if (!success) { - Logger.warning('设备命令执行失败: ${event['command']}'); + Logger.warning('lxm--设备命令执行失败: ${event['command']}'); return; } // 根据命令类型处理不同信息 final command = event['command']; + Logger.info('lxm--命令类型: $command (${command.runtimeType})'); if (command is int) { + Logger.info('lxm--基于命令ID处理: $command'); // 基于命令ID处理 _processDeviceInfoByCommandId(command, event); } else if (command is String) { + Logger.info('lxm--基于命令名称处理: $command'); // 基于命令名称处理 _processDeviceInfoByCommandName(command, event); + } else { + Logger.warning('lxm--未知的命令类型: ${command.runtimeType}'); } + } else { + Logger.info('lxm--事件不包含command或success字段,跳过处理'); + Logger.info('lxm--事件包含的键: ${event.keys.toList()}'); } } catch (e) { - Logger.error('处理设备信息异常: ${e.toString()}'); + Logger.error('lxm--处理设备信息异常: ${e.toString()}'); + Logger.error('lxm--异常堆栈: ${StackTrace.current}'); } } /// 根据命令ID处理设备信息 void _processDeviceInfoByCommandId( int commandId, Map data) { + Logger.info('lxm--_processDeviceInfoByCommandId被调用,命令ID: $commandId'); + Logger.info('lxm--命令数据: $data'); + switch (commandId) { case BleCommands.GET_VERSION: + Logger.info('lxm--处理版本信息命令'); _updateVersionInfoFromData(data); break; case BleCommands.GET_PRODUCT_ID: + Logger.info('lxm--处理产品ID命令'); _updateProductIdFromData(data); break; case BleCommands.GET_PRODUCT_COLOR: + Logger.info('lxm--处理产品颜色命令(暂未实现)'); break; case BleCommands.GET_BATTERY_INFO: + Logger.info('lxm--处理电池信息命令,准备调用_updateBatteryInfoFromData'); _updateBatteryInfoFromData(data); + Logger.info('lxm--电池信息处理完成'); break; case BleCommands.CONTROL_CODEC: + Logger.info('lxm--处理编解码控制命令'); // 处理通话状态 print(" CONTROL_CODEC: $commandId,$data"); //_isCall.value = data['callStatus'] as bool? ?? false; break; default: + Logger.warning('lxm--未处理的命令ID: $commandId,数据: $data'); print(" 未处理的命令ID: $commandId,$data"); - Logger.info('未处理的命令ID: $commandId'); } } @@ -302,14 +337,34 @@ class BleManager extends GetxService { /// 更新电池信息 void _updateBatteryInfoFromData(Map data) { try { + Logger.info('lxm--_updateBatteryInfoFromData被调用'); + Logger.info('lxm--接收到的原始数据: $data'); + // 确保数据中包含电池信息 if (!data.containsKey('leftEarBattery') || !data.containsKey('rightEarBattery') || !data.containsKey('caseBattery')) { - Logger.warning('电池信息数据不完整'); + Logger.warning('lxm--电池信息数据不完整,缺少必要字段'); + Logger.warning('lxm--数据包含的键: ${data.keys.toList()}'); return; } + Logger.info('lxm--原始电池数据解析:'); + Logger.info( + 'lxm-- leftEarBattery原始值: ${data['leftEarBattery']} (类型: ${data['leftEarBattery'].runtimeType})'); + Logger.info( + 'lxm-- rightEarBattery原始值: ${data['rightEarBattery']} (类型: ${data['rightEarBattery'].runtimeType})'); + Logger.info( + 'lxm-- caseBattery原始值: ${data['caseBattery']} (类型: ${data['caseBattery'].runtimeType})'); + Logger.info( + 'lxm-- leftEarCharging原始值: ${data['leftEarCharging']} (类型: ${data['leftEarCharging'].runtimeType})'); + Logger.info( + 'lxm-- rightEarCharging原始值: ${data['rightEarCharging']} (类型: ${data['rightEarCharging'].runtimeType})'); + Logger.info( + 'lxm-- caseCharging原始值: ${data['caseCharging']} (类型: ${data['caseCharging'].runtimeType})'); + Logger.info( + 'lxm-- batteryLevel原始值: ${data['batteryLevel']} (类型: ${data['batteryLevel']?.runtimeType})'); + // 提取电池信息 final int leftBattery = (data['leftEarBattery'] as int? ?? 0) > 100 ? 0 @@ -329,6 +384,16 @@ class BleManager extends GetxService { // 获取整体电量(原生层使用左耳电量作为主要指示) final int overallBattery = data['batteryLevel'] as int? ?? leftBattery; + Logger.info('lxm--处理后的电池数据:'); + Logger.info('lxm-- leftBattery: $leftBattery'); + Logger.info('lxm-- rightBattery: $rightBattery'); + Logger.info('lxm-- caseBattery: $caseBattery'); + Logger.info('lxm-- leftCharging: $leftCharging'); + Logger.info('lxm-- rightCharging: $rightCharging'); + Logger.info('lxm-- caseCharging: $caseCharging'); + Logger.info('lxm-- overallBattery: $overallBattery'); + + Logger.info('lxm--准备调用_updateDeviceInfoIfNeeded'); // 更新设备信息 _updateDeviceInfoIfNeeded( batteryLevel: overallBattery, @@ -341,9 +406,10 @@ class BleManager extends GetxService { ); Logger.info( - '设备电池信息已更新: 电量=$overallBattery%, 左耳=$leftBattery%, 右耳=$rightBattery%, 充电仓=$caseBattery%'); + 'lxm--设备电池信息已更新: 电量=$overallBattery%, 左耳=$leftBattery%, 右耳=$rightBattery%, 充电仓=$caseBattery%'); } catch (e) { - Logger.error('更新电池信息失败: ${e.toString()}'); + Logger.error('lxm--更新电池信息失败: ${e.toString()}'); + Logger.error('lxm--错误堆栈: ${StackTrace.current}'); } } @@ -406,8 +472,18 @@ class BleManager extends GetxService { String? firmwareProductId, String? firmwareProductColor, }) { + Logger.info('lxm--_updateDeviceInfoIfNeeded被调用'); + Logger.info( + 'lxm--传入参数: batteryLevel=$batteryLevel, leftEarBattery=$leftEarBattery, rightEarBattery=$rightEarBattery, caseBattery=$caseBattery'); + Logger.info( + 'lxm--充电状态: leftEarCharging=$leftEarCharging, rightEarCharging=$rightEarCharging, caseCharging=$caseCharging'); + Logger.info('lxm--当前deviceInfo.value是否为null: ${deviceInfo.value == null}'); + // 如果设备信息已存在,则更新 if (deviceInfo.value != null) { + Logger.info('lxm--设备信息已存在,进行更新操作'); + Logger.info('lxm--更新前的设备信息: ${deviceInfo.value}'); + deviceInfo.value = deviceInfo.value!.copyWith( batteryLevel: batteryLevel ?? deviceInfo.value?.batteryLevel, leftEarBattery: leftEarBattery ?? deviceInfo.value?.leftEarBattery, @@ -423,17 +499,20 @@ class BleManager extends GetxService { firmwareProductColor: firmwareProductColor ?? deviceInfo.value!.firmwareProductColor, ); + + Logger.info('lxm--更新后的设备信息: ${deviceInfo.value}'); } // 创建设备信息 // 如果设备信息不存在,但有地址和名称,则创建新的设备信息 else if (deviceInfo.value == null && _isConnected.value && (firmwareVersion != null || batteryLevel != null)) { + Logger.info('lxm--设备信息不存在,创建新的设备信息对象'); // 使用保存的设备信息创建新的DeviceInfo对象 String deviceAddress = _currentDeviceAddress ?? ""; String deviceName = _currentDeviceName ?? ""; - Logger.info('创建新的设备信息对象: address=$deviceAddress, name=$deviceName'); + Logger.info('lxm--创建新的设备信息对象: address=$deviceAddress, name=$deviceName'); deviceInfo.value = DeviceInfo( address: deviceAddress, name: deviceName, @@ -448,6 +527,11 @@ class BleManager extends GetxService { firmwareProductId: firmwareProductId ?? '', firmwareProductColor: firmwareProductColor ?? '', ); + + Logger.info('lxm--新创建的设备信息: ${deviceInfo.value}'); + } else { + Logger.info( + 'lxm--不满足更新条件: deviceInfo.value == null: ${deviceInfo.value == null}, _isConnected.value: ${_isConnected.value}, firmwareVersion: $firmwareVersion, batteryLevel: $batteryLevel'); } } @@ -639,21 +723,28 @@ class BleManager extends GetxService { } } + Logger.info('lxm--准备调用AgentService.startAgentService启动BLE服务'); final result = await AgentService.startAgentService(config); + Logger.info('lxm--AgentService.startAgentService调用结果: $result'); if (result) { - Logger.info('BLE服务启动成功'); + Logger.info('lxm--BLE服务启动成功'); // 添加延迟以等待设备连接 + Logger.info('lxm--等待2秒让设备连接'); await Future.delayed(const Duration(seconds: 2)); // 检查连接状态 + Logger.info('lxm--检查设备连接状态'); final isConnected = await _bleService.isConnected(); + Logger.info('lxm--设备连接状态检查结果: $isConnected'); if (isConnected) { + Logger.info('lxm--设备已连接,更新连接状态'); _isConnected.value = true; _connectionState.value = BleConnectionState.connected; // 如果设备信息存在,则获取详细信息 + Logger.info('lxm--准备获取设备详细信息'); if (deviceInfo.value != null) { // 获取详细设备信息 // fetchDeviceInfo(); @@ -705,9 +796,12 @@ class BleManager extends GetxService { /// 主动获取电池信息 Future fetchBatteryInfo() async { try { - return await _bleService.getBatteryInfo(); + Logger.info('lxm--fetchBatteryInfo被调用,准备向设备发送获取电池信息指令'); + final result = await _bleService.getBatteryInfo(); + Logger.info('lxm--getBatteryInfo指令发送结果: $result'); + return result; } catch (e) { - Logger.error('获取电池信息失败: ${e.toString()}'); + Logger.error('lxm--获取电池信息失败: ${e.toString()}'); return false; } } diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart index 4e63d2c82..ebf33cd74 100644 --- a/lib/modules/home/controllers/home_controller.dart +++ b/lib/modules/home/controllers/home_controller.dart @@ -1,5 +1,5 @@ import 'package:get/get.dart'; -import 'dart:async'; +// 移除了dart:async导入,因为不再使用Timer import '../../../data/services/novice_guide_service.dart'; import '../../../routes/app_routes.dart'; import '../../../core/utils/logger.dart'; @@ -24,10 +24,7 @@ class HomeController extends GetxController { final _isFullyConnected = false.obs; String? _lastConnectedDeviceName; - // 添加电池信息定时刷新相关变量 - Timer? _batteryRefreshTimer; - static const Duration _batteryRefreshInterval = - Duration(seconds: 2); // 2秒刷新一次 + // 移除了电池信息定时刷新相关变量 // OTA检查服务 late final OtaCheckService _otaCheckService; @@ -37,21 +34,51 @@ class HomeController extends GetxController { BluetoothDevice? get currentDevice => _bluetoothManager.currentDevice; Rx get deviceInfo => _bleManager.deviceInfo; - final leftEarBattery = 0.obs; - final rightEarBattery = 0.obs; + static final leftEarBattery = 0.obs; + static final rightEarBattery = 0.obs; final caseBattery = 0.obs; final leftEarCharging = false.obs; final rightEarCharging = false.obs; final caseCharging = false.obs; final firmwareVersion = ''.obs; void updateDeviceInfo(DeviceInfo? newDeviceInfo) { - leftEarBattery.value = newDeviceInfo?.leftEarBattery ?? 0; - rightEarBattery.value = newDeviceInfo?.rightEarBattery ?? 0; + Logger.d(_tag, 'lxm--updateDeviceInfo被调用'); + Logger.d(_tag, 'lxm--接收到的DeviceInfo: $newDeviceInfo'); + + if (newDeviceInfo != null) { + Logger.d(_tag, 'lxm--原始数据 - 左耳电量: ${newDeviceInfo.leftEarBattery}'); + Logger.d(_tag, 'lxm--原始数据 - 右耳电量: ${newDeviceInfo.rightEarBattery}'); + Logger.d(_tag, 'lxm--原始数据 - 充电仓电量: ${newDeviceInfo.caseBattery}'); + Logger.d(_tag, 'lxm--原始数据 - 左耳充电: ${newDeviceInfo.leftEarCharging}'); + Logger.d(_tag, 'lxm--原始数据 - 右耳充电: ${newDeviceInfo.rightEarCharging}'); + Logger.d(_tag, 'lxm--原始数据 - 充电仓充电: ${newDeviceInfo.caseCharging}'); + Logger.d(_tag, 'lxm--原始数据 - 固件版本: ${newDeviceInfo.firmwareVersion}'); + } else { + Logger.d(_tag, 'lxm--接收到的DeviceInfo为null'); + } + + // 只有当新数据不为0时才更新电池值,否则保持原值 + if ((newDeviceInfo?.leftEarBattery ?? 0) != 0) { + Logger.d(_tag, 'lxm--更新左耳电量: ${newDeviceInfo!.leftEarBattery}'); + leftEarBattery.value = newDeviceInfo.leftEarBattery; + } + if ((newDeviceInfo?.rightEarBattery ?? 0) != 0) { + Logger.d(_tag, 'lxm--更新右耳电量: ${newDeviceInfo!.rightEarBattery}'); + rightEarBattery.value = newDeviceInfo.rightEarBattery; + } caseBattery.value = newDeviceInfo?.caseBattery ?? 0; leftEarCharging.value = newDeviceInfo?.leftEarCharging ?? false; rightEarCharging.value = newDeviceInfo?.rightEarCharging ?? false; caseCharging.value = newDeviceInfo?.caseCharging ?? false; firmwareVersion.value = newDeviceInfo?.firmwareVersion ?? ''; + + Logger.d(_tag, 'lxm--更新后的值 - 左耳电量: ${leftEarBattery.value}'); + Logger.d(_tag, 'lxm--更新后的值 - 右耳电量: ${rightEarBattery.value}'); + Logger.d(_tag, 'lxm--更新后的值 - 充电仓电量: ${caseBattery.value}'); + Logger.d(_tag, 'lxm--更新后的值 - 左耳充电: ${leftEarCharging.value}'); + Logger.d(_tag, 'lxm--更新后的值 - 右耳充电: ${rightEarCharging.value}'); + Logger.d(_tag, 'lxm--更新后的值 - 充电仓充电: ${caseCharging.value}'); + Logger.d(_tag, 'lxm--更新后的值 - 固件版本: ${firmwareVersion.value}'); } Worker? _deviceInfoWorker; @@ -68,7 +95,7 @@ class HomeController extends GetxController { super.onInit(); _otaCheckService = Get.find(); _initWithCachedInfo(); - // _startBatteryRefreshTimer(); // 启动电池信息定时刷新 + // 移除了电池信息定时刷新的启动 } @override @@ -76,7 +103,7 @@ class HomeController extends GetxController { _deviceInfoWorker?.dispose(); _classicBluetoothWorker?.dispose(); _bleConnectionWorker?.dispose(); - _stopBatteryRefreshTimer(); // 停止定时器 + // 移除了定时器停止逻辑 super.onClose(); } @@ -87,8 +114,13 @@ class HomeController extends GetxController { void _setupStateListeners() { _deviceInfoWorker = ever(_bleManager.deviceInfo, (DeviceInfo? info) { + Logger.d(_tag, 'lxm--_deviceInfoWorker监听器被触发'); + Logger.d(_tag, 'lxm--从BleManager接收到的DeviceInfo: $info'); if (info != null) { + Logger.d(_tag, 'lxm--DeviceInfo不为null,调用updateDeviceInfo'); updateDeviceInfo(info); + } else { + Logger.d(_tag, 'lxm--DeviceInfo为null,跳过更新'); } update(); }); @@ -108,10 +140,7 @@ class HomeController extends GetxController { Future refreshDeviceConnection() async { await _checkConnectionStatus(); - // 如果设备已连接,立即刷新电池信息 - if (_isFullyConnected.value) { - await _refreshBatteryInfo(); - } + // 移除了立即刷新电池信息的逻辑 } void rescanDevices() { @@ -149,24 +178,15 @@ class HomeController extends GetxController { Future.delayed(const Duration(seconds: 1), () async { await _bleManager.fetchDeviceInfo(); }); - - // 连接成功后立即刷新一次电池信息 - Future.delayed(const Duration(milliseconds: 500), () { - _refreshBatteryInfo(); - }); - + + // 移除了连接成功后的电池信息刷新 + // 连接成功后检查OTA升级 Future.delayed(const Duration(seconds: 2), () { _checkOtaUpgrade(); }); } - // 根据连接状态控制定时器 - // if (isNowConnected) { - // _startBatteryRefreshTimer(); // 连接时启动定时器 - // } else { - // _stopBatteryRefreshTimer(); // 断开时停止定时器 - // // 注意:不再重置OTA检查状态,因为现在由全局服务管理 - // } + // 移除了根据连接状态控制定时器的逻辑 } update(); @@ -175,7 +195,7 @@ class HomeController extends GetxController { if (_isFullyConnected.value) { _isFullyConnected.value = false; _isFullyConnected.refresh(); - _stopBatteryRefreshTimer(); // 发生错误时停止定时器 + // 移除了发生错误时停止定时器的逻辑 // 注意:不再重置OTA检查状态,因为现在由全局服务管理 update(); } @@ -299,50 +319,7 @@ class HomeController extends GetxController { : 'unknown'.tr; } - /// 启动电池信息定时刷新 - void _startBatteryRefreshTimer() { - _stopBatteryRefreshTimer(); // 先停止现有定时器 - - _batteryRefreshTimer = Timer.periodic(_batteryRefreshInterval, (timer) { - // 只有在设备完全连接时才刷新电池信息 - if (_isFullyConnected.value) { - _refreshBatteryInfo(); - } - }); - - Logger.d(_tag, '电池信息定时刷新已启动,间隔: ${_batteryRefreshInterval.inSeconds}秒'); - } - - /// 停止电池信息定时刷新 - void _stopBatteryRefreshTimer() { - if (_batteryRefreshTimer != null) { - _batteryRefreshTimer!.cancel(); - _batteryRefreshTimer = null; - Logger.d(_tag, '电池信息定时刷新已停止'); - } - } - - /// 刷新电池信息 - Future _refreshBatteryInfo() async { - try { - if (!_isFullyConnected.value) { - return; - } - - //Logger.d(_tag, '开始刷新电池信息...'); - - // 通过BLE管理器获取最新的电池信息 - final success = await _bleManager.fetchBatteryInfo(); - - if (success) { - //Logger.d(_tag, '电池信息刷新请求发送成功'); - } else { - //Logger.w(_tag, '电池信息刷新请求发送失败'); - } - } catch (e) { - //Logger.e(_tag, '刷新电池信息时发生错误: $e'); - } - } + // 移除了电池信息定时刷新相关方法 /// 检查OTA固件升级 /// 在BLE连接成功后调用,检查是否需要升级 diff --git a/lib/modules/home/views/home_view.dart b/lib/modules/home/views/home_view.dart index 7e994eb38..b66b7989d 100644 --- a/lib/modules/home/views/home_view.dart +++ b/lib/modules/home/views/home_view.dart @@ -450,8 +450,8 @@ class HomeView extends GetView { Widget _buildBatteryInfoGrid(bool isDarkMode) { return Obx(() { // 获取各部分电池电量 - final leftBattery = controller.leftEarBattery; - final rightBattery = controller.rightEarBattery; + final leftBattery = HomeController.leftEarBattery; + final rightBattery = HomeController.rightEarBattery; final caseBattery = controller.caseBattery; // 获取充电状态 final leftEarCharging = controller.leftEarCharging; diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 5cc66c30b..8131d1e01 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -8,6 +8,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'dart:async'; import 'package:permission_handler/permission_handler.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../../../routes/app_routes.dart'; import '../../../core/utils/logger.dart'; import 'dart:io'; @@ -1131,8 +1132,14 @@ class PairingController extends GetxController with WidgetsBindingObserver { /// 打开蓝牙设置 - 简化版本 void _openBluetoothSettings() async { if (Platform.isIOS) { - // iOS平台:直接显示用户指导对话框 - _showBluetoothGuideDialog(); + const url = 'App-Prefs:'; + //拉起iOS系统设置app到前台,使用旧接口生效 + if (await canLaunch(url)) { + await launch(url); + } else { + // 如果无法直接打开,回退到显示指导对话框 + _showBluetoothGuideDialog(); + } } else { // Android平台使用原有方式 AppSettings.openAppSettings(type: AppSettingsType.bluetooth); diff --git a/lib/modules/translation/controllers/translation_controller.dart b/lib/modules/translation/controllers/translation_controller.dart index fb258a9d8..06211dbe8 100644 --- a/lib/modules/translation/controllers/translation_controller.dart +++ b/lib/modules/translation/controllers/translation_controller.dart @@ -4,7 +4,6 @@ import '../../../core/utils/permission_util.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'dart:async'; -import 'dart:convert'; import 'package:get_storage/get_storage.dart'; import 'package:intl/intl.dart'; import 'package:path_provider/path_provider.dart'; @@ -24,44 +23,40 @@ import 'record_timer_controller.dart'; import 'translation_history_controller.dart'; import '../models/translation_models.dart'; -// 切换音频输出设备的枚举 +/// 音频输出设备枚举 enum AudioOutputDevice { defaultDevice, // 默认(如有耳机优先耳机,否则扬声器) headphones, // 强制耳机 speaker, // 强制扬声器 } +/// 翻译控制器 - 负责管理语音识别、翻译和TTS功能 class TranslationController extends GetxController with WidgetsBindingObserver { static const String TAG = 'TranslationController'; - // 服务 - + // ==================== 服务依赖 ==================== final AsrService _asrService = Get.find(); final VolcanoTranslationService _translationService = Get.find(); final TtsService _ttsService = Get.find(); - final AstService _astService = Get.find(); final LanguageManager _languageManager = Get.find(); final GetStorage _storage = GetStorage(); - // 蓝牙服务 final BluetoothManager bluetoothManager = Get.find(); final BleManager bleManager = Get.find(); - //音乐播放管理 final _musiceManager = Get.find(); - // 统计服务 late final TranslationUsageService _usageService; - // ASR统计相关 - 精确时长统计 + // ==================== ASR统计相关 ==================== DateTime? _asrSessionStartTime; // ASR会话开始时间 DateTime? _asrActiveStartTime; // ASR活跃开始时间(用户实际开始语音识别的时间) Duration _asrActiveDuration = Duration.zero; // ASR累计活跃时长 bool _isAsrActive = false; // ASR是否处于活跃状态 - // 音频输入源 - bool _audioSourceType = false; -//是否开启播放 - bool isPlayback = false; + // ==================== 配置相关 ==================== + bool _audioSourceType = false; // 音频输入源类型 + bool isPlayback = false; // 是否开启播放 + bool isContinuePlaying = false; // 是否继续播放 // 存储相关配置 static const String _sourceLanguageKey = 'translation_source_language'; @@ -71,59 +66,60 @@ class TranslationController extends GetxController with WidgetsBindingObserver { final pageSize = 20; // 每页记录数量 bool _scrollListenerSetup = false; // 滚动监听器设置标志 + // ==================== 状态变量 ==================== RxInt activeSpeaker = 0.obs; // 0=无激活, 1=按钮1, 2=按钮2 RxInt lastActiveSpeaker = 0.obs; // 上一次状态 - bool isContinuePlaying = false; // 是否继续播放 - // 状态变量 final isRecognizing = false.obs; final isTranslating = false.obs; final isTtsEnabled = true.obs; final isRecording = false.obs; final lasyIsRecording = false.obs; final hasRecordPermission = false.obs; - // 语言相关 + + // ==================== 语言相关 ==================== final sourceLanguage = '中文(简体)'.obs; final targetLanguage = '英语'.obs; final sourceLanguageCode = 'zh-CN'.obs; final targetLanguageCode = 'en-US'.obs; var detectedLanguageCode = ''; - + final detectedLanguageCode1 = ''.obs; + final latestRecognitionText = ''.obs; + final faceToFaceRecognitionText = ''.obs; + // ==================== 翻译相关 ==================== var currsessionid = ''; final currentModeTitle = 'simultaneousTranslation'.obs; final currentMode = 'simultaneous'.obs; - // 翻译历史和当前项 - - String? fTFTranslationResult = ''; + //String? fTFTranslationResult = ''; String? currentSessionId; final appDocDir = getApplicationDocumentsDirectory(); var appDir; var dir; - // 使用新的管理器 + // ==================== 管理器 ==================== late final RecordTimerController _timerManager; late final TranslationHistoryManager _historyManager; - // 提供访问器 + + // ==================== 访问器 ==================== RxString get recordDurationText => _timerManager.recordDurationText; RxList get translationHistory => _historyManager.translationHistory; ScrollController get scrollController => _historyManager.scrollController; - // 添加历史管理器状态访问器 RxBool get hasMoreHistory => _historyManager.hasMoreHistory; RxBool get isLoadingMore => _historyManager.isLoadingMore; RxBool get isLoadingMoreError => _historyManager.isLoadingMoreError; - // 其他 + Map get supportedLanguages => + _languageManager.getChineseNameToAsrCodeMap(); + + // ==================== 流订阅 ==================== StreamSubscription? _recognitionSubscription; StreamSubscription? _voiceInteractionSubscription; Timer? _translationDebounceTimer; - // 获取支持的语言列表 - Map get supportedLanguages => - _languageManager.getChineseNameToAsrCodeMap(); -// 最新的语音识别文本 - final latestRecognitionText = ''.obs; -// 检测到的语言代码 - final detectedLanguageCode1 = ''.obs; - //int num = 0; + // 底部控制栏高度 + double _bottomBarHeight = 0.0; + + /// 更改翻译模式 + /// [mode] 翻译模式:simultaneous(同声传译)、audioVideo(音视频)、call(通话)、faceToFace(面对面) Future changeTranslationMode(String mode) async { currentMode.value = mode; currentModeTitle.value = _getModeTitle(mode); @@ -131,11 +127,12 @@ class TranslationController extends GetxController with WidgetsBindingObserver { if (mode == 'call') { await _initializeCallModeTranslationService(); - } else if (mode == 'faceToFace') { - await _ttsService.setAudioOutputDevice(1); } } + /// 根据模式获取标题 + /// [mode] 翻译模式 + /// 返回对应的标题字符串 String _getModeTitle(String mode) { switch (mode) { case 'audioVideo': @@ -144,84 +141,75 @@ class TranslationController extends GetxController with WidgetsBindingObserver { return 'callTranslation'; case 'faceToFace': return 'faceToFaceTranslation'; - default: return 'simultaneousTranslation'; } } - // 更新计时器相关方法 + // ==================== 计时器相关方法 ==================== + /// 暂停录音计时器 void pauseRecordTimer() => _timerManager.pauseTimer(); + + /// 恢复录音计时器 void resumeRecordTimer() => _timerManager.resumeTimer(); + + /// 重置录音计时器 void resetRecordTimer() => _timerManager.resetTimer(); + /// 设置激活的说话者(支持按住说话模式) + /// [id] 说话者ID:0=无激活, 1=按钮1, 2=按钮2 Future setActiveSpeaker(int id) async { - activeSpeaker.value = id; - await _asrService.startContinuousRecognition(_audioSourceType); - - if (activeSpeaker.value != 0) { - await _handleActiveSpeakerOn(id); - } else { - await _handleActiveSpeakerOff(); - } - } - - // 拆分出的辅助方法 - Future _handleActiveSpeakerOn(int id) async { - isPlayback = false; - isRecognizing.value = true; - - if (isRecording.value && isRecognizing.value) { - await _handleRecordingStart(); - } - - _startAsrActiveTracking(); - lastActiveSpeaker.value = id; + await _handleFaceToFaceHoldToTalk(id); } - Future _handleRecordingStart() async { - if (lasyIsRecording.value != isRecording.value) { - lasyIsRecording.value = isRecording.value; - await startRecording(); + /// 处理面对面翻译的按住说话逻辑 + /// [id] 说话者ID + Future _handleFaceToFaceHoldToTalk(int id) async { + if (id == 0) { + // 松开按钮,停止当前激活的说话者 + if (activeSpeaker.value != 0) { + lastActiveSpeaker.value = activeSpeaker.value; // 记录上一次激活的说话者 + activeSpeaker.value = id; + await _stopFaceToFaceRecognition(); + } } else { - await _asrService.resumeRecord(); - resumeRecordTimer(); + // 按下按钮,只有在没有其他按钮激活时才能激活 + if (activeSpeaker.value == 0) { + activeSpeaker.value = id; + await _startFaceToFaceRecognition(id); + } } } - Future _handleActiveSpeakerOff() async { - _stopAsrActiveTracking(); - - if (isRecording.value && isRecognizing.value) { - pauseRecordTimer(); - await _asrService.pauseRecord(); + /// 开始面对面翻译的语音识别 + /// [speakerId] 说话者ID + Future _startFaceToFaceRecognition(int speakerId) async { + try { + await _asrService.startContinuousRecognition(_audioSourceType); + await continueRecording(); + Logger.info('面对面翻译:激活说话者 $speakerId'); + } catch (e) { + Logger.error('启动面对面翻译失败: ${e.toString()}'); + activeSpeaker.value = 0; } - - await _handleTranslationPlayback(); } - Future _handleTranslationPlayback() async { - if (fTFTranslationResult != '' && !isPlayback) { - isPlayback = true; - // await _ttsService.setAudioOutputDevice(lastActiveSpeaker.value); - // await Future.delayed(const Duration(milliseconds: 1300)); - await playTranslatedText(fTFTranslationResult!); - fTFTranslationResult = ''; - } else if ((translationHistory.isEmpty || - !translationHistory.last.isIntermediate) && - currentMode.value == 'faceToFace') { - _asrService.stopContinuousRecognition(); + /// 停止面对面翻译的语音识别 + Future _stopFaceToFaceRecognition() async { + try { + await pauseRecording(); //暂停 + await _asrService.stopContinuousRecognition(); + _stopAsrActiveTracking(); + isRecognizing.value = false; + currentSessionId = null; + + Logger.info('面对面翻译:停止语音识别'); + } catch (e) { + Logger.error('停止面对面翻译失败: ${e.toString()}'); } } - // 禁用蓝牙音频 - Future disableBluetoothAudio() async => - await _asrService.disableBluetoothAudio(); - //恢复原始音频状态 - Future restoreOriginalAudioState() async => - await _asrService.restoreOriginalAudioState(); - - // 兼容旧版视图的计算属性 + /// 获取当前翻译项(兼容旧版视图) Rx get currentItem { if (translationHistory.isNotEmpty && translationHistory.last.isIntermediate) { @@ -237,7 +225,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { _timerManager = RecordTimerController(); _historyManager = TranslationHistoryManager(); - //_setupEventListeners(); // 预先检查权限,避免在用户交互时阻塞 _preCheckPermissions(); @@ -282,7 +269,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 初始化统计服务 + /// 初始化统计服务 void _initUsageService() { try { // 确保统计服务已注册 @@ -296,7 +283,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 加载保存的语言设置 + /// 加载保存的语言设置 void _loadSavedLanguages() { final savedSourceLanguage = _storage.read(_sourceLanguageKey); final savedTargetLanguage = _storage.read(_targetLanguageKey); @@ -312,12 +299,14 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 保存当前语言设置 + /// 保存当前语言设置 void _saveLanguageSettings() { _storage.write(_sourceLanguageKey, sourceLanguage.value); _storage.write(_targetLanguageKey, targetLanguage.value); } + /// 请求录音权限 + /// 返回是否授权成功 Future requestRecordPermission() async { try { hasRecordPermission.value = @@ -341,9 +330,9 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 请求存储权限 + /// 请求存储权限 + /// 返回是否授权成功 Future _requestStoragePermission() async { - // final BuildContext context = Get.overlayContext!; try { final bool granted = await PermissionUtil.instance.requestPermission( permissionType: Permission.storage, @@ -365,7 +354,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 暂停其他服务 + /// 暂停其他服务(如音乐播放) Future suspendOtherServices() async { try { var status = await _musiceManager.getStatus(); @@ -373,25 +362,25 @@ class TranslationController extends GetxController with WidgetsBindingObserver { if (isPlaying == true) { isContinuePlaying = true; - await _musiceManager.pause(); // 暂停音乐 + await _musiceManager.pause(); } else { isContinuePlaying = false; } } catch (e) { - Logger.error('初始化服务失败: ${e.toString()}'); + Logger.error('暂停其他服务失败: ${e.toString()}'); } } - // 恢复其他服务 + /// 恢复其他服务(如音乐播放) Future restoreOtherServices() async { try { - if (isContinuePlaying) await _musiceManager.resume(); // 暂停音乐 + if (isContinuePlaying) await _musiceManager.resume(); } catch (e) { - Logger.error('初始化服务失败: ${e.toString()}'); + Logger.error('恢复其他服务失败: ${e.toString()}'); } } - // 初始化服务 + /// 初始化所有服务 Future _initServices() async { try { await _translationService.initialize(); @@ -403,12 +392,10 @@ class TranslationController extends GetxController with WidgetsBindingObserver { ]; Logger.info('初始化ASR服务,支持语言: $asrSupportedLanguages'); - await _asrService.initialize( - supportedLanguages: asrSupportedLanguages, - ); - // 获取识别事件流 - 这启动了异步识别过程 + await _asrService.initialize(supportedLanguages: asrSupportedLanguages); + + // 获取识别事件流 var recognitionStream = await _asrService.recognizeCallback(); - // 监听识别结果 _recognitionSubscription?.cancel(); _recognitionSubscription = recognitionStream.listen(_handleRecognitionEvent); @@ -418,10 +405,11 @@ class TranslationController extends GetxController with WidgetsBindingObserver { Logger.d("Permission", "未授予存储权限,无法提供录音功能"); return; } - appDir = await appDocDir; // 先 await 获取目录 + + appDir = await appDocDir; dir = Directory("${appDir.path}/TranslatAudio"); if (!await dir.exists()) { - await dir.create(recursive: true); // Add recursive creation + await dir.create(recursive: true); } Logger.info('所有服务初始化完成'); } catch (e) { @@ -429,21 +417,17 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 初始化通话模式的语音翻译服务 + /// 初始化通话模式的语音翻译服务 Future _initializeCallModeTranslationService() async { try { Logger.info('开始初始化通话模式语音翻译服务'); - // 为通话模式配置特殊的ASR设置 final List callModeLanguages = [ sourceLanguageCode.value, targetLanguageCode.value ]; - // 重新初始化ASR服务以支持通话音频源 await _astService.initialize(supportedLanguages: callModeLanguages); - Logger.info('通话模式语音翻译服务初始化完成'); - return; } catch (e) { Logger.error('通话模式语音翻译服务初始化失败: ${e.toString()}'); } @@ -459,6 +443,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { restoreOtherServices(); _asrService.dispose(); _astService.dispose(); + // 释放管理器资源 _timerManager.dispose(); _historyManager.dispose(); @@ -470,15 +455,13 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } /// 应用生命周期变化回调 - /// 当应用进入后台、失去焦点或分离(inactive/paused/detached)时, - /// 兜底将 activeSpeaker 重置为 0,等价于“松手”,避免 onPointerUp 未触发导致的卡住问题。 + /// 当应用进入后台、失去焦点或分离时,兜底将 activeSpeaker 重置为 0 @override void didChangeAppLifecycleState(AppLifecycleState state) { if (state == AppLifecycleState.inactive || state == AppLifecycleState.paused || state == AppLifecycleState.detached) { if (activeSpeaker.value != 0) { - // 使用 microtask 避免阻塞当前生命周期回调 Future.microtask(() { setActiveSpeaker(0); }); @@ -486,25 +469,23 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 切换TTS功能 + /// 切换TTS功能开关 void toggleTts() => isTtsEnabled.toggle(); - // 切换录音功能 + /// 切换录音功能开关 Future toggleisRecord() async { isRecording.toggle(); if (isRecording.value && isRecognizing.value) { startRecording(); } else if (!isRecording.value) { stopRecording(); - } else {} + } } + /// 开始录音 Future startRecording() async { - //isRecording.value = true; _timerManager.startTimer(); - // 启动实际录音逻辑 - // ... final formattedTime = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now()); await _asrService.enableRecord( "${dir.path}/${currentModeTitle.value.tr}_$formattedTime.wav"); @@ -512,18 +493,33 @@ class TranslationController extends GetxController with WidgetsBindingObserver { await _astService.enableRecord( "${dir.path}/${currentModeTitle.value.tr}_${formattedTime}_mic.wav"); } - return; } + /// 停止录音 Future stopRecording() async { - // 停止计时器 _timerManager.stopTimer(); _asrService.stopRecord(true); lasyIsRecording.value = false; Logger.info('录音已停止,计时器已重置'); } - // 开始语音识别 + /// 暂停录音 + Future pauseRecording() async { + _timerManager.pauseTimer(); + _asrService.pauseRecord(); + lasyIsRecording.value = false; + Logger.info(' 录音已暂停'); + } + + /// 继续录音 + Future continueRecording() async { + _timerManager.resumeTimer(); + _asrService.resumeRecord(); + lasyIsRecording.value = true; + Logger.info(' 录音已继续'); + } + + /// 开始语音识别 Future startRecognition() async { Logger.info('开始语音识别'); @@ -541,7 +537,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 拆分出的辅助方法 + /// 检查权限 Future _checkPermissions() async { final bool record = await requestRecordPermission(); if (!record) { @@ -551,6 +547,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { return true; } + /// 初始化会话 Future _initializeSession() async { currentSessionId = DateTime.now().millisecondsSinceEpoch.toString(); @@ -564,6 +561,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + /// 配置音频模式 Future _configureAudioMode() async { switch (currentMode.value) { case "audioVideo": @@ -577,6 +575,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + /// 配置音视频模式 Future _configureAudioVideoMode() async { bleManager.openDecoder(); _audioSourceType = true; @@ -584,29 +583,28 @@ class TranslationController extends GetxController with WidgetsBindingObserver { Logger.info('发送ble音乐或者通话远端声音'); } + /// 配置通话模式 Future _configureCallMode() async { bleManager.openA2DPDecoder(); _audioSourceType = true; isTtsEnabled.value = false; - Logger.info('发送ble系统mic和dac(音乐或者通话远端)声音'); } + /// 配置默认模式 Future _configureDefaultMode() async { _audioSourceType = false; isTtsEnabled.value = true; } + /// 启动语音识别 Future _startAsrService() async { - // if (bluetoothManager.currentDeviceRx.value != null) { - // restoreOriginalAudioState(); - // } else { - // disableBluetoothAudio(); - // } - - await _asrService.startContinuousRecognition(_audioSourceType); + if (currentMode.value != 'faceToFace') { + await _asrService.startContinuousRecognition(_audioSourceType); + } } + /// 完成识别启动 Future _finalizeRecognitionStart() async { _startAsrActiveTracking(); isRecognizing.value = true; @@ -616,27 +614,29 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 处理识别事件 + /// 处理语音识别事件 + /// [event] 识别事件 void _handleRecognitionEvent(RecognitionEvent event) { if (event.type == RecognitionEventType.finalResult && event.text.isNotEmpty) { detectedLanguageCode = event.detectedLanguage; - print("处理识别事件:${event.text}"); - handleFinalResult(event.text); + print("处理识别完成:${event.text}"); + if (currentMode.value != 'faceToFace') { + handleFinalResult(event.text); + } else { + faceToFaceRecognitionText.value += event.text; + } + if (currentMode.value == 'faceToFace' && activeSpeaker.value == 0) { + handleFinalResult(faceToFaceRecognitionText.value); + faceToFaceRecognitionText.value = ''; + } } else if (event.type == RecognitionEventType.intermediateResult && event.text.isNotEmpty) { if (event.detectedLanguage.isNotEmpty) { detectedLanguageCode = event.detectedLanguage; } - print("处理识别事件:${event.text}"); + print("处理识别中事件:${event.text}"); handleIntermediateResult(event.text); - } else if (event.type == RecognitionEventType.finalResult1 && - event.text.isNotEmpty) { - if (event.detectedLanguage.isNotEmpty) { - detectedLanguageCode1.value = event.detectedLanguage; - } - latestRecognitionText.value = event.text; - print("处理麦:${event.text}"); } else if (event.type == RecognitionEventType.error) { Get.snackbar('error'.tr, event.error); isRecognizing.value = false; @@ -647,7 +647,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 停止语音识别 + /// 停止语音识别 Future stopRecognition() async { if (!isRecognizing.value) return; @@ -657,40 +657,21 @@ class TranslationController extends GetxController with WidgetsBindingObserver { if (currentMode.value == "call") { await _astService.stopContinuousTranslation(); } - // 停止ASR活跃时长计时 _stopAsrActiveTracking(); - isRecognizing.value = false; - - // 如果当前有中间结果,将其作为最终结果处理 - if (translationHistory.isNotEmpty && - translationHistory.last.isIntermediate && - translationHistory.last.sourceText.isNotEmpty) { - // 标记为最终结果 - translationHistory.last.isIntermediate = false; - translationHistory.refresh(); - - // 如果还没有翻译结果,尝试翻译 - if (translationHistory.last.translatedText.isEmpty) { - await translateText(translationHistory.last.sourceText, - translationHistory.last.timestamp, - isFinal: true); - } - - saveTranslationHistory(); - } - currentSessionId = null; } catch (e) { Logger.error('停止语音识别失败: ${e.toString()}'); } } - // 处理中间识别结果 + /// 处理中间识别结果 + /// [text] 识别的文本 void handleIntermediateResult(String text) { if (text.isEmpty) return; - - if (translationHistory.isEmpty || !translationHistory.last.isIntermediate) { + print( + "handleIntermediateResult:${translationHistory.isEmpty}${translationHistory.isNotEmpty ? translationHistory.last.isIntermediate : 'N/A'}"); + if (translationHistory.isEmpty || (translationHistory.isNotEmpty && !translationHistory.last.isIntermediate)) { currentSessionId ??= DateTime.now().millisecondsSinceEpoch.toString(); final newItem = TranslationItem( @@ -712,7 +693,12 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } else { // 更新当前项 - translationHistory.last.sourceText = text; + if (currentMode.value != 'faceToFace') { + translationHistory.last.sourceText = text; + } else { + translationHistory.last.sourceText = + faceToFaceRecognitionText.value + text; + } translationHistory.refresh(); _historyManager.scrollToBottom(); } @@ -730,27 +716,26 @@ class TranslationController extends GetxController with WidgetsBindingObserver { }); } - // 处理最终识别结果 + /// 处理最终识别结果 + /// [text] 识别的文本 Future handleFinalResult(String text) async { if (text.isEmpty || translationHistory.isEmpty) return; - // ASR识别到最终结果,表示用户完成了一次有效的语音输入 - // 更新当前项 if (translationHistory.last.isIntermediate) { translationHistory.last.sourceText = text; translationHistory.last.isIntermediate = false; translationHistory.refresh(); - // 更新后滚动到底部 _scrollToBottom(); saveTranslationHistory(); +//如果识别中,且是面对面翻译,则停止识别 if (activeSpeaker.value == 0 && currentMode.value == 'faceToFace') { _asrService.stopContinuousRecognition(); } - // 使用项目的时间戳进行翻译 + translateText(text, translationHistory.last.timestamp, isFinal: true); } else { - // 如果最后一项不是中间结果,创建新项 + // 创建新项 final newItem = TranslationItem( sourceText: text, translatedText: '', @@ -763,20 +748,24 @@ class TranslationController extends GetxController with WidgetsBindingObserver { translationHistory.last.sessionId != currentSessionId, isIntermediate: false, ); + if (currentMode.value == 'faceToFace' && activeSpeaker.value == 0) { _asrService.stopContinuousRecognition(); - } //else { + } + translationHistory.add(newItem); translationHistory.refresh(); _scrollToBottom(); saveTranslationHistory(); - // 使用新项目的时间戳进行翻译 translateText(text, newItem.timestamp, isFinal: true); - // } } } - // 翻译文本 + /// 翻译文本 + /// [sourceText] 源文本 + /// [timestamp] 时间戳 + /// [isFinal] 是否为最终结果 + /// 返回翻译结果 Future translateText(String sourceText, DateTime timestamp, {bool isFinal = false}) async { if (sourceText.isEmpty) return null; @@ -802,7 +791,8 @@ class TranslationController extends GetxController with WidgetsBindingObserver { return translationResult; } - // 拆分出的辅助方法 + /// 确定语言代码 + /// 返回源语言和目标语言代码的映射 Map _determineLanguageCodes() { String detectedSourceLanguageCode; String detectedTargetLanguageCode; @@ -829,6 +819,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { }; } + /// 判断是否为面对面说话者1 bool _isFaceToFaceSpeaker1() { return (currentMode.value == 'faceToFace' && activeSpeaker.value == 1) || (currentMode.value == 'faceToFace' && @@ -836,6 +827,7 @@ class TranslationController extends GetxController with WidgetsBindingObserver { lastActiveSpeaker.value == 1); } + /// 判断是否为面对面说话者2 bool _isFaceToFaceSpeaker2() { return (currentMode.value == 'faceToFace' && activeSpeaker.value == 2) || (currentMode.value == 'faceToFace' && @@ -843,6 +835,11 @@ class TranslationController extends GetxController with WidgetsBindingObserver { lastActiveSpeaker.value == 2); } + /// 执行翻译 + /// [sourceText] 源文本 + /// [sourceCode] 源语言代码 + /// [targetCode] 目标语言代码 + /// 返回翻译结果 Future _performTranslation( String sourceText, String sourceCode, String targetCode) async { return await _translationService.translateText( @@ -852,6 +849,12 @@ class TranslationController extends GetxController with WidgetsBindingObserver { ); } + /// 更新翻译历史 + /// [sourceText] 源文本 + /// [translationResult] 翻译结果 + /// [timestamp] 时间戳 + /// [languageCodes] 语言代码映射 + /// [isFinal] 是否为最终结果 Future _updateTranslationHistory( String sourceText, String translationResult, @@ -870,6 +873,12 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + /// 更新现有历史项 + /// [index] 历史项索引 + /// [translationResult] 翻译结果 + /// [languageCodes] 语言代码映射 + /// [sourceText] 源文本 + /// [isFinal] 是否为最终结果 Future _updateExistingHistoryItem( int index, String translationResult, @@ -896,6 +905,10 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + /// 记录翻译统计 + /// [sourceText] 源文本 + /// [translationResult] 翻译结果 + /// [languageCodes] 语言代码映射 Future _recordTranslationStats( String sourceText, String translationResult, @@ -925,28 +938,29 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + /// 处理TTS播放 + /// [translationResult] 翻译结果 Future _handleTtsPlayback(String translationResult) async { - if (isTtsEnabled.value && currentMode.value != 'faceToFace') { + if (isTtsEnabled.value) { await playTranslatedText(translationResult); - } else { - await _handleFaceToFaceTts(translationResult); - } - } - - Future _handleFaceToFaceTts(String translationResult) async { - fTFTranslationResult = (fTFTranslationResult ?? '') + translationResult; - print("translationResult=$translationResult"); - - if (activeSpeaker.value == 0 && !isPlayback) { - isPlayback = true; - // await _ttsService.setAudioOutputDevice(lastActiveSpeaker.value); - // await Future.delayed(const Duration(milliseconds: 1300)); - await playTranslatedText(fTFTranslationResult!); - fTFTranslationResult = ''; } } - // 播放翻译文本 + // /// 处理面对面TTS + // /// [translationResult] 翻译结果 + // Future _handleFaceToFaceTts(String translationResult) async { + // fTFTranslationResult = (fTFTranslationResult ?? '') + translationResult; + // print("translationResult=$translationResult"); + + // if (activeSpeaker.value == 0 && !isPlayback) { + // isPlayback = true; + // await playTranslatedText(fTFTranslationResult!); + // fTFTranslationResult = ''; + // } + // } + + /// 播放翻译文本 + /// [text] 要播放的文本 Future playTranslatedText(String text) async { if (text.isEmpty) return; @@ -964,17 +978,16 @@ class TranslationController extends GetxController with WidgetsBindingObserver { await _ttsService.speakOnce(currsessionid, text); final endTime = DateTime.now(); - // 记录TTS API调用统计 - 优化版(基于文本字符数计费) + // 记录TTS API调用统计 try { final durationSeconds = endTime.difference(startTime).inSeconds; final languageName = _languageManager .getChineseNameByAsrCode(detectedTargetLanguageCode) ?? '未知'; - // TTS的主要计费依据是文本字符数,播放时长仅用于分析 _usageService.recordTtsApiCall( - text: text, // 文本字符数是TTS计费的主要依据 - durationSeconds: durationSeconds, // 播放时长用于用户体验分析 + text: text, + durationSeconds: durationSeconds, language: languageName, ); @@ -988,18 +1001,17 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 停止所有操作 + /// 停止所有操作 Future stopAll() async { try { if (currentMode.value == "audioVideo" || currentMode.value == "call") { bleManager.closeCodec(); - // 发送ble音乐或者通话远端声音 - Logger.info('发送ble音乐或者通话远端声音'); + Logger.info('关闭ble编解码器'); } if (isRecognizing.value) { await stopRecognition(); } - // 确保停止ASR活跃时长跟踪 + _stopAsrActiveTracking(); _translationDebounceTimer?.cancel(); await _ttsService.stop(); @@ -1008,7 +1020,8 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 播放特定翻译项 + /// 播放特定翻译项 + /// [item] 翻译项 Future playTranslationItem(TranslationItem item) async { if (item.translatedText.isEmpty) return; @@ -1023,7 +1036,9 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 播放文本 + /// 播放文本 + /// [text] 要播放的文本 + /// [languageCode] 语言代码(可选) Future playText(String text, {String? languageCode}) async { if (text.isEmpty) return; @@ -1042,24 +1057,21 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 滚动到底部(适配reverse模式) + /// 滚动到底部(适配reverse模式) + /// [animate] 是否使用动画 void _scrollToBottom({bool animate = true}) { if (scrollController.hasClients && (translationHistory.isNotEmpty || currentSessionId != null)) { try { - // 🔑 reverse模式下:滚动到顶部(position = 0)来显示最新消息 - // 正常模式下:滚动到底部(maxScrollExtent)来显示最新消息 const targetPosition = 0.0; // reverse模式下最新消息在顶部 if (animate) { - // 有动画的滚动,用于新消息添加时 scrollController.animateTo( targetPosition, duration: const Duration(milliseconds: 300), curve: Curves.easeOut, ); } else { - // 无动画的跳转,用于初始化时 scrollController.jumpTo(targetPosition); } } catch (e) { @@ -1068,23 +1080,21 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } - // 设置滚动监听器(简化版,不再需要实际监听) + /// 设置滚动监听器(简化版,保留接口兼容性) void setupScrollListener() { // 简化后的空方法,保留接口兼容性 } - // 底部控制栏高度 - double _bottomBarHeight = 0.0; - - // 设置底部控制栏高度 + /// 设置底部控制栏高度 + /// [height] 高度值 void setBottomBarHeight(double height) { _bottomBarHeight = height; } - // 获取底部控制栏高度 + /// 获取底部控制栏高度 double get bottomBarHeight => _bottomBarHeight; - // 切换源语言和目标语言 + /// 切换源语言和目标语言 void swapLanguages() { stopAll(); @@ -1096,14 +1106,12 @@ class TranslationController extends GetxController with WidgetsBindingObserver { sourceLanguageCode.value = targetLanguageCode.value; targetLanguageCode.value = tempCode; - // 保存语言设置 _saveLanguageSettings(); - - // 更新ASR支持的语言并重新初始化 _reinitializeAsrService(); } - // 设置源语言 + /// 设置源语言 + /// [language] 语言名称 void setSourceLanguage(String language) { if (sourceLanguage.value != language) { stopAll(); @@ -1115,15 +1123,13 @@ class TranslationController extends GetxController with WidgetsBindingObserver { sourceLanguageCode.value = asrCode; } - // 保存语言设置 _saveLanguageSettings(); - - // 更新ASR支持的语言并重新初始化 _reinitializeAsrService(); } } - // 设置目标语言 + /// 设置目标语言 + /// [language] 语言名称 void setTargetLanguage(String language) { if (targetLanguage.value != language) { stopAll(); @@ -1135,21 +1141,16 @@ class TranslationController extends GetxController with WidgetsBindingObserver { targetLanguageCode.value = asrCode; } - // 保存语言设置 _saveLanguageSettings(); - - // 更新ASR支持的语言并重新初始化 _reinitializeAsrService(); } } - // 重新初始化ASR服务以支持新的语言 + /// 重新初始化ASR服务以支持新的语言 Future _reinitializeAsrService() async { try { - // 停止当前识别 await stopRecognition(); - // 更新ASR支持的语言 final List asrSupportedLanguages = [ sourceLanguageCode.value, targetLanguageCode.value @@ -1157,21 +1158,14 @@ class TranslationController extends GetxController with WidgetsBindingObserver { Logger.info('重新初始化ASR服务,支持语言: $asrSupportedLanguages'); - // 重新初始化ASR服务 - await _asrService.initialize( - supportedLanguages: asrSupportedLanguages, - ); + await _asrService.initialize(supportedLanguages: asrSupportedLanguages); - // 获取识别事件流 - 这启动了异步识别过程 var recognitionStream = await _asrService.recognizeCallback(); - // 监听识别结果 _recognitionSubscription?.cancel(); _recognitionSubscription = recognitionStream.listen(_handleRecognitionEvent); - //判断是否进入通话 if (currentMode.value == "call") { - // 重新初始化ASR服务以支持通话音频源 _initializeCallModeTranslationService(); } Logger.info('ASR服务重新初始化成功'); @@ -1180,21 +1174,20 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } } + // ==================== 历史记录相关方法 ==================== + /// 加载翻译历史 void loadTranslationHistory() => _historyManager.loadTranslationHistory(); - // 更新历史记录相关方法 + /// 保存翻译历史 void saveTranslationHistory() => _historyManager.saveTranslationHistory(); - // 设置滚动监听器(适配reverse模式) + /// 设置滚动监听器(适配reverse模式) void _setupScrollListener() { - if (_scrollListenerSetup) return; // 防止重复设置 + if (_scrollListenerSetup) return; scrollController.addListener(() { - // 🔑 reverse模式下:检查是否滚动到底部(实际是历史记录的顶部) - // 参考Agent模块的实现 if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 100) { - // 当距离底部100像素时触发加载更多历史记录 if (hasMoreHistory.value && !isLoadingMore.value) { Logger.d(TAG, '触发加载更多翻译历史记录(reverse模式)'); loadMoreHistory(); @@ -1205,18 +1198,33 @@ class TranslationController extends GetxController with WidgetsBindingObserver { _scrollListenerSetup = true; } + /// 清空翻译历史 void clearTranslationHistory() => _historyManager.clearTranslationHistory(); + /// 删除会话历史 + /// [sessionId] 会话ID void deleteSessionHistory(String sessionId) => _historyManager.deleteSessionHistory(sessionId); + /// 删除翻译项 + /// [sessionId] 会话ID + /// [timestamp] 时间戳 void deleteTranslationItem(String sessionId, DateTime timestamp) => _historyManager.deleteTranslationItem(sessionId, timestamp); + + /// 获取所有历史记录 + /// 返回所有翻译项列表 List getAllHistory() => _historyManager.getAllHistory(); + + /// 加载更多历史记录 Future loadMoreHistory() => _historyManager.loadMoreHistory(); + + /// 滚动到底部 + /// [animate] 是否使用动画 void scrollToBottom({bool animate = true}) => _historyManager.scrollToBottom(animate: animate); + // ==================== ASR活跃时长跟踪 ==================== /// 开始ASR活跃时长跟踪 void _startAsrActiveTracking() { if (!_isAsrActive) { @@ -1238,11 +1246,11 @@ class TranslationController extends GetxController with WidgetsBindingObserver { } /// 记录ASR使用统计 - 基于精确时长跟踪 + /// [language] 语言名称 void _recordAsrUsageStats(String language) { try { if (_asrSessionStartTime == null) return; - // 确保停止当前的活跃时长跟踪 _stopAsrActiveTracking(); final now = DateTime.now(); diff --git a/lib/modules/translation/views/translation_view.dart b/lib/modules/translation/views/translation_view.dart index 6796213ba..fed9c1558 100644 --- a/lib/modules/translation/views/translation_view.dart +++ b/lib/modules/translation/views/translation_view.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:ui'; import 'dart:io'; @@ -538,57 +537,6 @@ class TranslationView extends GetView { ); } -// // 按住说话按钮组件 -// Widget _buildHoldToTalkButton({ -// required bool isDarkMode, -// required int speakerId, -// required int activeSpeaker, -// required IconData icon, -// required String label, -// }) { -// bool isActive = activeSpeaker == speakerId; - -// return Listener( -// onPointerDown: (_) { -// if (activeSpeaker == 0) { -// // 没有激活的按钮时才能激活 - -// if (speakerId == 1) { -// //耳机收音 -// controller.restoreOriginalAudioState(); - -// //controller.setActiveSpeaker(speakerId); -// } else { -// controller.disableBluetoothAudio(); -// } -// controller.setActiveSpeaker(speakerId); -// //controller.startRecognition(); -// } -// }, -// onPointerUp: (_) { -// if (isActive) { -// //controller.stopRecognition(); -// controller.setActiveSpeaker(0); -// } -// }, -// child: Container( -// width: 60.w, -// height: 60.w, -// decoration: BoxDecoration( -// color: isActive -// ? (isDarkMode ? Colors.green[700] : Colors.green) // 激活状态颜色 -// : (isDarkMode ? AppColors.primary : Colors.blue), -// shape: BoxShape.circle, -// ), -// child: Icon( -// Icons.mic, // 麦克风图标 -// color: isActive ? Colors.white : Colors.white.withOpacity(0.7), -// size: 30.sp, -// ), -// ), -// ); -// } - // 按住说话按钮组件 Widget _buildHoldToTalkButton({ required bool isDarkMode, @@ -599,22 +547,25 @@ class TranslationView extends GetView { }) { bool isActive = activeSpeaker == speakerId; bool isDisabled = activeSpeaker != 0 && activeSpeaker != speakerId; - Timer? _holdTimer; // 增加延迟触发的计时器 + return Listener( onPointerDown: (_) async { - // 同步检查权限状态,不使用 await + // 检查权限 if (!controller.hasRecordPermission.value) { Get.snackbar('权限提示', '需要麦克风权限才能使用录音功能'); return; } - controller.setActiveSpeaker(speakerId); - }, - onPointerUp: (_) { - controller.setActiveSpeaker(0); + // 只有在没有其他按钮激活时才能激活当前按钮 + if (activeSpeaker == 0) { + await controller.setActiveSpeaker(speakerId); + } }, - onPointerCancel: (_) { - controller.setActiveSpeaker(0); + onPointerUp: (_) async { + // 松开按钮时,如果当前按钮是激活状态,则停止 + if (isActive) { + await controller.setActiveSpeaker(0); + } }, child: AnimatedContainer( duration: const Duration(milliseconds: 200), @@ -643,7 +594,7 @@ class TranslationView extends GetView { Stack( alignment: Alignment.center, children: [ - // 设备类型图标(叠加在麦克风上) + // 设备类型图标 Icon( icon, color: isActive diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt index 3c4cb9144..73a2e51c9 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleAgent.kt @@ -135,7 +135,7 @@ Log.d(TAG, "手动启动语音识别: ") AgentService.pushAudioData(data) // 可选:处理音频数据 } - override fun onAudioDataReceived1(data: ByteArray) { + override fun onAudioDataReceivedCall(data: ByteArray) { } /** diff --git a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift index e6701e459..0b15a3942 100644 --- a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift +++ b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift @@ -1510,7 +1510,7 @@ extension AgentServiceImpl: BleService.Callback { pushAudioData(data) } - func onAudioDataReceived1(data: Data) { + func onAudioDataReceivedCall(data: Data) { } diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt index e568d9ac3..2341bfb48 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureSpeechPlugin.kt @@ -1003,9 +1003,9 @@ class AzureSpeechPlugin : BleService.Callback, FlutterPlugin { // 可选:处理音频数据 } - override fun onAudioDataReceived1(data: ByteArray) { + override fun onAudioDataReceivedCall(data: ByteArray) { - // FileLogger.d(tag, "onAudioDataReceived1: ${data.size}") + // FileLogger.d(tag, "onAudioDataReceivedCall: ${data.size}") azureAstHelper.pushAudioData(data) // 可选:处理音频数据 diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift index 2f5f25bd5..d7d1a04d4 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureSpeechPlugin.swift @@ -947,7 +947,7 @@ extension AzureSpeechPlugin: BleService.Callback { /// 接收到音频数据回调1 /// - Parameter data: 音频数据 - public func onAudioDataReceived1(data: Data) { + public func onAudioDataReceivedCall(data: Data) { // 安全解包版本 guard let audioStream = azureAstHelper.audioProcessor else { os_log("音频流未初始化", type: .error) diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/tools/MicrophoneCapture.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/tools/MicrophoneCapture.swift index 06ecbeaab..a175aa829 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/tools/MicrophoneCapture.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/tools/MicrophoneCapture.swift @@ -318,7 +318,7 @@ public class MicrophoneCapture: NSObject { // 转换成功且无错误 if status == .haveData, error == nil { let data = strongSelf.audioBufferToData(convertedBuffer) - print("转换后数据长度: \(data.count)") + //print("转换后数据长度: \(data.count)") strongSelf.audioDataHandler?(data) } } diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index dc8389a0e..4f4660c80 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -55,7 +55,7 @@ object BleService { // 数据相关回调 fun onAudioDataReceived(data: ByteArray) // 数据相关回调 - fun onAudioDataReceived1(data: ByteArray) + fun onAudioDataReceivedCall(data: ByteArray) // 唤醒信号相关回调 fun onWakeupSignalReceived() @@ -1995,7 +1995,7 @@ startBytesStatistics() private fun notifyAudioDataReceived1(data: ByteArray) { for (callback in callbacks) { try { - callback.onAudioDataReceived1(data) + callback.onAudioDataReceivedCall(data) } catch (e: Exception) { Log.e(TAG, "分发音频数据回调异常", e) } diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt index 12a29477d..80fcb7780 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt @@ -361,7 +361,7 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, // sendEvent(dataEventSink, mapOf("type" to "audioData", "data" to data), "发送音频数据异常") } - override fun onAudioDataReceived1(data: ByteArray) { + override fun onAudioDataReceivedCall(data: ByteArray) { // sendEvent(dataEventSink, mapOf("type" to "audioData", "data" to data), "发送音频数据异常") } diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift index f7972197a..942728de5 100644 --- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift +++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift @@ -28,7 +28,7 @@ public class BleService: NSObject { // 数据相关回调 func onAudioDataReceived(data: Data) - func onAudioDataReceived1(data: Data) + func onAudioDataReceivedCall(data: Data) // 唤醒信号回调 func onWakeupSignalReceived() @@ -532,7 +532,7 @@ private var cmdReplyType: UInt8 = 0 /// 通知所有回调接收到音频数据 private func notifyAudioDataReceived1(data: Data) { for callback in callbacks { - callback.onAudioDataReceived1(data: data) + callback.onAudioDataReceivedCall(data: data) } } @@ -1189,7 +1189,7 @@ extension BleService: SwiftOpusAudioProcessor.AudioDataCallback { } /// 接收到解码后的PCM音频数据 - func onAudioDataReceived1(data: Data) { + func onAudioDataReceivedCall(data: Data) { notifyAudioDataReceived1(data: data) } diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift index 4a664d583..da70071fe 100644 --- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift +++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift @@ -236,7 +236,7 @@ extension SwiftBleServicePlugin: BleService.Callback { } } - public func onAudioDataReceived1(data: Data) { + public func onAudioDataReceivedCall(data: Data) { } diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift index 5f4c4c69d..5030de4ee 100644 --- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift +++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftOpusAudioProcessor.swift @@ -9,7 +9,7 @@ class SwiftOpusAudioProcessor: NSObject { /// 音频数据回调协议 protocol AudioDataCallback: AnyObject { func onAudioDataReceived(data: Data) - func onAudioDataReceived1(data: Data) + func onAudioDataReceivedCall(data: Data) func onEncodedDataReceived(data: Data) // 编码数据回调 } @@ -336,7 +336,7 @@ class SwiftOpusAudioProcessor: NSObject { // 回调分离后的音频数据 DispatchQueue.main.async { [weak self] in self?.callback?.onAudioDataReceived(data: rightBuffer) - self?.callback?.onAudioDataReceived1(data: leftBuffer) + self?.callback?.onAudioDataReceivedCall(data: leftBuffer) } } diff --git a/local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt b/local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt index 1830237b1..083ce0f70 100644 --- a/local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt +++ b/local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt @@ -383,7 +383,7 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler { // 可选:处理音频数据 } - override fun onAudioDataReceived1(data: ByteArray) { + override fun onAudioDataReceivedCall(data: ByteArray) { } /** diff --git a/pubspec.yaml b/pubspec.yaml index 5906aa5ea..e751796d5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: voitrans description: "Voitrans - AI Voice Assistant." publish_to: "none" -version: 1.0.10+25 +version: 1.0.12+29 environment: sdk: ">=3.3.0 <4.0.0"