2024-08-21 18:31:19 +08:00
|
|
|
|
|
2024-01-03 15:24:42 +08:00
|
|
|
|
import 'dart:async';
|
|
|
|
|
|
import 'dart:math';
|
|
|
|
|
|
|
|
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
|
|
import 'package:flutter_voice_processor/flutter_voice_processor.dart';
|
|
|
|
|
|
import 'package:get/get.dart';
|
|
|
|
|
|
import 'package:permission_handler/permission_handler.dart';
|
2024-01-06 14:49:44 +08:00
|
|
|
|
import 'package:star_lock/talk/call/callTalk.dart';
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
import '../../../../talk/call/g711.dart';
|
|
|
|
|
|
import '../../../../talk/udp/udp_manage.dart';
|
|
|
|
|
|
import '../../../../talk/udp/udp_senderManage.dart';
|
|
|
|
|
|
import '../../../../tools/baseGetXController.dart';
|
|
|
|
|
|
import '../../../../tools/eventBusEventManage.dart';
|
2024-04-26 15:38:59 +08:00
|
|
|
|
import '../../../app_settings/app_settings.dart';
|
2024-01-09 13:51:35 +08:00
|
|
|
|
import 'realTimePicture_state.dart';
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
class RealTimePictureLogic extends BaseGetXController {
|
|
|
|
|
|
final RealTimePictureState state = RealTimePictureState();
|
|
|
|
|
|
|
|
|
|
|
|
/// 初始化发送声音
|
|
|
|
|
|
initRecorder() {
|
|
|
|
|
|
state.voiceProcessor = VoiceProcessor.instance;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 收到视频流数据
|
|
|
|
|
|
StreamSubscription? _getTVDataRefreshUIEvent;
|
|
|
|
|
|
void _getTVDataRefreshUIAction() {
|
|
|
|
|
|
// 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus
|
|
|
|
|
|
_getTVDataRefreshUIEvent =
|
|
|
|
|
|
eventBus.on<GetTVDataRefreshUI>().listen((event) {
|
|
|
|
|
|
if (event.tvList.isNotEmpty) {
|
|
|
|
|
|
// 预加载图片数据
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final Uint8List imageData = Uint8List.fromList(event.tvList);
|
2024-01-03 15:24:42 +08:00
|
|
|
|
// 更新状态
|
|
|
|
|
|
state.listData.value = imageData;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-05 09:26:12 +08:00
|
|
|
|
/// 收到UDP发送的状态
|
|
|
|
|
|
StreamSubscription? _getUDPStatusRefreshUIEvent;
|
|
|
|
|
|
void _getUDPStatusRefreshUIAction() {
|
|
|
|
|
|
_getUDPStatusRefreshUIEvent =
|
2024-01-12 11:59:47 +08:00
|
|
|
|
eventBus.on<GetUDPStatusMonitorUI>().listen((event) {
|
2024-01-05 09:26:12 +08:00
|
|
|
|
state.udpStatus.value = event.udpStatus;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 监视
|
|
|
|
|
|
udpMonitorAction() async {
|
|
|
|
|
|
UDPSenderManage.sendMainProtocol(
|
|
|
|
|
|
command: 152,
|
|
|
|
|
|
commandTypeIsCalling: 1,
|
|
|
|
|
|
subCommand: 1,
|
2024-01-08 11:28:22 +08:00
|
|
|
|
lockID: state.getLockName.value,
|
2024-01-05 09:26:12 +08:00
|
|
|
|
lockIP: UDPManage().host,
|
2024-01-16 15:13:43 +08:00
|
|
|
|
userMobile: await state.userUid,
|
2024-01-05 09:26:12 +08:00
|
|
|
|
userMobileIP: await state.userMobileIP,
|
|
|
|
|
|
endData: []);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-01-03 15:24:42 +08:00
|
|
|
|
/// 挂断
|
|
|
|
|
|
udpHangUpAction() async {
|
|
|
|
|
|
UDPSenderManage.sendMainProtocol(
|
2024-01-05 09:26:12 +08:00
|
|
|
|
command: 152,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
commandTypeIsCalling: 1,
|
|
|
|
|
|
subCommand: 30,
|
|
|
|
|
|
lockID: UDPManage().lockId,
|
|
|
|
|
|
lockIP: UDPManage().host,
|
2024-01-16 15:13:43 +08:00
|
|
|
|
userMobile: await state.userUid,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
userMobileIP: await state.userMobileIP,
|
|
|
|
|
|
endData: []);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// 开门
|
2024-01-09 11:36:51 +08:00
|
|
|
|
udpOpenDoorAction(List<int> list) async {
|
2024-01-03 15:24:42 +08:00
|
|
|
|
UDPSenderManage.sendMainProtocol(
|
2024-01-05 09:26:12 +08:00
|
|
|
|
command: 152,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
commandTypeIsCalling: 1,
|
|
|
|
|
|
subCommand: 10,
|
|
|
|
|
|
lockID: UDPManage().lockId,
|
|
|
|
|
|
lockIP: UDPManage().host,
|
2024-01-16 15:13:43 +08:00
|
|
|
|
userMobile: await state.userUid,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
userMobileIP: await state.userMobileIP,
|
2024-01-09 11:36:51 +08:00
|
|
|
|
endData: list);
|
2024-01-03 15:24:42 +08:00
|
|
|
|
Get.back();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> _readG711Data() async {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final String filePath = 'assets/s10-g711.bin';
|
|
|
|
|
|
final List<int> audioData = await G711().readAssetFile(filePath);
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('发送读取711文件数据为:$audioData');// 数据为:$audioData
|
2024-01-03 15:24:42 +08:00
|
|
|
|
// return;
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('发送读取711文件数据长度为:${audioData.length}');// 数据为:$audioData
|
2024-01-03 15:24:42 +08:00
|
|
|
|
if (audioData.isNotEmpty) {
|
|
|
|
|
|
// 在这里处理你的音频数据
|
|
|
|
|
|
// pcmBytes = G711().convertList(audioData);
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('发送转换pcmBytes数据长度为:${pcmBytes.length}');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
int start = 0;
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final int length = 320;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
while (start < audioData.length) {
|
|
|
|
|
|
// await Future.delayed(const Duration(milliseconds: 50));
|
|
|
|
|
|
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final int end = (start + length > audioData.length)
|
2024-01-03 15:24:42 +08:00
|
|
|
|
? audioData.length
|
|
|
|
|
|
: start + length;
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final List<int> sublist = audioData.sublist(start, end);
|
2024-01-03 15:24:42 +08:00
|
|
|
|
sendRecordData({
|
2024-08-21 18:31:19 +08:00
|
|
|
|
'bytes': sublist,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
// "udpSendDataFrameNumber": 0,
|
2024-08-21 18:31:19 +08:00
|
|
|
|
'lockID': UDPManage().lockId,
|
|
|
|
|
|
'lockIP': UDPManage().host,
|
|
|
|
|
|
'userMobile': await state.userUid,
|
|
|
|
|
|
'userMobileIP': await state.userMobileIP,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
});
|
2024-04-26 15:38:59 +08:00
|
|
|
|
AppLog.log(sublist.toString());
|
2024-01-03 15:24:42 +08:00
|
|
|
|
start += length;
|
|
|
|
|
|
}
|
2024-04-26 15:38:59 +08:00
|
|
|
|
AppLog.log('G711数据发送完成');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
} else {
|
2024-04-26 15:38:59 +08:00
|
|
|
|
AppLog.log('Failed to read audio data.');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> startProcessing() async {
|
|
|
|
|
|
frameListener(List<int> frame) async {
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('Get data.length:${frame.length} Received data:$frame');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
for (int i = 0; i < frame.length; i++) {
|
|
|
|
|
|
frame[i] = linearToULaw(frame[i]);
|
|
|
|
|
|
}
|
2024-04-26 15:38:59 +08:00
|
|
|
|
// AppLog.log('change Get data.length:${frame.length} change Received data:$frame');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
await Future.delayed(const Duration(milliseconds: 50));
|
|
|
|
|
|
sendRecordData({
|
2024-08-21 18:31:19 +08:00
|
|
|
|
'bytes': frame,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
// "udpSendDataFrameNumber": 0,
|
2024-08-21 18:31:19 +08:00
|
|
|
|
'lockID': UDPManage().lockId,
|
|
|
|
|
|
'lockIP': UDPManage().host,
|
|
|
|
|
|
'userMobile': await state.userUid,
|
|
|
|
|
|
'userMobileIP': await state.userMobileIP,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
errorListener(VoiceProcessorException error) {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
AppLog.log('VoiceProcessorException: $error');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
state.voiceProcessor?.addFrameListener(frameListener);
|
|
|
|
|
|
state.voiceProcessor?.addErrorListener(errorListener);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (await state.voiceProcessor?.hasRecordAudioPermission() ?? false) {
|
|
|
|
|
|
await state.voiceProcessor?.start(320, 8000);
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final bool? isRecording = await state.voiceProcessor?.isRecording();
|
2024-01-03 15:24:42 +08:00
|
|
|
|
} else {}
|
|
|
|
|
|
} on PlatformException catch (ex) {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
AppLog.log('PlatformException: $ex');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
} finally {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<void> stopProcessing() async {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await state.voiceProcessor?.stop();
|
|
|
|
|
|
} on PlatformException catch (ex) {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
AppLog.log('PlatformException: $ex');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
} finally {}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void onError(Object e) {
|
2024-04-26 15:38:59 +08:00
|
|
|
|
AppLog.log(e.toString());
|
2024-01-03 15:24:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sendRecordData(Map<String, dynamic> args) async {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final List<int> bytes = args['bytes'];
|
2024-01-03 15:24:42 +08:00
|
|
|
|
// int udpSendDataFrameNumber = args["udpSendDataFrameNumber"];
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final String? lockID = args['lockID'];
|
|
|
|
|
|
final String? lockIP = args['lockIP'];
|
|
|
|
|
|
final String? userMobile = args['userMobile'];
|
|
|
|
|
|
final String? userMobileIP = args['userMobileIP'];
|
2024-01-03 15:24:42 +08:00
|
|
|
|
state.udpSendDataFrameNumber++;
|
|
|
|
|
|
if (state.udpSendDataFrameNumber >= 65536) state.udpSendDataFrameNumber = 1;
|
|
|
|
|
|
// 57
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final List<int> topBytes = [];
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
topBytes.addAll([
|
|
|
|
|
|
1, 1, 1, 1, // 时间戳
|
|
|
|
|
|
1, 0, // 音频
|
|
|
|
|
|
1, 0, // 帧序号
|
|
|
|
|
|
64, 0, 0, 0, // 帧长度
|
|
|
|
|
|
1, 0, // 总包数
|
|
|
|
|
|
1, 0, // 当前包号
|
|
|
|
|
|
64, 1, // 数据长度
|
|
|
|
|
|
176, 4, // 保留
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
2024-08-21 18:31:19 +08:00
|
|
|
|
topBytes[6] = state.udpSendDataFrameNumber & 0x000000FF;
|
|
|
|
|
|
topBytes[7] = (state.udpSendDataFrameNumber & 0x0000FF00) >> 8;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
topBytes.addAll(bytes);
|
2024-08-21 18:31:19 +08:00
|
|
|
|
AppLog.log('setVoiceBytes:$topBytes');
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
UDPSenderManage.sendMainProtocol(
|
2024-01-12 11:59:47 +08:00
|
|
|
|
command: 152,
|
2024-01-03 15:24:42 +08:00
|
|
|
|
commandTypeIsCalling: 1,
|
|
|
|
|
|
subCommand: 8,
|
|
|
|
|
|
lockID: lockID,
|
|
|
|
|
|
lockIP: lockIP,
|
|
|
|
|
|
userMobile: userMobile,
|
|
|
|
|
|
userMobileIP: userMobileIP,
|
|
|
|
|
|
endData: topBytes);
|
|
|
|
|
|
|
|
|
|
|
|
// UDPManage().sendData(topBytes);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 拿到的音频转化成pcm
|
|
|
|
|
|
int linearToULaw(int pcmVal) {
|
|
|
|
|
|
int mask;
|
|
|
|
|
|
int seg;
|
|
|
|
|
|
int uval;
|
|
|
|
|
|
|
|
|
|
|
|
if (pcmVal < 0) {
|
|
|
|
|
|
pcmVal = 0x84 - pcmVal;
|
|
|
|
|
|
mask = 0x7F;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
pcmVal += 0x84;
|
|
|
|
|
|
mask = 0xFF;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
seg = search(pcmVal);
|
|
|
|
|
|
if (seg >= 8) {
|
|
|
|
|
|
return 0x7F ^ mask;
|
|
|
|
|
|
} else {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
uval = seg << 4;
|
|
|
|
|
|
uval |= (pcmVal >> (seg + 3)) & 0xF;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
return uval ^ mask;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int search(int val) {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final List<int> table = [
|
2024-01-03 15:24:42 +08:00
|
|
|
|
0xFF,
|
|
|
|
|
|
0x1FF,
|
|
|
|
|
|
0x3FF,
|
|
|
|
|
|
0x7FF,
|
|
|
|
|
|
0xFFF,
|
|
|
|
|
|
0x1FFF,
|
|
|
|
|
|
0x3FFF,
|
|
|
|
|
|
0x7FFF
|
|
|
|
|
|
];
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final int size = 8;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
|
|
|
if (val <= table[i]) {
|
|
|
|
|
|
return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return size;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double _calculateVolumeLevel(List<int> frame) {
|
|
|
|
|
|
double rms = 0.0;
|
|
|
|
|
|
for (int sample in frame) {
|
|
|
|
|
|
rms += pow(sample, 2);
|
|
|
|
|
|
}
|
|
|
|
|
|
rms = sqrt(rms / frame.length);
|
|
|
|
|
|
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final double dbfs = 20 * log(rms / 32767.0) / log(10);
|
|
|
|
|
|
final double normalizedValue = (dbfs + 50) / 50;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
return normalizedValue.clamp(0.0, 1.0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Future<bool> getPermissionStatus() async {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final Permission permission = Permission.microphone;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
//granted 通过,denied 被拒绝,permanentlyDenied 拒绝且不在提示
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final PermissionStatus status = await permission.status;
|
2024-01-03 15:24:42 +08:00
|
|
|
|
if (status.isGranted) {
|
|
|
|
|
|
return true;
|
|
|
|
|
|
} else if (status.isDenied) {
|
|
|
|
|
|
requestPermission(permission);
|
|
|
|
|
|
} else if (status.isPermanentlyDenied) {
|
|
|
|
|
|
openAppSettings();
|
|
|
|
|
|
} else if (status.isRestricted) {
|
|
|
|
|
|
requestPermission(permission);
|
|
|
|
|
|
} else {}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///申请权限
|
|
|
|
|
|
void requestPermission(Permission permission) async {
|
2024-08-21 18:31:19 +08:00
|
|
|
|
final PermissionStatus status = await permission.request();
|
2024-01-03 15:24:42 +08:00
|
|
|
|
if (status.isPermanentlyDenied) {
|
|
|
|
|
|
openAppSettings();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void onReady() {
|
|
|
|
|
|
super.onReady();
|
|
|
|
|
|
|
|
|
|
|
|
_getTVDataRefreshUIAction();
|
2024-01-05 09:26:12 +08:00
|
|
|
|
_getUDPStatusRefreshUIAction();
|
2024-01-03 15:24:42 +08:00
|
|
|
|
|
|
|
|
|
|
initRecorder();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void onInit() {
|
|
|
|
|
|
super.onInit();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
void onClose() {
|
2024-04-15 14:53:14 +08:00
|
|
|
|
CallTalk().finishAVData();
|
2024-01-03 15:24:42 +08:00
|
|
|
|
_getTVDataRefreshUIEvent!.cancel();
|
2024-01-05 09:26:12 +08:00
|
|
|
|
_getUDPStatusRefreshUIEvent!.cancel();
|
|
|
|
|
|
if (state.oneMinuteTimeTimer != null) {
|
|
|
|
|
|
state.oneMinuteTimeTimer.cancel();
|
|
|
|
|
|
}
|
2024-01-03 15:24:42 +08:00
|
|
|
|
stopProcessing();
|
2024-01-08 17:56:12 +08:00
|
|
|
|
state.listData.value = Uint8List(0);
|
2024-01-03 15:24:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|