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.

@@ -1,6 +1,12 @@
1
- from flet_audio_recorder.audio_recorder import (
1
+ from .audio_recorder import AudioRecorder
2
+ from .types import (
3
+ AndroidAudioSource,
4
+ AndroidRecorderConfiguration,
2
5
  AudioEncoder,
3
- AudioRecorder,
6
+ AudioRecorderConfiguration,
4
7
  AudioRecorderState,
5
8
  AudioRecorderStateChangeEvent,
9
+ InputDevice,
10
+ IosAudioCategoryOption,
11
+ IosRecorderConfiguration,
6
12
  )
@@ -1,294 +1,229 @@
1
- import json
2
- from enum import Enum
3
- from typing import Any, Optional
1
+ import asyncio
2
+ from dataclasses import field
3
+ from typing import List, Optional
4
4
 
5
- from flet.core.control import Control, OptionalNumber
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
- class AudioRecorderState(Enum):
14
- STOPPED = "stopped"
15
- RECORDING = "recording"
16
- PAUSED = "paused"
14
+ __all__ = ["AudioRecorder"]
17
15
 
18
16
 
19
- class AudioRecorderStateChangeEvent(ControlEvent):
20
- def __init__(self, e: ControlEvent):
21
- super().__init__(e.target, e.name, e.data, e.control, e.page)
22
- self.state: AudioRecorderState = AudioRecorderState(e.data)
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
- class AudioRecorder(Control):
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
- Online docs: https://flet.dev/docs/controls/audiorecorder
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 __init__(
45
+ async def start_recording_async(
47
46
  self,
48
- audio_encoder: Optional[AudioEncoder] = None,
49
- suppress_noise: Optional[bool] = None,
50
- cancel_echo: Optional[bool] = None,
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 when not on web"
90
- started = self.invoke_method(
91
- "start_recording",
92
- {"outputPath": output_path},
93
- wait_for_result=True,
94
- wait_timeout=wait_timeout,
95
- )
96
- return started == "true"
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
- wait_for_result=True,
170
- wait_timeout=wait_timeout,
171
- )
172
- return supported == "true"
173
-
174
- async def is_supported_encoder_async(
175
- self, encoder: AudioEncoder, wait_timeout: Optional[float] = 5
176
- ) -> bool:
177
- supported = await self.invoke_method_async(
178
- "is_supported_encoder",
179
- {
180
- "encoder": (
181
- encoder.value if isinstance(encoder, AudioEncoder) else encoder
182
- )
183
- },
184
- wait_for_result=True,
185
- wait_timeout=wait_timeout,
186
- )
187
- return supported == "true"
188
-
189
- def get_input_devices(self, wait_timeout: Optional[float] = 5) -> dict:
190
- devices = self.invoke_method(
191
- "get_input_devices",
192
- wait_for_result=True,
193
- wait_timeout=wait_timeout,
194
- )
195
- return json.loads(devices)
196
-
197
- async def get_input_devices_async(self, wait_timeout: Optional[float] = 5) -> dict:
198
- devices = await self.invoke_method_async(
199
- "get_input_devices",
200
- wait_for_result=True,
201
- wait_timeout=wait_timeout,
202
- )
203
- return json.loads(devices)
204
-
205
- def has_permission(self, wait_timeout: Optional[float] = 10) -> bool:
206
- p = self.invoke_method(
207
- "has_permission",
208
- wait_for_result=True,
209
- wait_timeout=wait_timeout,
210
- )
211
- return p == "true"
212
-
213
- async def has_permission_async(self, wait_timeout: Optional[float] = 10) -> bool:
214
- p = await self.invoke_method_async(
215
- "has_permission",
216
- wait_for_result=True,
217
- wait_timeout=wait_timeout,
218
- )
219
- return p == "true"
220
-
221
- # audio_encoder
222
- @property
223
- def audio_encoder(self):
224
- return self._get_attr("audioEncoder")
225
-
226
- @audio_encoder.setter
227
- def audio_encoder(self, value: Optional[AudioEncoder]):
228
- self._set_enum_attr("audioEncoder", value, AudioEncoder)
229
-
230
- # suppress_noise
231
- @property
232
- def suppress_noise(self) -> bool:
233
- return self._get_attr("suppressNoise", data_type="bool", def_value=False)
234
-
235
- @suppress_noise.setter
236
- def suppress_noise(self, value: Optional[bool]):
237
- self._set_attr("suppressNoise", value)
238
-
239
- # cancel_echo
240
- @property
241
- def cancel_echo(self) -> bool:
242
- return self._get_attr("cancelEcho", data_type="bool", def_value=False)
243
-
244
- @cancel_echo.setter
245
- def cancel_echo(self, value: Optional[bool]):
246
- self._set_attr("cancelEcho", value)
247
-
248
- # auto_gain
249
- @property
250
- def auto_gain(self) -> bool:
251
- return self._get_attr("autoGain", data_type="bool", def_value=False)
252
-
253
- @auto_gain.setter
254
- def auto_gain(self, value: Optional[bool]):
255
- self._set_attr("autoGain", value)
256
-
257
- # bit_rate
258
- @property
259
- def bit_rate(self) -> OptionalNumber:
260
- return self._get_attr("bitRate")
261
-
262
- @bit_rate.setter
263
- def bit_rate(self, value: OptionalNumber):
264
- self._set_attr("bitRate", value)
265
-
266
- # sample_rate
267
- @property
268
- def sample_rate(self) -> OptionalNumber:
269
- return self._get_attr("sampleRate")
270
-
271
- @sample_rate.setter
272
- def sample_rate(self, value: OptionalNumber):
273
- self._set_attr("sampleRate", value)
274
-
275
- # channels_num
276
- @property
277
- def channels_num(self) -> OptionalNumber:
278
- return self._get_attr("channels")
279
-
280
- @channels_num.setter
281
- def channels_num(self, value: OptionalNumber):
282
- if value is None or value in (1, 2):
283
- self._set_attr("channels", value)
284
-
285
- # on_state_changed
286
- @property
287
- def on_state_changed(self):
288
- return self.__on_state_changed.handler
289
-
290
- @on_state_changed.setter
291
- def on_state_changed(
292
- self, handler: OptionalEventCallable[AudioRecorderStateChangeEvent]
293
- ):
294
- self.__on_state_changed.handler = handler
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)