|
@@ -5,11 +5,13 @@ import 'package:custom_notification/custom_notification.dart';
|
|
|
import 'package:electronic_assistant/module/record/record_task.dart';
|
|
import 'package:electronic_assistant/module/record/record_task.dart';
|
|
|
import 'package:electronic_assistant/router/app_pages.dart';
|
|
import 'package:electronic_assistant/router/app_pages.dart';
|
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
|
|
|
+import 'package:flutter_sound/flutter_sound.dart';
|
|
|
|
|
+import 'package:flutter_sound/public/flutter_sound_recorder.dart';
|
|
|
import 'package:get/get.dart';
|
|
import 'package:get/get.dart';
|
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:path_provider/path_provider.dart';
|
|
|
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
|
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
|
|
|
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
|
import 'package:get/get_rx/src/rx_types/rx_types.dart';
|
|
|
-import 'package:record/record.dart';
|
|
|
|
|
|
|
+import 'package:permission_handler/permission_handler.dart';
|
|
|
import 'package:uuid/uuid.dart';
|
|
import 'package:uuid/uuid.dart';
|
|
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
|
import 'package:wakelock_plus/wakelock_plus.dart';
|
|
|
import '../../data/bean/talks.dart';
|
|
import '../../data/bean/talks.dart';
|
|
@@ -37,14 +39,17 @@ class RecordHandler {
|
|
|
|
|
|
|
|
final Rx<RecordStatus> currentStatus = RecordStatus.pending.obs;
|
|
final Rx<RecordStatus> currentStatus = RecordStatus.pending.obs;
|
|
|
final RxDouble currentDuration = 0.0.obs;
|
|
final RxDouble currentDuration = 0.0.obs;
|
|
|
- final AudioRecorder _record = AudioRecorder();
|
|
|
|
|
|
|
+
|
|
|
|
|
+ final FlutterSoundRecorder _soundPlayer = FlutterSoundRecorder();
|
|
|
|
|
+ StreamController<Uint8List>? recordingDataController;
|
|
|
|
|
+
|
|
|
final RecordConfig _recordConfig = RecordConfig(
|
|
final RecordConfig _recordConfig = RecordConfig(
|
|
|
- encoder: AudioEncoder.pcm16bits,
|
|
|
|
|
- bitRate: 16000,
|
|
|
|
|
|
|
+ codec: Codec.pcm16,
|
|
|
sampleRate: SampleRate.rate44_1k.value,
|
|
sampleRate: SampleRate.rate44_1k.value,
|
|
|
numChannels: Channel.mono.value,
|
|
numChannels: Channel.mono.value,
|
|
|
);
|
|
);
|
|
|
-
|
|
|
|
|
|
|
+ StreamSubscription? _recorderSubscription;
|
|
|
|
|
+ bool? _isSoundInited;
|
|
|
String? _lastRecordId;
|
|
String? _lastRecordId;
|
|
|
|
|
|
|
|
final int _serviceId = 256;
|
|
final int _serviceId = 256;
|
|
@@ -148,8 +153,8 @@ class RecordHandler {
|
|
|
|
|
|
|
|
Future<void> stopRecord({bool? isStopService}) async {
|
|
Future<void> stopRecord({bool? isStopService}) async {
|
|
|
_releaseWakeLock();
|
|
_releaseWakeLock();
|
|
|
- if (await _record.isRecording()) {
|
|
|
|
|
- await _record.stop();
|
|
|
|
|
|
|
+ if (_soundPlayer.isRecording) {
|
|
|
|
|
+ await _soundPlayer.pauseRecorder();
|
|
|
}
|
|
}
|
|
|
_changeRecordStatus(RecordStatus.paused);
|
|
_changeRecordStatus(RecordStatus.paused);
|
|
|
if (isStopService == true) {
|
|
if (isStopService == true) {
|
|
@@ -206,8 +211,8 @@ class RecordHandler {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Future<void> startOrContinueRecord() async {
|
|
Future<void> startOrContinueRecord() async {
|
|
|
- bool hasPermission = await _record.hasPermission();
|
|
|
|
|
- if (!hasPermission) {
|
|
|
|
|
|
|
+ var status = await Permission.microphone.request();
|
|
|
|
|
+ if (status != PermissionStatus.granted) {
|
|
|
_onRecordPermissionDenied();
|
|
_onRecordPermissionDenied();
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -215,15 +220,12 @@ class RecordHandler {
|
|
|
await _requestForegroundTaskPermission().catchError((error) {
|
|
await _requestForegroundTaskPermission().catchError((error) {
|
|
|
debugPrint("requestForegroundTaskPermission error: $error");
|
|
debugPrint("requestForegroundTaskPermission error: $error");
|
|
|
});
|
|
});
|
|
|
-
|
|
|
|
|
|
|
+ recordingDataController = StreamController<Uint8List>();
|
|
|
File targetFile = await _getCurrentRecordFile();
|
|
File targetFile = await _getCurrentRecordFile();
|
|
|
- Stream<Uint8List> recordStream = await _record.startStream(_recordConfig);
|
|
|
|
|
- _setWakeLock();
|
|
|
|
|
- _startForegroundService();
|
|
|
|
|
- if (currentStatus.value != RecordStatus.recording) {
|
|
|
|
|
- _changeRecordStatus(RecordStatus.recording);
|
|
|
|
|
|
|
+ if (_recorderSubscription != null) {
|
|
|
|
|
+ _recorderSubscription?.cancel();
|
|
|
}
|
|
}
|
|
|
- recordStream.listen((data) async {
|
|
|
|
|
|
|
+ _recorderSubscription = recordingDataController!.stream.listen((data) {
|
|
|
if (data.isEmpty) {
|
|
if (data.isEmpty) {
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
@@ -236,6 +238,18 @@ class RecordHandler {
|
|
|
}, onError: (error) {
|
|
}, onError: (error) {
|
|
|
_changeRecordStatus(RecordStatus.paused);
|
|
_changeRecordStatus(RecordStatus.paused);
|
|
|
});
|
|
});
|
|
|
|
|
+ await _soundPlayer.openRecorder();
|
|
|
|
|
+ _isSoundInited = true;
|
|
|
|
|
+ await _soundPlayer.startRecorder(
|
|
|
|
|
+ toStream: recordingDataController!.sink,
|
|
|
|
|
+ codec: _recordConfig.codec,
|
|
|
|
|
+ numChannels: _recordConfig.numChannels,
|
|
|
|
|
+ sampleRate: _recordConfig.sampleRate);
|
|
|
|
|
+ _setWakeLock();
|
|
|
|
|
+ _startForegroundService();
|
|
|
|
|
+ if (currentStatus.value != RecordStatus.recording) {
|
|
|
|
|
+ _changeRecordStatus(RecordStatus.recording);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Future<void> _requestForegroundTaskPermission() async {
|
|
Future<void> _requestForegroundTaskPermission() async {
|
|
@@ -290,7 +304,24 @@ class RecordHandler {
|
|
|
return await file.exists() && await file.length() > 0;
|
|
return await file.exists() && await file.length() > 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void onClose() async {}
|
|
|
|
|
|
|
+ void onClose() async {
|
|
|
|
|
+ if (currentStatus.value != RecordStatus.recording) {
|
|
|
|
|
+ releaseSoundRecorder();
|
|
|
|
|
+ _cancelRecorderSubscriptions();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void releaseSoundRecorder() {
|
|
|
|
|
+ if (_isSoundInited == true) {
|
|
|
|
|
+ _soundPlayer.closeRecorder();
|
|
|
|
|
+ _isSoundInited = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void _cancelRecorderSubscriptions() {
|
|
|
|
|
+ recordingDataController = null;
|
|
|
|
|
+ _recorderSubscription?.cancel();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
Future<void> getConvertWavFile(String talkId) async {
|
|
Future<void> getConvertWavFile(String talkId) async {
|
|
|
File pcmFile = await _getCurrentRecordFile();
|
|
File pcmFile = await _getCurrentRecordFile();
|
|
@@ -326,4 +357,15 @@ class RecordHandler {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+class RecordConfig {
|
|
|
|
|
+ Codec codec;
|
|
|
|
|
+ int numChannels;
|
|
|
|
|
+ int sampleRate;
|
|
|
|
|
+
|
|
|
|
|
+ RecordConfig(
|
|
|
|
|
+ {required this.codec,
|
|
|
|
|
+ required this.numChannels,
|
|
|
|
|
+ required this.sampleRate});
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
final recordHandler = RecordHandler._();
|
|
final recordHandler = RecordHandler._();
|