修改对讲发送逻辑
This commit is contained in:
parent
1806c15c2f
commit
4492e75a40
@ -1,3 +1,4 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
@ -7,8 +12,10 @@ import 'package:flutter_sound/flutter_sound.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:network_info_plus/network_info_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:flutter_audio_capture/flutter_audio_capture.dart';
|
||||
|
||||
import '../../../../app_settings/app_colors.dart';
|
||||
import '../../../../blue/io_tool/io_tool.dart';
|
||||
import '../../../../talk/udp/udp_manage.dart';
|
||||
import '../../../../talk/udp/udp_senderManage.dart';
|
||||
import '../../../../talk/udp/udp_talkClass.dart';
|
||||
@ -28,9 +35,10 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
||||
final logic = Get.put(LockMonitoringLogic());
|
||||
final state = Get.find<LockMonitoringLogic>().state;
|
||||
|
||||
late FlutterSoundRecorder recorder;
|
||||
late FlutterSoundPlayer player;
|
||||
late String filePath;
|
||||
late FlutterAudioCapture audioCapture;
|
||||
// late FlutterSoundRecorder recorder;
|
||||
// late FlutterSoundPlayer player;
|
||||
// late String filePath;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -198,10 +206,10 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
||||
print("onLongPressUp");
|
||||
// _playRecording();
|
||||
|
||||
// _stopCapture();
|
||||
if (state.udpStatus.value == 9) {
|
||||
state.udpStatus.value = 8;
|
||||
}
|
||||
_stopRecording();
|
||||
}
|
||||
)
|
||||
),
|
||||
@ -334,104 +342,323 @@ class _LockMonitoringPageState extends State<LockMonitoringPage> {
|
||||
|
||||
//录音处理
|
||||
_initRecorder() {
|
||||
recorder = FlutterSoundRecorder();
|
||||
// recorder = FlutterSoundRecorder();
|
||||
audioCapture = FlutterAudioCapture();
|
||||
}
|
||||
|
||||
// Future<void> _startRecording(List<int> dataList) async {
|
||||
// try {
|
||||
// await recorder.openAudioSession();
|
||||
// /// 监听录音
|
||||
// recorder.onProgress!.listen((e) {
|
||||
// print("onProgress:$e");
|
||||
// });
|
||||
//
|
||||
// await recorder.startRecorder(
|
||||
// onProgress: (StreamController<FooderData> progress) {
|
||||
// progress.stream.listen((FooderData fooData) {
|
||||
// // 在这里处理 PCM 数据(fooData.buffer)
|
||||
// print('Received PCM data: ${fooData.buffer.length} bytes');
|
||||
// });
|
||||
// },
|
||||
// );
|
||||
// setState(() {
|
||||
// _isRecording = true;
|
||||
// });
|
||||
// } catch (e) {
|
||||
// print('Error starting recording: $e');
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<void> _stopRecording() async {
|
||||
// try {
|
||||
// await recorder.stopRecorder();
|
||||
// await _recorder.closeAudioSession();
|
||||
// setState(() {
|
||||
// _isRecording = false;
|
||||
// });
|
||||
// } catch (e) {
|
||||
// print('Error stopping recording: $e');
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
//开始录音
|
||||
_startRecording() async {
|
||||
getFilePath().then((value) {
|
||||
filePath = value;
|
||||
});
|
||||
await recorder.openRecorder();
|
||||
await recorder.startRecorder(
|
||||
toFile: filePath,
|
||||
codec: Codec.pcm16WAV,
|
||||
bitRate: 8000,
|
||||
numChannels: 1,
|
||||
sampleRate: 8000,
|
||||
try {
|
||||
// _getFilePath().then((value) {
|
||||
// filePath = value;
|
||||
// });
|
||||
// await recorder.openRecorder();
|
||||
// // 监听录音
|
||||
// recorder.onProgress!.listen((e) {
|
||||
// print("onProgress:$e");
|
||||
// });
|
||||
// await recorder.startRecorder(
|
||||
// toFile: filePath,
|
||||
// codec: Codec.pcm16WAV,
|
||||
// bitRate: 8000,
|
||||
// numChannels: 1,
|
||||
// sampleRate: 8000,
|
||||
// );
|
||||
|
||||
_startCapture();
|
||||
} catch (e) {
|
||||
print('Error starting recording: $e');
|
||||
}
|
||||
|
||||
// getFilePath().then((value) {
|
||||
// filePath = value;
|
||||
// });
|
||||
// await recorder.openRecorder();
|
||||
// await recorder.startRecorder(
|
||||
// toFile: filePath,
|
||||
// codec: Codec.pcm16WAV,
|
||||
// bitRate: 8000,
|
||||
// numChannels: 1,
|
||||
// sampleRate: 8000,
|
||||
// );
|
||||
}
|
||||
|
||||
Future<void> _startCapture() async {
|
||||
await audioCapture.start(
|
||||
_listener,
|
||||
onError,
|
||||
sampleRate: 8000,
|
||||
bufferSize: 3000
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _stopCapture() async {
|
||||
await audioCapture.stop();
|
||||
}
|
||||
|
||||
Future<void> _listener(dynamic obj) async {
|
||||
print('data.length:${obj.length} Received data:$obj');
|
||||
var buffer = Float64List.fromList(obj.cast<double>());
|
||||
Int16List list = float64ListToInt16List(buffer);
|
||||
print('Get data.length:${list.length} Received data:$list');
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
list[i] = linearToULaw(list[i]);
|
||||
}
|
||||
print('change Get data.length:${list.length} change Received data:$list');
|
||||
List<int> sendList = list.toList();
|
||||
|
||||
Isolate isolate = await Isolate.spawn(_sendRecordData, {
|
||||
"bytes": sendList,
|
||||
"udpSendDataFrameNumber": 0,
|
||||
"lockID": UDPManage().lockId,
|
||||
"lockIP": UDPManage().host,
|
||||
"userMobile": await Storage.getMobile(),
|
||||
"userMobileIP": await NetworkInfo().getWifiIP(),
|
||||
});
|
||||
|
||||
// 在主线程中监听子线程发送的数据
|
||||
// receivePort.listen((data) {
|
||||
// print('Received data: $data');
|
||||
// });
|
||||
}
|
||||
|
||||
void onError(Object e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
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 {
|
||||
uval = (seg << 4);
|
||||
uval |= ((pcmVal >> (seg + 3)) & 0xF);
|
||||
return uval ^ mask;
|
||||
}
|
||||
}
|
||||
|
||||
int search(int val) {
|
||||
List<int> table = [0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF];
|
||||
int size = 8;
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (val <= table[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
Int16List float64ListToInt16List(Float64List float64List) {
|
||||
Int16List int16List = Int16List(float64List.length);
|
||||
for (int i = 0; i < float64List.length; i++) {
|
||||
double sample = float64List[i];
|
||||
// Make sure the sample value is within the int16 range
|
||||
if (sample > 1.0) {
|
||||
sample = 1.0;
|
||||
} else if (sample < -1.0) {
|
||||
sample = -1.0;
|
||||
}
|
||||
// Convert the sample to int16 by scaling it to the full int16 range
|
||||
int16List[i] = (sample * 32767).toInt();
|
||||
}
|
||||
return int16List;
|
||||
}
|
||||
|
||||
//停止录音
|
||||
_stopRecording() async {
|
||||
await recorder.stopRecorder();
|
||||
// _stopRecording() async {
|
||||
// try {
|
||||
// await recorder.stopRecorder();
|
||||
// } catch (e) {
|
||||
// print('Error stopping recording: $e');
|
||||
// }
|
||||
|
||||
// await recorder.stopRecorder();
|
||||
//
|
||||
// // final file = File(filePath);
|
||||
// File file = File(filePath); // 使用 create 方法创建文件
|
||||
//
|
||||
// print('filePathfilePath:$filePath file:$file await file.exists():${await file.exists()}');
|
||||
// if (await file.exists()) {
|
||||
// final List<int> bytes = await file.readAsBytes();
|
||||
// print('Recorded audio bytes.length:${bytes.length} bytes: $bytes');
|
||||
//
|
||||
// _sendRecordData(bytes);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Future<String> _getFilePath() async {
|
||||
// final directory = await getApplicationDocumentsDirectory();
|
||||
// final filePath = '${directory.path}/recording.wav';
|
||||
//
|
||||
// // 创建文件
|
||||
// File file = File(filePath);
|
||||
// await file.create(); // 使用 create 方法创建文件
|
||||
//
|
||||
// return filePath;
|
||||
// }
|
||||
|
||||
|
||||
// Future<void> _getRecordedAudioBytes() async {
|
||||
// final file = File(filePath);
|
||||
File file = File(filePath); // 使用 create 方法创建文件
|
||||
|
||||
print('filePathfilePath:$filePath file:$file await file.exists():${await file.exists()}');
|
||||
if (await file.exists()) {
|
||||
final List<int> bytes = await file.readAsBytes();
|
||||
print('Recorded audio bytes.length:${bytes.length} bytes: $bytes');
|
||||
|
||||
_sendRecordData(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
Future<String> getFilePath() async {
|
||||
final directory = await getApplicationDocumentsDirectory();
|
||||
final filePath = '${directory.path}/recording.wav';
|
||||
|
||||
// 创建文件
|
||||
File file = File(filePath);
|
||||
await file.create(); // 使用 create 方法创建文件
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
|
||||
Future<void> _getRecordedAudioBytes() async {
|
||||
final file = File(filePath);
|
||||
if (await file.exists()) {
|
||||
final List<int> bytes = await file.readAsBytes();
|
||||
print('Recorded audio bytes: $bytes');
|
||||
}
|
||||
}
|
||||
// if (await file.exists()) {
|
||||
// final List<int> bytes = await file.readAsBytes();
|
||||
// print('Recorded audio bytes: $bytes');
|
||||
// }
|
||||
// }
|
||||
|
||||
//播放录音
|
||||
_playRecording() async {
|
||||
player = FlutterSoundPlayer();
|
||||
player.openPlayer();
|
||||
|
||||
await player.startPlayer(
|
||||
fromURI: filePath,
|
||||
codec: Codec.pcm16WAV,
|
||||
);
|
||||
// _playRecording() async {
|
||||
// player = FlutterSoundPlayer();
|
||||
// player.openPlayer();
|
||||
//
|
||||
// await player.startPlayer(
|
||||
// fromURI: filePath,
|
||||
// codec: Codec.pcm16WAV,
|
||||
// );
|
||||
// Toast.show(msg: "储存录音播放了");
|
||||
print('_playRecording() 储存录音播放了');
|
||||
}
|
||||
// print('_playRecording() 储存录音播放了');
|
||||
// }
|
||||
|
||||
//停止播放
|
||||
// _stopPlaying() async {
|
||||
// await player.stopPlayer();
|
||||
// }
|
||||
|
||||
_sendRecordData(List<int> bytes) async {
|
||||
// 刚进来是接听状态,然后改为长按对讲
|
||||
var userMobileIP = await NetworkInfo().getWifiIP();
|
||||
var userMobile = await Storage.getMobile();
|
||||
// var udpSendDataFrameNumber = 0;
|
||||
_sendRecordData(Map<String, dynamic> args) async {
|
||||
|
||||
// 57
|
||||
List<int> topBytes = [
|
||||
1, 1, 1, 1, // 时间戳
|
||||
1, 0, // 音频
|
||||
1, 0, // 帧序号
|
||||
64, 0, 0, 0, // 帧长度
|
||||
1, 0, // 总包数
|
||||
1, 0, // 当前包号
|
||||
64, 1, // 数据长度
|
||||
176, 4, // 保留
|
||||
];
|
||||
UDPSenderManage.sendMainProtocol(
|
||||
command: 150,
|
||||
commandTypeIsCalling: 1,
|
||||
subCommand: 8,
|
||||
lockID: UDPManage().lockId,
|
||||
lockIP: UDPManage().host,
|
||||
userMobile: userMobile,
|
||||
userMobileIP: userMobileIP,
|
||||
endData: bytes
|
||||
);
|
||||
List<int> bytes = args["bytes"];
|
||||
int udpSendDataFrameNumber = args["udpSendDataFrameNumber"];
|
||||
String? lockID = args["lockID"];
|
||||
String? lockIP = args["lockIP"];
|
||||
String? userMobile = args["userMobile"];
|
||||
String? userMobileIP = args["userMobileIP"];
|
||||
|
||||
int length = 320; // 每个子List的长度
|
||||
for (int i = 0; i < bytes.length; i += length) {
|
||||
int end = (i + length < bytes.length) ? i + length : bytes.length;
|
||||
bytes.sublist(i, end);
|
||||
// _sendRecordData(bytes.sublist(i, end));
|
||||
// // 刚进来是接听状态,然后改为长按对讲
|
||||
// var userMobileIP = await NetworkInfo().getWifiIP();
|
||||
// var userMobile = await Storage.getMobile();
|
||||
|
||||
while(true) {
|
||||
udpSendDataFrameNumber++;
|
||||
if (udpSendDataFrameNumber >= 65536) udpSendDataFrameNumber=1;
|
||||
// 57
|
||||
List<int> topBytes = [
|
||||
1, 1, 1, 1, // 时间戳
|
||||
1, 0, // 音频
|
||||
1, 0, // 帧序号
|
||||
64, 0, 0, 0, // 帧长度
|
||||
1, 0, // 总包数
|
||||
1, 0, // 当前包号
|
||||
64, 1, // 数据长度
|
||||
176, 4, // 保留
|
||||
];
|
||||
|
||||
ByteData byteData = ByteData(2);
|
||||
byteData.setUint16(0, udpSendDataFrameNumber, Endian.little);
|
||||
topBytes[6] = byteData.getUint8(0);
|
||||
topBytes[7] = byteData.getUint8(1);
|
||||
|
||||
topBytes.addAll(bytes);
|
||||
// print("topBytes:$topBytes");
|
||||
// UDPSenderManage.sendMainProtocol(
|
||||
// command: 150,
|
||||
// commandTypeIsCalling: 1,
|
||||
// subCommand: 8,
|
||||
// lockID: lockID,
|
||||
// lockIP: lockIP,
|
||||
// userMobile: userMobile,
|
||||
// userMobileIP: userMobileIP,
|
||||
// endData: topBytes
|
||||
// );
|
||||
|
||||
// 命令
|
||||
topBytes.add(150);
|
||||
|
||||
// 命令类型
|
||||
topBytes.add(1);
|
||||
|
||||
// 子命令
|
||||
topBytes.add(8);
|
||||
|
||||
// lockID
|
||||
List<int> lockIDData = utf8.encode(lockID!);
|
||||
topBytes.addAll(lockIDData);
|
||||
topBytes = getFixedLengthList(lockIDData, 20 - lockIDData.length);
|
||||
|
||||
// lockIP
|
||||
var lockIPList = lockIP!.split(".");
|
||||
lockIPList.forEach((element) {
|
||||
topBytes.add(int.parse(element));
|
||||
});
|
||||
|
||||
// userMobile
|
||||
List<int> userMobileData = utf8.encode(userMobile!);
|
||||
topBytes.addAll(userMobileData);
|
||||
topBytes = getFixedLengthList(topBytes, 20 - userMobileData.length);
|
||||
|
||||
// userMobileIP
|
||||
var userMobileIPList = lockIP!.split(".");
|
||||
userMobileIPList.forEach((element) {
|
||||
topBytes.add(int.parse(element));
|
||||
});
|
||||
|
||||
UDPManage().sendData(topBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:get/get.dart';
|
||||
|
||||
class LockMonitoringState {
|
||||
var isOpenVoice = false.obs;
|
||||
var udpSendDataFrameNumber = 0;// 帧序号
|
||||
var udpStatus =
|
||||
0.obs; //0:初始状态 1:等待监视 2: 3:监视中 4:呼叫成功 5:主角通话中 6:被叫通话 8:被叫通话中 9:长按说话
|
||||
var passwordTF = TextEditingController();
|
||||
|
||||
@ -19,7 +19,7 @@ class CommandUDPReciverManager {
|
||||
if (dataSize < 4) {
|
||||
return;
|
||||
}
|
||||
print("appReceiveUDPData:$data");
|
||||
// print("appReceiveUDPData:$data");
|
||||
|
||||
Uint8List data1 = Uint8List.fromList(data);
|
||||
if (data1.length == 1) {
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <aj_captcha_flutter/aj_captcha_flutter_plugin.h>
|
||||
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_audio_capture/flutter_audio_capture_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
@ -21,6 +22,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_audio_capture_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAudioCapturePlugin");
|
||||
flutter_audio_capture_plugin_register_with_registrar(flutter_audio_capture_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
|
||||
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
||||
aj_captcha_flutter
|
||||
audioplayers_linux
|
||||
file_selector_linux
|
||||
flutter_audio_capture
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
|
||||
@ -127,6 +127,7 @@ dependencies:
|
||||
flutter_sound: ^9.2.13
|
||||
ffmpeg_kit_flutter: 5.1.0-LTS
|
||||
fast_gbk: ^1.0.0
|
||||
flutter_audio_capture: ^1.1.6
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user