flet-audio-recorder 0.2.0.dev17__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.
- flet_audio_recorder/__init__.py +8 -2
- flet_audio_recorder/audio_recorder.py +212 -277
- flet_audio_recorder/types.py +336 -0
- flet_audio_recorder-0.2.0.dev50.dist-info/METADATA +69 -0
- flet_audio_recorder-0.2.0.dev50.dist-info/RECORD +18 -0
- {flet_audio_recorder-0.2.0.dev17.dist-info → flet_audio_recorder-0.2.0.dev50.dist-info}/WHEEL +1 -1
- flet_audio_recorder-0.2.0.dev50.dist-info/licenses/LICENSE +201 -0
- flutter/flet_audio_recorder/lib/flet_audio_recorder.dart +1 -1
- flutter/flet_audio_recorder/lib/src/audio_recorder.dart +67 -141
- flutter/flet_audio_recorder/lib/src/extension.dart +15 -0
- flutter/flet_audio_recorder/lib/src/utils/audio_recorder.dart +70 -23
- flutter/flet_audio_recorder/pubspec.lock +141 -84
- flutter/flet_audio_recorder/pubspec.yaml +7 -2
- flet_audio_recorder-0.2.0.dev17.dist-info/METADATA +0 -93
- flet_audio_recorder-0.2.0.dev17.dist-info/RECORD +0 -16
- flutter/flet_audio_recorder/lib/src/create_control.dart +0 -17
- {flet_audio_recorder-0.2.0.dev17.dist-info → flet_audio_recorder-0.2.0.dev50.dist-info}/top_level.txt +0 -0
flet_audio_recorder/__init__.py
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
from
|
|
1
|
+
from .audio_recorder import AudioRecorder
|
|
2
|
+
from .types import (
|
|
3
|
+
AndroidAudioSource,
|
|
4
|
+
AndroidRecorderConfiguration,
|
|
2
5
|
AudioEncoder,
|
|
3
|
-
|
|
6
|
+
AudioRecorderConfiguration,
|
|
4
7
|
AudioRecorderState,
|
|
5
8
|
AudioRecorderStateChangeEvent,
|
|
9
|
+
InputDevice,
|
|
10
|
+
IosAudioCategoryOption,
|
|
11
|
+
IosRecorderConfiguration,
|
|
6
12
|
)
|
|
@@ -1,294 +1,229 @@
|
|
|
1
|
-
import
|
|
2
|
-
from
|
|
3
|
-
from typing import
|
|
1
|
+
import asyncio
|
|
2
|
+
from dataclasses import field
|
|
3
|
+
from typing import List, Optional
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
from flet.core.control_event import ControlEvent
|
|
7
|
-
from flet.core.event_handler import EventHandler
|
|
8
|
-
from flet.core.ref import Ref
|
|
9
|
-
from flet.core.types import OptionalEventCallable
|
|
10
|
-
from flet.utils import deprecated
|
|
5
|
+
import flet as ft
|
|
11
6
|
|
|
7
|
+
from .types import (
|
|
8
|
+
AudioEncoder,
|
|
9
|
+
AudioRecorderConfiguration,
|
|
10
|
+
AudioRecorderStateChangeEvent,
|
|
11
|
+
InputDevice,
|
|
12
|
+
)
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
STOPPED = "stopped"
|
|
15
|
-
RECORDING = "recording"
|
|
16
|
-
PAUSED = "paused"
|
|
14
|
+
__all__ = ["AudioRecorder"]
|
|
17
15
|
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class AudioEncoder(Enum):
|
|
26
|
-
AACLC = "aacLc"
|
|
27
|
-
AACELD = "aacEld"
|
|
28
|
-
AACHE = "aacHe"
|
|
29
|
-
AMRNB = "amrNb"
|
|
30
|
-
AMRWB = "amrWb"
|
|
31
|
-
OPUS = "opus"
|
|
32
|
-
FLAC = "flac"
|
|
33
|
-
WAV = "wav"
|
|
34
|
-
PCM16BITS = "pcm16bits"
|
|
17
|
+
@ft.control("AudioRecorder")
|
|
18
|
+
class AudioRecorder(ft.Service):
|
|
19
|
+
"""
|
|
20
|
+
A control that allows you to record audio from your device.
|
|
35
21
|
|
|
22
|
+
This control can record audio using different audio encoders and also allows configuration
|
|
23
|
+
of various audio recording parameters such as noise suppression, echo cancellation, and more.
|
|
36
24
|
|
|
37
|
-
|
|
25
|
+
Note:
|
|
26
|
+
This control is non-visual and should be added to `Page.services` list before it can be used.
|
|
38
27
|
"""
|
|
39
|
-
A control that allows you to record audio from your device.
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
configuration: AudioRecorderConfiguration = field(
|
|
30
|
+
default_factory=lambda: AudioRecorderConfiguration()
|
|
31
|
+
)
|
|
32
|
+
"""
|
|
33
|
+
The default configuration of the audio recorder.
|
|
34
|
+
"""
|
|
42
35
|
|
|
43
|
-
|
|
36
|
+
on_state_change: ft.OptionalEventHandler[
|
|
37
|
+
AudioRecorderStateChangeEvent["AudioRecorder"]
|
|
38
|
+
] = None
|
|
39
|
+
"""
|
|
40
|
+
Event handler that is called when the state of the audio recorder changes.
|
|
41
|
+
|
|
42
|
+
Event handler argument is of type [`AudioRecorderStateChangeEvent`][(p).].
|
|
44
43
|
"""
|
|
45
44
|
|
|
46
|
-
def
|
|
45
|
+
async def start_recording_async(
|
|
47
46
|
self,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
auto_gain: Optional[bool] = None,
|
|
52
|
-
channels_num: OptionalNumber = None,
|
|
53
|
-
sample_rate: OptionalNumber = None,
|
|
54
|
-
bit_rate: OptionalNumber = None,
|
|
55
|
-
on_state_changed: OptionalEventCallable[AudioRecorderStateChangeEvent] = None,
|
|
56
|
-
#
|
|
57
|
-
# Control
|
|
58
|
-
#
|
|
59
|
-
ref: Optional[Ref] = None,
|
|
60
|
-
data: Any = None,
|
|
61
|
-
):
|
|
62
|
-
Control.__init__(
|
|
63
|
-
self,
|
|
64
|
-
ref=ref,
|
|
65
|
-
data=data,
|
|
66
|
-
)
|
|
67
|
-
self.__on_state_changed = EventHandler(
|
|
68
|
-
lambda e: AudioRecorderStateChangeEvent(e)
|
|
69
|
-
)
|
|
70
|
-
self._add_event_handler("state_changed", self.__on_state_changed.get_handler())
|
|
71
|
-
|
|
72
|
-
self.audio_encoder = audio_encoder
|
|
73
|
-
self.suppress_noise = suppress_noise
|
|
74
|
-
self.cancel_echo = cancel_echo
|
|
75
|
-
self.auto_gain = auto_gain
|
|
76
|
-
self.channels_num = channels_num
|
|
77
|
-
self.sample_rate = sample_rate
|
|
78
|
-
self.bit_rate = bit_rate
|
|
79
|
-
self.on_state_changed = on_state_changed
|
|
80
|
-
|
|
81
|
-
def _get_control_name(self):
|
|
82
|
-
return "audiorecorder"
|
|
83
|
-
|
|
84
|
-
def start_recording(
|
|
85
|
-
self, output_path: str = None, wait_timeout: Optional[float] = 10
|
|
47
|
+
output_path: Optional[str] = None,
|
|
48
|
+
configuration: Optional[AudioRecorderConfiguration] = None,
|
|
49
|
+
timeout: Optional[float] = 10,
|
|
86
50
|
) -> bool:
|
|
51
|
+
"""
|
|
52
|
+
Starts recording audio and saves it to the specified output path.
|
|
53
|
+
|
|
54
|
+
If not on the web, the `output_path` parameter must be provided.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
output_path: The file path where the audio will be saved.
|
|
58
|
+
It must be specified if not on web.
|
|
59
|
+
configuration: The configuration for the audio recorder.
|
|
60
|
+
If `None`, the `AudioRecorder.configuration` will be used.
|
|
61
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
62
|
+
Returns:
|
|
63
|
+
`True` if recording was successfully started, `False` otherwise.
|
|
64
|
+
Raises:
|
|
65
|
+
TimeoutError: If the request times out.
|
|
66
|
+
"""
|
|
87
67
|
assert (
|
|
88
68
|
self.page.web or output_path
|
|
89
|
-
), "output_path must be provided
|
|
90
|
-
|
|
91
|
-
"start_recording",
|
|
92
|
-
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def is_recording(self, wait_timeout: Optional[float] = 5) -> bool:
|
|
99
|
-
recording = self.invoke_method(
|
|
100
|
-
"is_recording",
|
|
101
|
-
wait_for_result=True,
|
|
102
|
-
wait_timeout=wait_timeout,
|
|
103
|
-
)
|
|
104
|
-
return recording == "true"
|
|
105
|
-
|
|
106
|
-
async def is_recording_async(self, wait_timeout: Optional[float] = 5) -> bool:
|
|
107
|
-
recording = await self.invoke_method_async(
|
|
108
|
-
"is_recording",
|
|
109
|
-
wait_for_result=True,
|
|
110
|
-
wait_timeout=wait_timeout,
|
|
111
|
-
)
|
|
112
|
-
return recording == "true"
|
|
113
|
-
|
|
114
|
-
def stop_recording(self, wait_timeout: Optional[float] = 5) -> Optional[str]:
|
|
115
|
-
return self.invoke_method(
|
|
116
|
-
"stop_recording",
|
|
117
|
-
wait_for_result=True,
|
|
118
|
-
wait_timeout=wait_timeout,
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
async def stop_recording_async(
|
|
122
|
-
self, wait_timeout: Optional[float] = 10
|
|
123
|
-
) -> Optional[str]:
|
|
124
|
-
return await self.invoke_method_async(
|
|
125
|
-
"stop_recording",
|
|
126
|
-
wait_for_result=True,
|
|
127
|
-
wait_timeout=wait_timeout,
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
def cancel_recording(self, wait_timeout: Optional[float] = 5) -> None:
|
|
131
|
-
self.invoke_method(
|
|
132
|
-
"cancel_recording",
|
|
133
|
-
wait_for_result=True,
|
|
134
|
-
wait_timeout=wait_timeout,
|
|
135
|
-
)
|
|
136
|
-
|
|
137
|
-
def resume_recording(self):
|
|
138
|
-
self.invoke_method("resume_recording")
|
|
139
|
-
|
|
140
|
-
def pause_recording(self):
|
|
141
|
-
self.invoke_method("pause_recording")
|
|
142
|
-
|
|
143
|
-
def is_paused(self, wait_timeout: Optional[float] = 5) -> bool:
|
|
144
|
-
paused = self.invoke_method(
|
|
145
|
-
"is_paused",
|
|
146
|
-
wait_for_result=True,
|
|
147
|
-
wait_timeout=wait_timeout,
|
|
148
|
-
)
|
|
149
|
-
return paused == "true"
|
|
150
|
-
|
|
151
|
-
async def is_paused_async(self, wait_timeout: Optional[float] = 5) -> bool:
|
|
152
|
-
supported = await self.invoke_method_async(
|
|
153
|
-
"is_paused",
|
|
154
|
-
wait_for_result=True,
|
|
155
|
-
wait_timeout=wait_timeout,
|
|
156
|
-
)
|
|
157
|
-
return supported == "true"
|
|
158
|
-
|
|
159
|
-
def is_supported_encoder(
|
|
160
|
-
self, encoder: AudioEncoder, wait_timeout: Optional[float] = 5
|
|
161
|
-
) -> bool:
|
|
162
|
-
supported = self.invoke_method(
|
|
163
|
-
"is_supported_encoder",
|
|
164
|
-
{
|
|
165
|
-
"encoder": (
|
|
166
|
-
encoder.value if isinstance(encoder, AudioEncoder) else encoder
|
|
167
|
-
)
|
|
69
|
+
), "output_path must be provided on platforms other than web"
|
|
70
|
+
return await self._invoke_method_async(
|
|
71
|
+
method_name="start_recording",
|
|
72
|
+
arguments={
|
|
73
|
+
"output_path": output_path,
|
|
74
|
+
"configuration": configuration
|
|
75
|
+
if configuration is not None
|
|
76
|
+
else self.configuration,
|
|
168
77
|
},
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
def
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
):
|
|
294
|
-
|
|
78
|
+
timeout=timeout,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
async def is_recording_async(self, timeout: Optional[float] = 10) -> bool:
|
|
82
|
+
"""
|
|
83
|
+
Checks whether the audio recorder is currently recording.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
87
|
+
Returns:
|
|
88
|
+
`True` if the recorder is currently recording, `False` otherwise.
|
|
89
|
+
Raises:
|
|
90
|
+
TimeoutError: If the request times out.
|
|
91
|
+
"""
|
|
92
|
+
return await self._invoke_method_async("is_recording", timeout=timeout)
|
|
93
|
+
|
|
94
|
+
async def stop_recording_async(self, timeout: Optional[float] = 10) -> Optional[str]:
|
|
95
|
+
"""
|
|
96
|
+
Stops the audio recording and optionally returns the path to the saved file.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
100
|
+
Returns:
|
|
101
|
+
The file path where the audio was saved or `None` if not applicable.
|
|
102
|
+
Raises:
|
|
103
|
+
TimeoutError: If the request times out.
|
|
104
|
+
"""
|
|
105
|
+
return await self._invoke_method_async("stop_recording", timeout=timeout)
|
|
106
|
+
|
|
107
|
+
async def cancel_recording_async(self, timeout: Optional[float] = 10):
|
|
108
|
+
"""
|
|
109
|
+
Cancels the current audio recording.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
113
|
+
Raises:
|
|
114
|
+
TimeoutError: If the request times out.
|
|
115
|
+
"""
|
|
116
|
+
await self._invoke_method_async("cancel_recording", timeout=timeout)
|
|
117
|
+
|
|
118
|
+
def cancel_recording(self, timeout: Optional[float] = 10):
|
|
119
|
+
"""
|
|
120
|
+
Cancels the current audio recording.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
124
|
+
Raises:
|
|
125
|
+
TimeoutError: If the request times out.
|
|
126
|
+
"""
|
|
127
|
+
asyncio.create_task(self.cancel_recording_async(timeout=timeout))
|
|
128
|
+
|
|
129
|
+
async def resume_recording_async(self, timeout: Optional[float] = 10):
|
|
130
|
+
"""
|
|
131
|
+
Resumes a paused audio recording.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
135
|
+
Raises:
|
|
136
|
+
TimeoutError: If the request times out.
|
|
137
|
+
"""
|
|
138
|
+
await self._invoke_method_async("resume_recording", timeout=timeout)
|
|
139
|
+
|
|
140
|
+
def resume_recording(self, timeout: Optional[float] = 10):
|
|
141
|
+
"""
|
|
142
|
+
Resumes a paused audio recording.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
146
|
+
Raises:
|
|
147
|
+
TimeoutError: If the request times out.
|
|
148
|
+
"""
|
|
149
|
+
asyncio.create_task(self.resume_recording_async(timeout=timeout))
|
|
150
|
+
|
|
151
|
+
async def pause_recording_async(self, timeout: Optional[float] = 10):
|
|
152
|
+
"""
|
|
153
|
+
Pauses the ongoing audio recording.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
157
|
+
Raises:
|
|
158
|
+
TimeoutError: If the request times out.
|
|
159
|
+
"""
|
|
160
|
+
await self._invoke_method_async("pause_recording", timeout=timeout)
|
|
161
|
+
|
|
162
|
+
def pause_recording(self, timeout: Optional[float] = 10):
|
|
163
|
+
"""
|
|
164
|
+
Pauses the ongoing audio recording.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
168
|
+
Raises:
|
|
169
|
+
TimeoutError: If the request times out.
|
|
170
|
+
"""
|
|
171
|
+
asyncio.create_task(self.pause_recording_async(timeout=timeout))
|
|
172
|
+
|
|
173
|
+
async def is_paused_async(self, timeout: Optional[float] = 10) -> bool:
|
|
174
|
+
"""
|
|
175
|
+
Checks whether the audio recorder is currently paused.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
179
|
+
Returns:
|
|
180
|
+
`True` if the recorder is paused, `False` otherwise.
|
|
181
|
+
Raises:
|
|
182
|
+
TimeoutError: If the request times out.
|
|
183
|
+
"""
|
|
184
|
+
return await self._invoke_method_async("is_paused", timeout=timeout)
|
|
185
|
+
|
|
186
|
+
async def is_supported_encoder_async(self, encoder: AudioEncoder, timeout: Optional[float] = 10) -> bool:
|
|
187
|
+
"""
|
|
188
|
+
Checks if the given audio encoder is supported by the recorder.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
encoder: The audio encoder to check.
|
|
192
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
193
|
+
Returns:
|
|
194
|
+
`True` if the encoder is supported, `False` otherwise.
|
|
195
|
+
Raises:
|
|
196
|
+
TimeoutError: If the request times out.
|
|
197
|
+
"""
|
|
198
|
+
return await self._invoke_method_async(
|
|
199
|
+
"is_supported_encoder", {"encoder": encoder}, timeout=timeout
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
async def get_input_devices_async(self, timeout: Optional[float] = 10) -> List[InputDevice]:
|
|
203
|
+
"""
|
|
204
|
+
Retrieves the available input devices for recording.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
208
|
+
Returns:
|
|
209
|
+
A list of available input devices.
|
|
210
|
+
Raises:
|
|
211
|
+
TimeoutError: If the request times out.
|
|
212
|
+
"""
|
|
213
|
+
r = await self._invoke_method_async("get_input_devices", timeout=timeout)
|
|
214
|
+
return [
|
|
215
|
+
InputDevice(id=device_id, label=label) for device_id, label in r.items()
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
async def has_permission_async(self, timeout: Optional[float] = 10) -> bool:
|
|
219
|
+
"""
|
|
220
|
+
Checks if the app has permission to record audio.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
timeout: The maximum amount of time (in seconds) to wait for a response.
|
|
224
|
+
Returns:
|
|
225
|
+
`True` if the app has permission, `False` otherwise.
|
|
226
|
+
Raises:
|
|
227
|
+
TimeoutError: If the request times out.
|
|
228
|
+
"""
|
|
229
|
+
return await self._invoke_method_async("has_permission", timeout=timeout)
|