flet-audio-recorder 0.2.0.dev18__py3-none-any.whl → 0.2.0.dev50__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of flet-audio-recorder might be problematic. Click here for more details.

@@ -1,5 +1,4 @@
1
1
  import 'dart:async';
2
- import 'dart:convert';
3
2
 
4
3
  import 'package:flet/flet.dart';
5
4
  import 'package:flutter/widgets.dart';
@@ -7,159 +6,86 @@ import 'package:record/record.dart';
7
6
 
8
7
  import 'utils/audio_recorder.dart';
9
8
 
10
- class AudioRecorderControl extends StatefulWidget {
11
- final Control? parent;
12
- final Control control;
13
- final FletControlBackend backend;
9
+ class AudioRecorderService extends FletService {
10
+ AudioRecorderService({required super.control});
14
11
 
15
- const AudioRecorderControl(
16
- {super.key,
17
- required this.parent,
18
- required this.control,
19
- required this.backend});
20
-
21
- @override
22
- State<AudioRecorderControl> createState() => _AudioRecorderControlState();
23
- }
24
-
25
- class _AudioRecorderControlState extends State<AudioRecorderControl>
26
- with FletStoreMixin {
27
12
  AudioRecorder? recorder;
28
- void Function(RecordState)? _onStateChanged;
29
13
  StreamSubscription? _onStateChangedSubscription;
30
14
 
31
15
  @override
32
- void initState() {
33
- debugPrint("AudioRecorder.initState($hashCode)");
34
- recorder = widget.control.state["recorder"];
35
- if (recorder == null) {
36
- recorder = AudioRecorder();
37
- recorder = widget.control.state["recorder"] = recorder;
38
- }
16
+ void init() {
17
+ super.init();
18
+ debugPrint("AudioRecorder.init($hashCode)");
19
+ control.addInvokeMethodListener(_invokeMethod);
39
20
 
40
- _onStateChangedSubscription = recorder?.onStateChanged().listen((state) {
41
- _onStateChanged?.call(state);
42
- });
21
+ recorder = AudioRecorder();
43
22
 
44
- widget.control.onRemove.clear();
45
- widget.control.onRemove.add(_onRemove);
46
- super.initState();
47
- }
48
-
49
- void _onRemove() {
50
- debugPrint("AudioRecorder.remove($hashCode)");
51
- widget.control.state["recorder"]?.dispose();
52
- widget.backend.unsubscribeMethods(widget.control.id);
23
+ _onStateChangedSubscription = recorder!.onStateChanged().listen((state) {
24
+ _onStateChanged.call(state);
25
+ });
53
26
  }
54
27
 
55
- @override
56
- void deactivate() {
57
- debugPrint("AudioRecorder.deactivate($hashCode)");
58
- _onStateChangedSubscription?.cancel();
59
- super.deactivate();
28
+ void _onStateChanged(RecordState state) {
29
+ var stateMap = {
30
+ RecordState.record: "recording",
31
+ RecordState.pause: "paused",
32
+ RecordState.stop: "stopped",
33
+ };
34
+ control.triggerEvent("state_change", stateMap[state]);
60
35
  }
61
36
 
62
- Future<String?> stopRecording() async {
63
- debugPrint("AudioRecorder.stopRecording($hashCode)");
64
- final path = await recorder!.stop();
65
- return path;
37
+ Future<dynamic> _invokeMethod(String name, dynamic args) async {
38
+ debugPrint("AudioRecorder.$name($args)");
39
+ switch (name) {
40
+ case "start_recording":
41
+ final config = parseRecordConfig(args["configuration"]);
42
+ if (config != null && await recorder!.hasPermission()) {
43
+ final out = control.backend.getAssetSource(args["output_path"] ?? "");
44
+ if (!isWebPlatform() && !out.isFile) {
45
+ // on non-web/IO platforms, the output path must be a valid file path
46
+ return false;
47
+ }
48
+
49
+ await recorder!.start(config, path: out.path);
50
+ return true;
51
+ }
52
+ return false;
53
+ case "stop_recording":
54
+ return await recorder!.stop();
55
+ case "cancel_recording":
56
+ await recorder!.cancel();
57
+ case "resume_recording":
58
+ await recorder!.resume();
59
+ case "pause_recording":
60
+ await recorder!.pause();
61
+ case "is_supported_encoder":
62
+ var encoder = parseAudioEncoder(args["encoder"]);
63
+ if (encoder != null) {
64
+ return await recorder!.isEncoderSupported(encoder);
65
+ }
66
+ break;
67
+ case "is_paused":
68
+ return await recorder!.isPaused();
69
+ case "is_recording":
70
+ return await recorder!.isRecording();
71
+ case "has_permission":
72
+ return await recorder!.hasPermission();
73
+ case "get_input_devices":
74
+ List<InputDevice> devices = await recorder!.listInputDevices();
75
+ return devices.asMap().map((k, v) {
76
+ return MapEntry(v.id, v.label);
77
+ });
78
+ default:
79
+ throw Exception("Unknown AudioRecorder method: $name");
80
+ }
66
81
  }
67
82
 
68
83
  @override
69
- Widget build(BuildContext context) {
70
- debugPrint(
71
- "AudioRecorder build: ${widget.control.id} (${widget.control.hashCode})");
72
-
73
- int bitRate = widget.control.attrInt("bitRate", 128000)!;
74
- int sampleRate = widget.control.attrInt("sampleRate", 44100)!;
75
- int numChannels = widget.control.attrInt("channels", 2)!;
76
- bool autoGain = widget.control.attrBool("autoGain", false)!;
77
- bool cancelEcho = widget.control.attrBool("cancelEcho", false)!;
78
- bool suppressNoise = widget.control.attrBool("suppressNoise", false)!;
79
- AudioEncoder audioEncoder =
80
- parseAudioEncoder(widget.control.attrString("audioEncoder", "wav"))!;
81
-
82
- _onStateChanged = (state) {
83
- debugPrint("AudioRecorder($hashCode) - state_changed: ${state.name}");
84
- var s = state.name.toString();
85
- if (s == "record") {
86
- s = "recording";
87
- } else if (s == "pause") {
88
- s = "paused";
89
- } else if (s == "stop") {
90
- s = "stopped";
91
- }
92
- widget.backend.triggerControlEvent(widget.control.id, "state_changed", s);
93
- };
94
-
95
- () async {
96
- widget.backend.subscribeMethods(widget.control.id,
97
- (methodName, args) async {
98
- switch (methodName) {
99
- case "start_recording":
100
- if (await recorder!.hasPermission()) {
101
- if (args["outputPath"] != null) {
102
- await recorder!.start(
103
- RecordConfig(
104
- encoder: audioEncoder,
105
- bitRate: bitRate,
106
- sampleRate: sampleRate,
107
- numChannels: numChannels,
108
- autoGain: autoGain,
109
- echoCancel: cancelEcho,
110
- noiseSuppress: suppressNoise,
111
- ),
112
- path: args["outputPath"]!);
113
- return "true";
114
- }
115
- break;
116
- }
117
- return null;
118
- case "stop_recording":
119
- debugPrint("AudioRecorder.stopRecording($hashCode)");
120
- String? out = await recorder!.stop();
121
- return out;
122
- case "cancel_recording":
123
- debugPrint("AudioRecorder.cancelRecording($hashCode)");
124
- await recorder!.cancel();
125
- case "resume_recording":
126
- debugPrint("AudioRecorder.resumeRecording($hashCode)");
127
- await recorder!.resume();
128
- case "pause_recording":
129
- debugPrint("AudioRecorder.pauseRecording($hashCode)");
130
- await recorder!.pause();
131
- case "is_supported_encoder":
132
- debugPrint("AudioRecorder.isEncoderSupported($hashCode)");
133
- if (parseAudioEncoder(args["encoder"]) != null) {
134
- bool isSupported = await recorder!.isEncoderSupported(
135
- parseAudioEncoder(args["encoder"]) ?? AudioEncoder.wav);
136
- return isSupported.toString();
137
- }
138
- break;
139
- case "is_paused":
140
- debugPrint("AudioRecorder.isPaused($hashCode)");
141
- bool isPaused = await recorder!.isPaused();
142
- return isPaused.toString();
143
- case "is_recording":
144
- debugPrint("AudioRecorder.isRecording($hashCode)");
145
- bool isRecording = await recorder!.isRecording();
146
- return isRecording.toString();
147
- case "has_permission":
148
- debugPrint("AudioRecorder.hasPermission($hashCode)");
149
- bool hasPermission = await recorder!.hasPermission();
150
- return hasPermission.toString();
151
- case "get_input_devices":
152
- debugPrint("AudioRecorder.getInputDevices($hashCode)");
153
- List<InputDevice> devices = await recorder!.listInputDevices();
154
- String devicesJson = json.encode(devices.asMap().map((key, value) {
155
- return MapEntry(key, (value.id, value.label));
156
- }).toString());
157
- return devicesJson;
158
- }
159
- return null;
160
- });
161
- }();
162
-
163
- return const SizedBox.shrink();
84
+ void dispose() {
85
+ debugPrint("AudioRecorder(${control.id}).dispose()");
86
+ _onStateChangedSubscription?.cancel();
87
+ recorder?.dispose();
88
+ control.removeInvokeMethodListener(_invokeMethod);
89
+ super.dispose();
164
90
  }
165
91
  }
@@ -0,0 +1,15 @@
1
+ import 'package:flet/flet.dart';
2
+
3
+ import 'audio_recorder.dart';
4
+
5
+ class Extension extends FletExtension {
6
+ @override
7
+ FletService? createService(Control control) {
8
+ switch (control.type) {
9
+ case "AudioRecorder":
10
+ return AudioRecorderService(control: control);
11
+ default:
12
+ return null;
13
+ }
14
+ }
15
+ }
@@ -1,26 +1,73 @@
1
+ import 'package:collection/collection.dart';
2
+ import 'package:flet/flet.dart';
1
3
  import 'package:record/record.dart';
2
4
 
3
- AudioEncoder? parseAudioEncoder(String? encoding) {
4
- switch (encoding?.toLowerCase()) {
5
- case "aaclc":
6
- return AudioEncoder.aacLc;
7
- case "aaceld":
8
- return AudioEncoder.aacEld;
9
- case "aache":
10
- return AudioEncoder.aacHe;
11
- case "amrnb":
12
- return AudioEncoder.amrNb;
13
- case "amrwb":
14
- return AudioEncoder.amrWb;
15
- case "opus":
16
- return AudioEncoder.opus;
17
- case "flac":
18
- return AudioEncoder.flac;
19
- case "wav":
20
- return AudioEncoder.wav;
21
- case "pcm16bits":
22
- return AudioEncoder.pcm16bits;
23
- default:
24
- return null;
25
- }
5
+ AudioEncoder? parseAudioEncoder(String? value, [AudioEncoder? defaultValue]) {
6
+ if (value == null) return defaultValue;
7
+ return AudioEncoder.values.firstWhereOrNull(
8
+ (e) => e.name.toLowerCase() == value.toLowerCase()) ??
9
+ defaultValue;
10
+ }
11
+
12
+ InputDevice? parseInputDevice(dynamic value, [InputDevice? defaultValue]) {
13
+ if (value == null) return defaultValue;
14
+ return InputDevice(id: value["id"], label: value["label"]);
15
+ }
16
+
17
+ AndroidAudioSource? parseAndroidAudioSource(String? value,
18
+ [AndroidAudioSource? defaultValue]) {
19
+ if (value == null) return defaultValue;
20
+ return AndroidAudioSource.values.firstWhereOrNull(
21
+ (e) => e.name.toLowerCase() == value.toLowerCase()) ??
22
+ defaultValue;
23
+ }
24
+
25
+ AndroidRecordConfig? parseAndroidRecordConfig(dynamic value,
26
+ [AndroidRecordConfig? defaultValue]) {
27
+ if (value == null) return defaultValue;
28
+ return AndroidRecordConfig(
29
+ audioSource: parseAndroidAudioSource(
30
+ value["audio_source"], AndroidAudioSource.defaultSource)!,
31
+ manageBluetooth: parseBool(value["manage_bluetooth"], true)!,
32
+ muteAudio: parseBool(value["mute_audio"], false)!,
33
+ useLegacy: parseBool(value["use_legacy"], false)!);
34
+ }
35
+
36
+ IosAudioCategoryOption? parseIosAudioCategoryOption(String? value,
37
+ [IosAudioCategoryOption? defaultValue]) {
38
+ if (value == null) return defaultValue;
39
+ return IosAudioCategoryOption.values.firstWhereOrNull(
40
+ (e) => e.name.toLowerCase() == value.toLowerCase()) ??
41
+ defaultValue;
42
+ }
43
+
44
+ IosRecordConfig? parseIosRecordConfig(dynamic value,
45
+ [IosRecordConfig? defaultValue]) {
46
+ if (value == null) return defaultValue;
47
+ var options = (value["options"] as List)
48
+ .map((o) => parseIosAudioCategoryOption(o))
49
+ .nonNulls
50
+ .toList();
51
+ return IosRecordConfig(
52
+ manageAudioSession: parseBool(value["manage_audio_session"], true)!,
53
+ categoryOptions: options,
54
+ );
55
+ }
56
+
57
+ RecordConfig? parseRecordConfig(dynamic value, [RecordConfig? defaultValue]) {
58
+ if (value == null) return defaultValue;
59
+ return RecordConfig(
60
+ autoGain: parseBool(value["auto_gain"], false)!,
61
+ bitRate: parseInt(value["bit_rate"], 128000)!,
62
+ encoder: parseAudioEncoder(value["encoder"], AudioEncoder.wav)!,
63
+ echoCancel: parseBool(value["cancel_echo"], false)!,
64
+ noiseSuppress: parseBool(value["suppress_noise"], false)!,
65
+ numChannels: parseInt(value["channels"], 2)!,
66
+ device: parseInputDevice(value["device"]),
67
+ sampleRate: parseInt(value["sample_rate"], 44100)!,
68
+ androidConfig: parseAndroidRecordConfig(
69
+ value["android_configuration"], const AndroidRecordConfig())!,
70
+ iosConfig: parseIosRecordConfig(
71
+ value["ios_configuration"], const IosRecordConfig())!,
72
+ );
26
73
  }