import 'dart:async'; import 'package:camera/camera.dart'; import 'package:get/get.dart'; import 'package:tencent_trtc_cloud/trtc_cloud.dart'; import 'package:tencent_trtc_cloud/tx_device_manager.dart'; import 'package:flutter_sound_platform_interface/flutter_sound_recorder_platform_interface.dart'; import 'package:flutter_sound/flutter_sound.dart'; import 'package:audio_session/audio_session.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'index.dart'; class HardwareDetectionController extends GetxController { HardwareDetectionController(); final state = HardwareDetectionState(); /// 相机控制器需要的参数 late List _cameras; late CameraController cameraController; /// 扬声器控制器需要的参数 final FlutterSoundPlayer flutterSound = FlutterSoundPlayer(); /// 麦克风控制器需要的参数 Codec _codec = Codec.aacMP4; String _mPath = 'tau_file.mp4'; final FlutterSoundRecorder flutterRecorder = FlutterSoundRecorder(); /// 初始化设备列表 Future _intialize() async { await _initCameras(); await _initMicrophones(); await _initSpeakers(); print("总设备数:${state.deviceList.length}"); state.cameraList = state.deviceList .where((element) => element.type == HardwareDeviceType.camera) .toList(); state.microphoneList = state.deviceList .where((element) => element.type == HardwareDeviceType.microphone) .toList(); state.speakerList = state.deviceList .where((element) => element.type == HardwareDeviceType.speaker) .toList(); if (state.cameraList.isNotEmpty) state.currentCamera = state.cameraList[0]; if (state.microphoneList.isNotEmpty) state.currentMicrophone = state.microphoneList[0]; if (state.speakerList.isNotEmpty) state.currentSpeaker = state.speakerList[0]; } /// 初始化摄像头列表 Future _initCameras() async { List _cameraList = await _trtcGetCameras(); _cameras = await availableCameras(); print("初始摄像头数量:${_cameras.length}"); for (var i = 0; i < _cameras.length; i++) { for (var j = 0; j < _cameraList.length; j++) { if (_cameras[i].name == _cameraList[j].name) { state.deviceList.add(_cameraList[j]); break; } } } } /// 初始化麦克风列表 Future _initMicrophones() async { List _microphoneList = await _trtcGetMicrophones(); state.deviceList.addAll(_microphoneList); await _initTheRecorder(); } /// 初始化扬声器列表 Future _initSpeakers() async { List _speakerList = await _trtcGetSpeakers(); state.deviceList.addAll(_speakerList); await _initThePlayer(); } // 刷新设备列表 Future refreshAllDevices() async { await refreshCameraList(); await refreshMicrophoneList(); await refreshSpeakerList(); } /// 设置当前选中的摄像头可用性 void setCameraAvailable(bool available) { state.cameraAvailable = available; stopDetectingCamera(); } /// 设置当前选中的麦克风可用性 void setMicrophoneAvailable(bool available) { state.microphoneAvailable = available; stopDetectingMicrophone(); } /// 设置当前选中的扬声器可用性 void setSpeakerAvailable(bool available) { state.speakerAvailable = available; stopDetectingSpeaker(); } /// 开始检测摄像头 void startDetectingCamera() { state.cameraAvailable = null; state.detectingCamera = true; _openSelectedCamera(); } /// 结束检测摄像头 void stopDetectingCamera() { state.detectingCamera = false; _stopCamera(); } /// 开始检测麦克风 void startDetectingMicrophone() { state.microphoneAvailable = null; state.detectingMicrophone = true; _startRecordMicrophone(); } /// 结束检测麦克风 void stopDetectingMicrophone() { state.detectingMicrophone = false; _stopRecordMicrophone(); } /// 开始检测扬声器 void startDetectingSpeaker() { state.speakerAvailable = null; state.detectingSpeaker = true; _startPlaySound(); } /// 结束检测扬声器 void stopDetectingSpeaker() { state.detectingSpeaker = false; _stopPlaySound(); } /// 开始检测所有设备 Future startDetectingAll() async { await refreshAllDevices(); if (state.cameraList.isNotEmpty) startDetectingCamera(); if (state.microphoneList.isNotEmpty) startDetectingMicrophone(); if (state.speakerList.isNotEmpty) startDetectingSpeaker(); } /// 选择摄像头 void selectCameraById(String deviceId) { if (state.currentCamera != null && deviceId == state.currentCamera!.id) return; state.cameraList.forEach((element) { if (element.id == deviceId) { state.currentCamera = element; state.cameraAvailable = null; print("选择摄像头: ${element.name} id: ${element.id}"); } }); if (state.currentCamera == null) return; if (state.detectingCamera) { _stopCamera(); _openSelectedCamera(); } } /// 选择麦克风 Future selectMicrophoneById(String deviceId) async { state.microphoneList.forEach((element) { if (element.id == deviceId) { state.currentMicrophone = element; state.microphoneAvailable = null; print("选择麦克风: ${element.name} id: ${element.id}"); } }); if (state.currentMicrophone == null) return; if (state.detectingMicrophone) { await _stopRecordMicrophone(); _startRecordMicrophone(); } } /// 选择扬声器 void selectSpeakerById(String deviceId) { state.speakerList.forEach((element) { if (element.id == deviceId) { state.currentSpeaker = element; state.speakerAvailable = null; print("选择扬声器: ${element.name} id: ${element.id}"); } }); if (state.currentSpeaker == null) return; } /// 刷新扬声器列表 Future refreshSpeakerList() async { if (state.detectingSpeaker) stopDetectingSpeaker(); state.speakerList = []; state.speakerAvailable = null; await Future.delayed(Duration(milliseconds: 100)); state.speakerList = await _trtcGetSpeakers(); for (int i = 0; i < state.deviceList.length; i++) { if (state.deviceList[i].type == HardwareDeviceType.speaker) { state.deviceList.removeAt(i); i--; } } state.deviceList.addAll(state.speakerList); } /// 刷新摄像头列表 Future refreshCameraList() async { if (state.detectingCamera) stopDetectingCamera(); state.cameraList = []; state.cameraAvailable = null; await Future.delayed(Duration(milliseconds: 100)); state.cameraList = await _trtcGetCameras(); for (int i = 0; i < state.deviceList.length; i++) { if (state.deviceList[i].type == HardwareDeviceType.camera) { state.deviceList.removeAt(i); i--; } } state.deviceList.addAll(state.cameraList); } /// 刷新麦克风列表 Future refreshMicrophoneList() async { if (state.detectingMicrophone) stopDetectingMicrophone(); state.microphoneList = []; state.microphoneAvailable = null; await Future.delayed(Duration(milliseconds: 100)); state.microphoneList = await _trtcGetMicrophones(); for (int i = 0; i < state.deviceList.length; i++) { if (state.deviceList[i].type == HardwareDeviceType.microphone) { state.deviceList.removeAt(i); i--; } } state.deviceList.addAll(state.microphoneList); } /// 调用 TRTC 获取摄像头列表 Future> _trtcGetCameras() async { List deviceList = []; TRTCCloud trtcCloud = (await TRTCCloud.sharedInstance())!; TXDeviceManager deviceManager = trtcCloud.getDeviceManager(); final List? cameras = await deviceManager.getDevicesList(2); if (cameras != null && cameras.isNotEmpty) { cameras.forEach((camera) { deviceList.add(HardwareDevice( id: camera["deviceId"], name: camera["label"], type: HardwareDeviceType.camera)); }); } return deviceList; } /// 调用 TRTC 获取麦克风列表 Future> _trtcGetMicrophones() async { List deviceList = []; TRTCCloud trtcCloud = (await TRTCCloud.sharedInstance())!; TXDeviceManager deviceManager = trtcCloud.getDeviceManager(); final List? microphones = await deviceManager.getDevicesList(0); if (microphones != null && microphones.isNotEmpty) { microphones.forEach((microphone) { deviceList.add(HardwareDevice( id: microphone["deviceId"], name: microphone["label"], type: HardwareDeviceType.microphone)); }); } return deviceList; } /// 调用 TRTC 获取扬声器列表 Future> _trtcGetSpeakers() async { List deviceList = []; TRTCCloud trtcCloud = (await TRTCCloud.sharedInstance())!; TXDeviceManager deviceManager = trtcCloud.getDeviceManager(); final List? speakers = await deviceManager.getDevicesList(1); if (speakers != null && speakers.isNotEmpty) { speakers.forEach((speaker) { deviceList.add(HardwareDevice( id: speaker["deviceId"], name: speaker["label"], type: HardwareDeviceType.speaker)); }); } return deviceList; } /// TODO 调用 js 获取所有设备列表 /// const devices = await navigator.mediaDevices.enumerateDevices(); /// 打开当前选中的摄像头 _openSelectedCamera() { bool found = false; int cameraIndex = 0; for (var i = 0; i < _cameras.length; i++) { if (_cameras[i].name == state.currentCamera?.name) { cameraIndex = i; found = true; break; } } if (!found) { print("未找到当前选中的摄像头"); return; } cameraController = CameraController(_cameras[cameraIndex], ResolutionPreset.max); cameraController.initialize().then((_) { state.isDisplayCameraWindow = true; }).catchError((Object e) { if (e is CameraException) { switch (e.code) { case 'CameraAccessDenied': // Handle access errors here. break; default: // Handle other errors here. break; } } }); } /// 关闭摄像头并释放 _stopCamera() { state.isDisplayCameraWindow = false; if (cameraController.value.isStreamingImages) { cameraController.stopImageStream(); } cameraController.dispose(); } /// 使用当前的扬声器播放测试音频 Future _startPlaySound() async { await flutterSound.startPlayer( fromURI: "assets/testspeak.mp3", codec: Codec.aacADTS, whenFinished: () { print("播放完成"); }); } /// 停止播放音频 _stopPlaySound() { print("停止播放音频"); flutterSound.stopPlayer(); } /// 初始化播放器 Future _initThePlayer() async { await flutterSound.openPlayer(); await flutterSound .setSubscriptionDuration(const Duration(milliseconds: 100)); state.isDisplaySpeakerWave = true; } // 开始采集麦克风音频 void _startRecordMicrophone() async { /// 获取到当前选中的麦克风的id if (state.currentMicrophone == null) { return; } final String fileNameWithMicrophoneId = "${state.currentMicrophone!.id}.webm"; /// 将麦克风的id作为文件名,web端的record会做处理,会将文件名作为选中的麦克风id进行设置 await flutterRecorder.startRecorder( toFile: fileNameWithMicrophoneId, codec: _codec, audioSource: AudioSource.microphone); } /// 停止采集麦克风音频 Future _stopRecordMicrophone() async { await flutterRecorder.stopRecorder(); } /// 初始化麦克风录音器 Future _initTheRecorder() async { await flutterRecorder.openRecorder(); if (!await flutterRecorder.isEncoderSupported(_codec) && kIsWeb) { _codec = Codec.opusWebM; _mPath = 'tau_file.webm'; if (!await flutterRecorder.isEncoderSupported(_codec) && kIsWeb) { state.isDisplayMicrophoneWave = true; return; } } // 设置采样率 await flutterRecorder .setSubscriptionDuration(const Duration(milliseconds: 50)); final session = await AudioSession.instance; await session.configure(AudioSessionConfiguration( avAudioSessionCategory: AVAudioSessionCategory.playAndRecord, avAudioSessionCategoryOptions: AVAudioSessionCategoryOptions.allowBluetooth | AVAudioSessionCategoryOptions.defaultToSpeaker, avAudioSessionMode: AVAudioSessionMode.spokenAudio, avAudioSessionRouteSharingPolicy: AVAudioSessionRouteSharingPolicy.defaultPolicy, avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none, androidAudioAttributes: const AndroidAudioAttributes( contentType: AndroidAudioContentType.speech, flags: AndroidAudioFlags.none, usage: AndroidAudioUsage.voiceCommunication, ), androidAudioFocusGainType: AndroidAudioFocusGainType.gain, androidWillPauseWhenDucked: true, )); state.isDisplayMicrophoneWave = true; } /// 在 widget 内存中分配后立即调用。 @override void onInit() async { await _intialize(); super.onInit(); } /// 在 onInit() 之后调用 1 帧。这是进入的理想场所 @override void onReady() { super.onReady(); } /// 在 [onDelete] 方法之前调用。 @override void onClose() { super.onClose(); } /// dispose 释放内存 @override void dispose() { super.dispose(); cameraController.dispose(); flutterSound.closePlayer(); flutterRecorder.closeRecorder(); } }