|
|
@@ -2,6 +2,7 @@ import 'dart:async';
|
|
|
import 'dart:io';
|
|
|
import 'dart:typed_data';
|
|
|
import 'package:custom_notification/custom_notification.dart';
|
|
|
+import 'package:electronic_assistant/dialog/loading_dialog.dart';
|
|
|
import 'package:electronic_assistant/module/record/record_task.dart';
|
|
|
import 'package:electronic_assistant/resource/colors.gen.dart';
|
|
|
import 'package:electronic_assistant/router/app_pages.dart';
|
|
|
@@ -46,7 +47,7 @@ class RecordHandler {
|
|
|
final FlutterSoundRecorder _soundPlayer = FlutterSoundRecorder();
|
|
|
StreamController<Uint8List>? recordingDataController;
|
|
|
|
|
|
- final RecordConfig _recordConfig = RecordConfig(
|
|
|
+ static final RecordConfig recordConfig = RecordConfig(
|
|
|
codec: Codec.pcm16,
|
|
|
sampleRate: SampleRate.rate44_1k.value,
|
|
|
numChannels: Channel.mono.value,
|
|
|
@@ -131,7 +132,7 @@ class RecordHandler {
|
|
|
if (currentRecordFile.existsSync() && fileLength > 0) {
|
|
|
_changeRecordStatus(RecordStatus.paused);
|
|
|
double time = _getPcmDuration(
|
|
|
- fileLength, _recordConfig.sampleRate, 16, _recordConfig.numChannels);
|
|
|
+ fileLength, recordConfig.sampleRate, 16, recordConfig.numChannels);
|
|
|
currentDuration.value = time;
|
|
|
} else {
|
|
|
currentDuration.value = 0;
|
|
|
@@ -269,8 +270,8 @@ class RecordHandler {
|
|
|
}
|
|
|
targetFile.writeAsBytesSync(data, mode: FileMode.append);
|
|
|
currentDuration.value = currentDuration.value +
|
|
|
- _getPcmDuration(data.length, _recordConfig.sampleRate, 16,
|
|
|
- _recordConfig.numChannels);
|
|
|
+ _getPcmDuration(data.length, recordConfig.sampleRate, 16,
|
|
|
+ recordConfig.numChannels);
|
|
|
}, onDone: () {
|
|
|
_changeRecordStatus(RecordStatus.paused);
|
|
|
}, onError: (error) {
|
|
|
@@ -280,9 +281,9 @@ class RecordHandler {
|
|
|
_isSoundInited = true;
|
|
|
await _soundPlayer.startRecorder(
|
|
|
toStream: recordingDataController!.sink,
|
|
|
- codec: _recordConfig.codec,
|
|
|
- numChannels: _recordConfig.numChannels,
|
|
|
- sampleRate: _recordConfig.sampleRate);
|
|
|
+ codec: recordConfig.codec,
|
|
|
+ numChannels: recordConfig.numChannels,
|
|
|
+ sampleRate: recordConfig.sampleRate);
|
|
|
_setWakeLock();
|
|
|
_startForegroundService();
|
|
|
if (currentStatus.value != RecordStatus.recording) {
|
|
|
@@ -331,24 +332,6 @@ class RecordHandler {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- /// 判断是否有未上传的录音
|
|
|
- static Future<bool> hasUnUploadRecord() async {
|
|
|
- String? lastRecordId = KVUtil.getString(keyLastRecordId, null);
|
|
|
- if (lastRecordId == null || lastRecordId.isEmpty) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- Directory documentDir = await getApplicationDocumentsDirectory();
|
|
|
- File file = File("${documentDir.path}/.atmob/record/$lastRecordId");
|
|
|
- return await file.exists() && await file.length() > 0;
|
|
|
- }
|
|
|
-
|
|
|
- void onClose() async {
|
|
|
- if (currentStatus.value != RecordStatus.recording) {
|
|
|
- releaseSoundRecorder();
|
|
|
- _cancelRecorderSubscriptions();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
void releaseSoundRecorder() {
|
|
|
if (_isSoundInited == true) {
|
|
|
_soundPlayer.closeRecorder();
|
|
|
@@ -365,19 +348,36 @@ class RecordHandler {
|
|
|
File pcmFile = await _getCurrentRecordFile();
|
|
|
if (pcmFile.existsSync()) {
|
|
|
File wavFile = await getRecordFile(talkId);
|
|
|
- PcmWavConverter.convert(pcmFile, wavFile, _recordConfig.sampleRate,
|
|
|
- _recordConfig.numChannels, 16);
|
|
|
- pcmFile.delete();
|
|
|
- KVUtil.putString(keyLastRecordId, "");
|
|
|
+ try {
|
|
|
+ LoadingDialog.show('正在保存录音,请稍等...');
|
|
|
+ await PcmWavConverter.convert(pcmFile, wavFile, recordConfig.sampleRate,
|
|
|
+ recordConfig.numChannels, 16);
|
|
|
+ } catch (e) {
|
|
|
+ LoadingDialog.hide();
|
|
|
+ throw ServerErrorException(-1, '录音文件保存失败');
|
|
|
+ } finally {
|
|
|
+ LoadingDialog.hide();
|
|
|
+ }
|
|
|
+ //检查pcm文件是否可删除
|
|
|
+ await checkRecordSourceCanDelete(pcmFile, wavFile);
|
|
|
} else {
|
|
|
- throw Exception("pcm file not found");
|
|
|
+ throw ServerErrorException(-1, "录音文件不存在");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// 获取录音文件地址
|
|
|
- static Future<File> getRecordFile(String talkId) async {
|
|
|
- Directory documentDir = await getApplicationDocumentsDirectory();
|
|
|
- return File("${documentDir.path}/.atmob/record/$talkId.wav");
|
|
|
+ Future<void> checkRecordSourceCanDelete(File pcmFile, File wavFile) async {
|
|
|
+ if (!pcmFile.existsSync() || !wavFile.existsSync()) {
|
|
|
+ throw ServerErrorException(-1, "录音文件不存在");
|
|
|
+ }
|
|
|
+ int wavFileLength = wavFile.lengthSync();
|
|
|
+ if (wavFileLength <= 44) {
|
|
|
+ throw ServerErrorException(-1, "录音文件异常");
|
|
|
+ }
|
|
|
+ if (wavFileLength < pcmFile.lengthSync()) {
|
|
|
+ throw ServerErrorException(-1, "录音文件未转换成功");
|
|
|
+ }
|
|
|
+ pcmFile.delete();
|
|
|
+ KVUtil.putString(keyLastRecordId, "");
|
|
|
}
|
|
|
|
|
|
Future<TalkBean> saveCurrentRecord() async {
|
|
|
@@ -386,6 +386,10 @@ class RecordHandler {
|
|
|
throw ServerErrorException(-1, "录音时长不足$minRecordDuration秒");
|
|
|
}
|
|
|
await recordHandler.stopRecord(isStopService: true);
|
|
|
+ //检查录音文件
|
|
|
+ if (!await checkRecordFile()) {
|
|
|
+ throw ServerErrorException(-1, "录音文件不存在");
|
|
|
+ }
|
|
|
return talkRepository
|
|
|
.talkCreate(recordHandler.lastRecordId, currentDuration.value.toInt())
|
|
|
.then((talkInfo) async {
|
|
|
@@ -393,6 +397,44 @@ class RecordHandler {
|
|
|
return talkInfo;
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+ Future<bool> checkRecordFile() async {
|
|
|
+ File pcmFile = await _getCurrentRecordFile();
|
|
|
+ if (pcmFile.existsSync()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ void onClose() async {
|
|
|
+ if (currentStatus.value != RecordStatus.recording) {
|
|
|
+ releaseSoundRecorder();
|
|
|
+ _cancelRecorderSubscriptions();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //********************静态方法***************************/
|
|
|
+ /// 判断是否有未上传的录音
|
|
|
+ static Future<bool> hasUnUploadRecord() async {
|
|
|
+ String? lastRecordId = KVUtil.getString(keyLastRecordId, null);
|
|
|
+ if (lastRecordId == null || lastRecordId.isEmpty) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Directory documentDir = await getApplicationDocumentsDirectory();
|
|
|
+ File file = File("${documentDir.path}/.atmob/record/$lastRecordId");
|
|
|
+ return await file.exists() && await file.length() > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// 获取录音文件地址
|
|
|
+ static Future<File> getRecordFile(String talkId) async {
|
|
|
+ Directory documentDir = await getApplicationDocumentsDirectory();
|
|
|
+ return File("${documentDir.path}/.atmob/record/$talkId.wav");
|
|
|
+ }
|
|
|
+
|
|
|
+ static Future<File> getPcmRecordFile(String requestId) async {
|
|
|
+ Directory documentDir = await getApplicationDocumentsDirectory();
|
|
|
+ return File("${documentDir.path}/.atmob/record/$requestId");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
class RecordConfig {
|