fdp 1 year ago
parent
commit
84b0de987e
  1. 19
      lib/data/services/ble_manager.dart
  2. 42
      lib/data/services/speech_impl/volcano_tts_service.dart
  3. 4
      lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart
  4. 210
      lib/modules/settings/views/settings_view.dart
  5. 23
      local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt

19
lib/data/services/ble_manager.dart

@ -184,6 +184,19 @@ class BleManager extends GetxService {
state == BleConnectionState.error) { state == BleConnectionState.error) {
Logger.info('BLE设备已断开或发生错误'); Logger.info('BLE设备已断开或发生错误');
_isConnected.value = false; _isConnected.value = false;
// 更新设备信息Add commentMore actions
_updateDeviceInfoIfNeeded(
batteryLevel: 0,
leftEarBattery: 0,
rightEarBattery: 0,
caseBattery: 0,
leftEarCharging: false,
rightEarCharging: false,
caseCharging: false,
firmwareVersion: '',
firmwareProductId: '',
firmwareProductColor: '',
);
// 断开连接时不清除设备信息,保留最后的电量信息 // 断开连接时不清除设备信息,保留最后的电量信息
// 只有在需要完全清除设备时才重置信息 // 只有在需要完全清除设备时才重置信息
} }
@ -467,7 +480,8 @@ class BleManager extends GetxService {
_bleService.getProductId(), _bleService.getProductId(),
]); ]);
Logger.info('设备信息获取结果: 电池=${results[0]}, 版本=${results[1]}, 产品ID=${results[2]}'); Logger.info(
'设备信息获取结果: 电池=${results[0]}, 版本=${results[1]}, 产品ID=${results[2]}');
if (!results[0]) { if (!results[0]) {
Logger.warning('电池信息获取指令发送失败'); Logger.warning('电池信息获取指令发送失败');
@ -788,7 +802,8 @@ class BleManager extends GetxService {
// 从蓝牙管理器获取设备名称 // 从蓝牙管理器获取设备名称
final bluetoothManager = Get.find<BluetoothManager>(); final bluetoothManager = Get.find<BluetoothManager>();
_currentDeviceName = bluetoothManager.currentDevice?.name ?? ""; _currentDeviceName = bluetoothManager.currentDevice?.name ?? "";
Logger.info('保存设备信息: address=$_currentDeviceAddress, name=$_currentDeviceName'); Logger.info(
'保存设备信息: address=$_currentDeviceAddress, name=$_currentDeviceName');
} }
return await _bleService.registerBackgroundScan(macAddress: macAddress); return await _bleService.registerBackgroundScan(macAddress: macAddress);

42
lib/data/services/speech_impl/volcano_tts_service.dart

@ -11,10 +11,12 @@ class VolcanoTtsService extends GetxService implements TtsService {
static const MethodChannel _channel = MethodChannel('volcano_speech/tts'); static const MethodChannel _channel = MethodChannel('volcano_speech/tts');
/// 事件通道 /// 事件通道
static const EventChannel _eventChannel = EventChannel('volcano_speech/tts_events'); static const EventChannel _eventChannel =
EventChannel('volcano_speech/tts_events');
/// 音频数据通道 /// 音频数据通道
static const EventChannel _audioDataChannel = EventChannel('volcano_speech/tts_audio_data'); static const EventChannel _audioDataChannel =
EventChannel('volcano_speech/tts_audio_data');
/// 事件流控制器 /// 事件流控制器
final StreamController<TtsEvent> _eventStreamController = final StreamController<TtsEvent> _eventStreamController =
@ -130,15 +132,17 @@ class VolcanoTtsService extends GetxService implements TtsService {
final appToken = dotenv.env['VOLCANO_SPEECH_APP_TOKEN'] ?? ''; final appToken = dotenv.env['VOLCANO_SPEECH_APP_TOKEN'] ?? '';
if (appId.isEmpty || appToken.isEmpty) { if (appId.isEmpty || appToken.isEmpty) {
debugPrint('火山语音初始化失败:缺少VOLCANO_SPEECH_APP_ID或VOLCANO_SPEECH_APP_TOKEN环境变量'); debugPrint(
'火山语音初始化失败:缺少VOLCANO_SPEECH_APP_ID或VOLCANO_SPEECH_APP_TOKEN环境变量');
return false; return false;
} }
// 初始化火山语音TTS // 初始化火山语音TTS
final result = await _channel.invokeMethod<bool>('initialize', { final result = await _channel.invokeMethod<bool>('initialize', {
'appId': appId, 'appId': appId,
'appToken': appToken, 'appToken': appToken,
}) ?? false; }) ??
false;
if (!result) { if (!result) {
debugPrint('火山语音TTS初始化失败'); debugPrint('火山语音TTS初始化失败');
@ -167,8 +171,9 @@ class VolcanoTtsService extends GetxService implements TtsService {
try { try {
final result = await _channel.invokeMethod<bool>('setVoice', { final result = await _channel.invokeMethod<bool>('setVoice', {
'voice': voiceName, 'voice': voiceName,
}) ?? false; }) ??
false;
if (result) { if (result) {
_currentVoice = voiceName; _currentVoice = voiceName;
@ -186,8 +191,9 @@ class VolcanoTtsService extends GetxService implements TtsService {
try { try {
final result = await _channel.invokeMethod<bool>('enableAudioCallback', { final result = await _channel.invokeMethod<bool>('enableAudioCallback', {
'enable': enable, 'enable': enable,
}) ?? false; }) ??
false;
if (result) { if (result) {
_isAudioCallbackEnabled = enable; _isAudioCallbackEnabled = enable;
@ -206,8 +212,9 @@ class VolcanoTtsService extends GetxService implements TtsService {
try { try {
// 单次播放 // 单次播放
final result = await _channel.invokeMethod<bool>('speakOnce', { final result = await _channel.invokeMethod<bool>('speakOnce', {
'text': text, 'text': text,
}) ?? false; }) ??
false;
return result; return result;
} catch (e) { } catch (e) {
@ -224,8 +231,9 @@ class VolcanoTtsService extends GetxService implements TtsService {
try { try {
// 流式添加文本 // 流式添加文本
final result = await _channel.invokeMethod<bool>('speakStream', { final result = await _channel.invokeMethod<bool>('speakStream', {
'text': text, 'text': text,
}) ?? false; }) ??
false;
return result; return result;
} catch (e) { } catch (e) {
@ -282,4 +290,10 @@ class VolcanoTtsService extends GetxService implements TtsService {
_isInitialized = false; _isInitialized = false;
} }
} }
@override
Future<bool> setAudioOutputDevice(int type) {
// TODO: implement setAudioOutputDevice
throw UnimplementedError();
}
} }

4
lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart

@ -327,7 +327,7 @@ class OtaUpgradeController extends GetxController {
} }
if (existingSameFile) { if (existingSameFile) {
Get.snackbar('文件已存在', '跳过下载,直接更新'); //Get.snackbar('文件已存在', '跳过下载,直接更新');
startUpgrading(savePath); startUpgrading(savePath);
return; return;
@ -367,7 +367,7 @@ class OtaUpgradeController extends GetxController {
); );
File file = File(savePath); File file = File(savePath);
if (await file.exists()) { if (await file.exists()) {
Get.snackbar('下载完成', '文件已保存至: $savePath'); // Get.snackbar('下载完成', '文件已保存至: $savePath');
} else { } else {
Get.snackbar('错误', '文件未找到,请检查写入权限'); Get.snackbar('错误', '文件未找到,请检查写入权限');
} }

210
lib/modules/settings/views/settings_view.dart

@ -525,114 +525,114 @@ class SettingsView extends GetView<SettingsController> {
? Colors.white.withOpacity(0.1) ? Colors.white.withOpacity(0.1)
: Colors.grey[200]), : Colors.grey[200]),
// 杰理测试 // // 杰理测试
_buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(
title: '杰理蓝牙测试', // title: '杰理蓝牙测试',
subtitle: '测试杰理蓝牙设备扫描、连接和功能', // subtitle: '测试杰理蓝牙设备扫描、连接和功能',
icon: Icons.bluetooth, // icon: Icons.bluetooth,
iconBgColor: isDarkMode // iconBgColor: isDarkMode
? Colors.blue[900]!.withOpacity(0.3) // ? Colors.blue[900]!.withOpacity(0.3)
: Colors.blue[100]!, // : Colors.blue[100]!,
iconColor: // iconColor:
isDarkMode ? Colors.blue[300]! : Colors.blue[600]!, // isDarkMode ? Colors.blue[300]! : Colors.blue[600]!,
titleColor: isDarkMode ? Colors.white : null, // titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, // subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { // onTap: () {
Get.toNamed(Routes.jieliTest); // Get.toNamed(Routes.jieliTest);
}, // },
isDarkMode: isDarkMode, // isDarkMode: isDarkMode,
), // ),
Divider( // Divider(
height: 1, // height: 1,
color: isDarkMode // color: isDarkMode
? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
: Colors.grey[200]), // : Colors.grey[200]),
// 面对面翻译测试 // // 面对面翻译测试
_buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(
title: '面对面翻译测试', // title: '面对面翻译测试',
subtitle: '测试面对面翻译', // subtitle: '测试面对面翻译',
icon: Icons.bluetooth_searching, // icon: Icons.bluetooth_searching,
iconBgColor: isDarkMode // iconBgColor: isDarkMode
? Colors.green[900]!.withOpacity(0.3) // ? Colors.green[900]!.withOpacity(0.3)
: Colors.green[100]!, // : Colors.green[100]!,
iconColor: // iconColor:
isDarkMode ? Colors.green[300]! : Colors.green[600]!, // isDarkMode ? Colors.green[300]! : Colors.green[600]!,
titleColor: isDarkMode ? Colors.white : null, // titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, // subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { // onTap: () {
Get.toNamed(Routes.ftftranslation); // Get.toNamed(Routes.ftftranslation);
}, // },
isDarkMode: isDarkMode, // isDarkMode: isDarkMode,
), // ),
Divider( // Divider(
height: 1, // height: 1,
color: isDarkMode // color: isDarkMode
? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
: Colors.grey[200]), // : Colors.grey[200]),
// BLE测试 // // BLE测试
_buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(
title: 'opus解码测试', // title: 'opus解码测试',
subtitle: '测试opus解码', // subtitle: '测试opus解码',
icon: Icons.bluetooth_searching, // icon: Icons.bluetooth_searching,
iconBgColor: isDarkMode // iconBgColor: isDarkMode
? Colors.green[900]!.withOpacity(0.3) // ? Colors.green[900]!.withOpacity(0.3)
: Colors.green[100]!, // : Colors.green[100]!,
iconColor: // iconColor:
isDarkMode ? Colors.green[300]! : Colors.green[600]!, // isDarkMode ? Colors.green[300]! : Colors.green[600]!,
titleColor: isDarkMode ? Colors.white : null, // titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, // subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { // onTap: () {
Get.toNamed(Routes.opusTest); // Get.toNamed(Routes.opusTest);
}, // },
isDarkMode: isDarkMode, // isDarkMode: isDarkMode,
), // ),
Divider( // Divider(
height: 1, // height: 1,
color: isDarkMode // color: isDarkMode
? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
: Colors.grey[200]), // : Colors.grey[200]),
// BLE测试 // BLE测试
_buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(
title: 'BLE蓝牙测试', // title: 'BLE蓝牙测试',
subtitle: '测试BLE蓝牙设备扫描、连接和功能', // subtitle: '测试BLE蓝牙设备扫描、连接和功能',
icon: Icons.bluetooth_searching, // icon: Icons.bluetooth_searching,
iconBgColor: isDarkMode // iconBgColor: isDarkMode
? Colors.green[900]!.withOpacity(0.3) // ? Colors.green[900]!.withOpacity(0.3)
: Colors.green[100]!, // : Colors.green[100]!,
iconColor: // iconColor:
isDarkMode ? Colors.green[300]! : Colors.green[600]!, // isDarkMode ? Colors.green[300]! : Colors.green[600]!,
titleColor: isDarkMode ? Colors.white : null, // titleColor: isDarkMode ? Colors.white : null,
subtitleColor: isDarkMode ? Colors.white70 : null, // subtitleColor: isDarkMode ? Colors.white70 : null,
onTap: () { // onTap: () {
Get.toNamed(Routes.bleTest); // Get.toNamed(Routes.bleTest);
}, // },
isDarkMode: isDarkMode, // isDarkMode: isDarkMode,
), // ),
Divider( // Divider(
height: 1, // height: 1,
color: isDarkMode // color: isDarkMode
? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
: Colors.grey[200]), // : Colors.grey[200]),
// 火山语音测试 // // 火山语音测试
_buildSimpleNavigationSetting( // _buildSimpleNavigationSetting(
title: '语音测试', // title: '语音测试',
subtitle: '测试语音识别和合成功能,支持多种服务实现', // subtitle: '测试语音识别和合成功能,支持多种服务实现',
icon: Icons.record_voice_over, // icon: Icons.record_voice_over,
iconBgColor: isDarkMode // iconBgColor: isDarkMode
? Colors.orange[900]!.withOpacity(0.3) // ? Colors.orange[900]!.withOpacity(0.3)
: Colors.orange[100]!, // : Colors.orange[100]!,
iconColor: // iconColor:
isDarkMode ? Colors.orange[300]! : Colors.orange[600]!, // isDarkMode ? Colors.orange[300]! : Colors.orange[600]!,
onTap: () => Get.toNamed(Routes.speechTest), // onTap: () => Get.toNamed(Routes.speechTest),
isDarkMode: isDarkMode, // isDarkMode: isDarkMode,
), // ),
Divider( // Divider(
height: 1, // height: 1,
color: isDarkMode // color: isDarkMode
? Colors.white.withOpacity(0.1) // ? Colors.white.withOpacity(0.1)
: Colors.grey[200]), // : Colors.grey[200]),
// 测试ble耳机固件版本升级 // 测试ble耳机固件版本升级
_buildSimpleNavigationSetting( _buildSimpleNavigationSetting(
title: 'ota升级', title: 'ota升级',

23
local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt

@ -146,9 +146,10 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
private lateinit var channel: MethodChannel private lateinit var channel: MethodChannel
private lateinit var context: Context private lateinit var context: Context
private lateinit var otaDevice: BluetoothDevice private lateinit var otaDevice: BluetoothDevice
private lateinit var bluetoothHelper: BluetoothHelper private var bluetoothHelper: BluetoothHelper? = null
private var otaManager: OTAManager? = null
private lateinit var otaManager: OTAManager
private lateinit var filePath: String//升级文件路径 private lateinit var filePath: String//升级文件路径
private var isDisconnect = false//是否主动断开 private var isDisconnect = false//是否主动断开
private var streamSink: EventChannel.EventSink? = null private var streamSink: EventChannel.EventSink? = null
@ -216,8 +217,8 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
private val bluetoothCallback = object : BtEventCallback() { private val bluetoothCallback = object : BtEventCallback() {
override fun onConnection(device: BluetoothDevice?, status: Int) { override fun onConnection(device: BluetoothDevice?, status: Int) {
if ((status == StateCode.CONNECTION_FAILED || status == StateCode.CONNECTION_DISCONNECT) && bluetoothHelper.getConnectedDevice() != null) { if ((status == StateCode.CONNECTION_FAILED || status == StateCode.CONNECTION_DISCONNECT) && bluetoothHelper?.getConnectedDevice() != null) {
bluetoothHelper.disconnectDevice(bluetoothHelper.getConnectedDevice()) bluetoothHelper?.disconnectDevice(bluetoothHelper?.getConnectedDevice())
} }
otaDevice = device!! otaDevice = device!!
@ -238,10 +239,10 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
) )
) )
Log.d("TAG", "startUpgrade,filePath=${filePath}") Log.d("TAG", "startUpgrade,filePath=${filePath}")
otaManager.bluetoothOption.firmwareFilePath = filePath otaManager?.bluetoothOption?.firmwareFilePath = filePath
otaManager.startOTA( otaManager?.startOTA(
CustomUpdateCallback( CustomUpdateCallback(
otaManager.bluetoothHelper.getConnectedDevice(), streamSink otaManager?.bluetoothHelper?.getConnectedDevice(), streamSink
) )
) )
} }
@ -280,7 +281,7 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
otaManager = OTAManager(context) otaManager = OTAManager(context)
bluetoothHelper = BluetoothHelper(context) bluetoothHelper = BluetoothHelper(context)
// 如果需要额外的初始化逻辑,请在这里添加 // 如果需要额外的初始化逻辑,请在这里添加
otaManager.registerBluetoothCallback(bluetoothCallback) otaManager!!.registerBluetoothCallback(bluetoothCallback)
// 初始化BleService // 初始化BleService
// 2. 初始化BleService并注册回调 // 2. 初始化BleService并注册回调
if (BleService.initialize(context)) { if (BleService.initialize(context)) {
@ -335,10 +336,12 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
} else if (call.method == "onOtaClose") { } else if (call.method == "onOtaClose") {
BleService.isEnterOta = false BleService.isEnterOta = false
isDisconnect = false isDisconnect = false
if(otaManager!= null) {
otaManager?.bluetoothHelper?.stopScan() otaManager?.bluetoothHelper?.stopScan()
otaManager?.bluetoothHelper?.disconnectDevice(otaDevice) otaManager?.bluetoothHelper?.disconnectDevice(otaDevice)
}
result.success("") result.success("")
} else { } else {
result.notImplemented() result.notImplemented()
@ -370,7 +373,7 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
if (state == BleConst.STATE_DISCONNECTED && isDisconnect) { if (state == BleConst.STATE_DISCONNECTED && isDisconnect) {
Log.d("TAG", "Ble设备已断开,onConnectionStateChanged") Log.d("TAG", "Ble设备已断开,onConnectionStateChanged")
Handler(Looper.getMainLooper()).postDelayed({ Handler(Looper.getMainLooper()).postDelayed({
otaManager.bluetoothHelper.startScan(otaDevice) otaManager?.bluetoothHelper?.startScan(otaDevice)
}, 2000) // 2000 毫秒 = 2 秒 }, 2000) // 2000 毫秒 = 2 秒
} }
} }

Loading…
Cancel
Save