reachy-mini 1.2.5rc1__py3-none-any.whl → 1.2.11__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.
Files changed (65) hide show
  1. reachy_mini/apps/app.py +24 -21
  2. reachy_mini/apps/manager.py +17 -3
  3. reachy_mini/apps/sources/hf_auth.py +92 -0
  4. reachy_mini/apps/sources/hf_space.py +1 -1
  5. reachy_mini/apps/sources/local_common_venv.py +199 -24
  6. reachy_mini/apps/templates/main.py.j2 +4 -3
  7. reachy_mini/daemon/app/dashboard/static/js/apps.js +9 -1
  8. reachy_mini/daemon/app/dashboard/static/js/appstore.js +228 -0
  9. reachy_mini/daemon/app/dashboard/static/js/logs.js +148 -0
  10. reachy_mini/daemon/app/dashboard/templates/logs.html +37 -0
  11. reachy_mini/daemon/app/dashboard/templates/sections/appstore.html +92 -0
  12. reachy_mini/daemon/app/dashboard/templates/sections/cache.html +82 -0
  13. reachy_mini/daemon/app/dashboard/templates/sections/daemon.html +5 -0
  14. reachy_mini/daemon/app/dashboard/templates/settings.html +1 -0
  15. reachy_mini/daemon/app/main.py +172 -7
  16. reachy_mini/daemon/app/models.py +8 -0
  17. reachy_mini/daemon/app/routers/apps.py +56 -0
  18. reachy_mini/daemon/app/routers/cache.py +58 -0
  19. reachy_mini/daemon/app/routers/hf_auth.py +57 -0
  20. reachy_mini/daemon/app/routers/logs.py +124 -0
  21. reachy_mini/daemon/app/routers/state.py +25 -1
  22. reachy_mini/daemon/app/routers/wifi_config.py +75 -0
  23. reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py +1 -1
  24. reachy_mini/daemon/app/services/bluetooth/commands/WIFI_RESET.sh +8 -0
  25. reachy_mini/daemon/app/services/wireless/launcher.sh +8 -2
  26. reachy_mini/daemon/app/services/wireless/reachy-mini-daemon.service +13 -0
  27. reachy_mini/daemon/backend/abstract.py +29 -9
  28. reachy_mini/daemon/backend/mockup_sim/__init__.py +12 -0
  29. reachy_mini/daemon/backend/mockup_sim/backend.py +176 -0
  30. reachy_mini/daemon/backend/mujoco/backend.py +0 -5
  31. reachy_mini/daemon/backend/robot/backend.py +78 -5
  32. reachy_mini/daemon/daemon.py +46 -7
  33. reachy_mini/daemon/utils.py +71 -15
  34. reachy_mini/io/zenoh_client.py +26 -0
  35. reachy_mini/io/zenoh_server.py +10 -6
  36. reachy_mini/kinematics/nn_kinematics.py +2 -2
  37. reachy_mini/kinematics/placo_kinematics.py +15 -15
  38. reachy_mini/media/__init__.py +55 -1
  39. reachy_mini/media/audio_base.py +185 -13
  40. reachy_mini/media/audio_control_utils.py +60 -5
  41. reachy_mini/media/audio_gstreamer.py +97 -16
  42. reachy_mini/media/audio_sounddevice.py +120 -19
  43. reachy_mini/media/audio_utils.py +110 -5
  44. reachy_mini/media/camera_base.py +182 -11
  45. reachy_mini/media/camera_constants.py +132 -4
  46. reachy_mini/media/camera_gstreamer.py +42 -2
  47. reachy_mini/media/camera_opencv.py +83 -5
  48. reachy_mini/media/camera_utils.py +95 -7
  49. reachy_mini/media/media_manager.py +139 -6
  50. reachy_mini/media/webrtc_client_gstreamer.py +142 -13
  51. reachy_mini/media/webrtc_daemon.py +72 -7
  52. reachy_mini/motion/recorded_move.py +76 -2
  53. reachy_mini/reachy_mini.py +196 -40
  54. reachy_mini/tools/reflash_motors.py +1 -1
  55. reachy_mini/tools/scan_motors.py +86 -0
  56. reachy_mini/tools/setup_motor.py +49 -31
  57. reachy_mini/utils/interpolation.py +1 -1
  58. reachy_mini/utils/wireless_version/startup_check.py +278 -21
  59. reachy_mini/utils/wireless_version/update.py +44 -1
  60. {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/METADATA +7 -6
  61. {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/RECORD +65 -53
  62. {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/WHEEL +0 -0
  63. {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/entry_points.txt +0 -0
  64. {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/licenses/LICENSE +0 -0
  65. {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,15 @@
1
1
  """Base classes for audio implementations.
2
2
 
3
3
  The audio implementations support various backends and provide a unified
4
- interface for audio input/output.
4
+ interface for audio input/output. This module defines the abstract base class
5
+ that all audio implementations should inherit from, ensuring consistent
6
+ API across different audio backends.
7
+
8
+ Available backends include:
9
+ - SoundDevice: Cross-platform audio backend using sounddevice library
10
+ - GStreamer: GStreamer-based audio backend for advanced audio processing
11
+ - WebRTC: WebRTC-based audio for real-time communication
12
+
5
13
  """
6
14
 
7
15
  import logging
@@ -15,13 +23,36 @@ from reachy_mini.media.audio_control_utils import ReSpeaker, init_respeaker_usb
15
23
 
16
24
 
17
25
  class AudioBase(ABC):
18
- """Abstract class for opening and managing audio devices."""
26
+ """Abstract class for opening and managing audio devices.
27
+
28
+ This class defines the interface that all audio implementations must follow.
29
+ It provides common audio parameters and methods for managing audio devices,
30
+ including microphone input and speaker output functionality.
31
+
32
+ Attributes:
33
+ SAMPLE_RATE (int): Default sample rate for audio operations (16000 Hz).
34
+ CHANNELS (int): Default number of audio channels (2 for stereo).
35
+ logger (logging.Logger): Logger instance for audio-related messages.
36
+ _respeaker (Optional[ReSpeaker]): ReSpeaker microphone array device handler.
37
+
38
+ """
19
39
 
20
40
  SAMPLE_RATE = 16000 # respeaker samplerate
21
41
  CHANNELS = 2 # respeaker channels
22
42
 
23
43
  def __init__(self, log_level: str = "INFO") -> None:
24
- """Initialize the audio device."""
44
+ """Initialize the audio device.
45
+
46
+ Args:
47
+ log_level (str): Logging level for audio operations.
48
+ Options: 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'.
49
+ Default: 'INFO'.
50
+
51
+ Note:
52
+ This constructor initializes the logging system and attempts to detect
53
+ and initialize the ReSpeaker microphone array if available.
54
+
55
+ """
25
56
  self.logger = logging.getLogger(__name__)
26
57
  self.logger.setLevel(log_level)
27
58
  self._respeaker: Optional[ReSpeaker] = init_respeaker_usb()
@@ -33,48 +64,179 @@ class AudioBase(ABC):
33
64
 
34
65
  @abstractmethod
35
66
  def start_recording(self) -> None:
36
- """Start recording audio."""
67
+ """Start recording audio.
68
+
69
+ This method should initialize the audio recording system and prepare
70
+ it to capture audio data. After calling this method, get_audio_sample()
71
+ should be able to retrieve recorded audio data.
72
+
73
+ Note:
74
+ Implementations should handle any necessary resource allocation and
75
+ error checking. If recording cannot be started, implementations should
76
+ log appropriate error messages.
77
+
78
+ Raises:
79
+ RuntimeError: If audio recording cannot be started due to hardware
80
+ or configuration issues.
81
+
82
+ """
37
83
  pass
38
84
 
39
85
  @abstractmethod
40
86
  def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]:
41
- """Read audio data from the device. Returns the data or None if error."""
87
+ """Read audio data from the device. Returns the data or None if error.
88
+
89
+ Returns:
90
+ Optional[npt.NDArray[np.float32]]: A numpy array containing audio samples
91
+ in float32 format, or None if no data is available or an error occurred.
92
+
93
+ The array shape is typically (num_samples,) for mono or
94
+ (num_samples, num_channels) for multi-channel audio.
95
+
96
+ Note:
97
+ This method should be called after start_recording() has been called.
98
+ The sample rate and number of channels can be obtained via
99
+ get_input_audio_samplerate() and get_input_channels() respectively.
100
+
101
+ Example:
102
+ >>> audio.start_recording()
103
+ >>> samples = audio.get_audio_sample()
104
+ >>> if samples is not None:
105
+ ... print(f"Got {len(samples)} audio samples")
106
+
107
+ """
42
108
  pass
43
109
 
44
110
  def get_input_audio_samplerate(self) -> int:
45
- """Get the input samplerate of the audio device."""
111
+ """Get the input samplerate of the audio device.
112
+
113
+ Returns:
114
+ int: The sample rate in Hz at which audio is being captured.
115
+ Default is 16000 Hz.
116
+
117
+ Note:
118
+ This value represents the number of audio samples captured per second
119
+ for each channel.
120
+
121
+ """
46
122
  return self.SAMPLE_RATE
47
123
 
48
124
  def get_output_audio_samplerate(self) -> int:
49
- """Get the outputsamplerate of the audio device."""
125
+ """Get the output samplerate of the audio device.
126
+
127
+ Returns:
128
+ int: The sample rate in Hz at which audio is being played back.
129
+ Default is 16000 Hz.
130
+
131
+ Note:
132
+ This value represents the number of audio samples played per second
133
+ for each channel.
134
+
135
+ """
50
136
  return self.SAMPLE_RATE
51
137
 
52
138
  def get_input_channels(self) -> int:
53
- """Get the number of input channels of the audio device."""
139
+ """Get the number of input channels of the audio device.
140
+
141
+ Returns:
142
+ int: The number of audio input channels (e.g., 1 for mono, 2 for stereo).
143
+ Default is 2 channels.
144
+
145
+ Note:
146
+ For the ReSpeaker microphone array, this typically returns 2 channels
147
+ representing the stereo microphone configuration.
148
+
149
+ """
54
150
  return self.CHANNELS
55
151
 
56
152
  def get_output_channels(self) -> int:
57
- """Get the number of output channels of the audio device."""
153
+ """Get the number of output channels of the audio device.
154
+
155
+ Returns:
156
+ int: The number of audio output channels (e.g., 1 for mono, 2 for stereo).
157
+ Default is 2 channels.
158
+
159
+ Note:
160
+ This determines how audio data should be formatted when passed to
161
+ push_audio_sample() method.
162
+
163
+ """
58
164
  return self.CHANNELS
59
165
 
60
166
  @abstractmethod
61
167
  def stop_recording(self) -> None:
62
- """Close the audio device and release resources."""
168
+ """Close the audio device and release resources.
169
+
170
+ This method should stop any ongoing audio recording and release
171
+ all associated resources. After calling this method, get_audio_sample()
172
+ should return None until start_recording() is called again.
173
+
174
+ Note:
175
+ Implementations should ensure proper cleanup to prevent resource leaks.
176
+
177
+ """
63
178
  pass
64
179
 
65
180
  @abstractmethod
66
181
  def start_playing(self) -> None:
67
- """Start playing audio."""
182
+ """Start playing audio.
183
+
184
+ This method should initialize the audio playback system and prepare
185
+ it to receive audio data via push_audio_sample().
186
+
187
+ Note:
188
+ Implementations should handle any necessary resource allocation and
189
+ error checking. If playback cannot be started, implementations should
190
+ log appropriate error messages.
191
+
192
+ Raises:
193
+ RuntimeError: If audio playback cannot be started due to hardware
194
+ or configuration issues.
195
+
196
+ """
197
+ pass
198
+
199
+ @abstractmethod
200
+ def set_max_output_buffers(self, max_buffers: int) -> None:
201
+ """Set the maximum number of output buffers to queue in the player.
202
+
203
+ Args:
204
+ max_buffers (int): Maximum number of buffers to queue.
205
+
206
+ """
68
207
  pass
69
208
 
70
209
  @abstractmethod
71
210
  def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None:
72
- """Push audio data to the output device."""
211
+ """Push audio data to the output device.
212
+
213
+ Args:
214
+ data (npt.NDArray[np.float32]): Audio samples to be played.
215
+ The array should contain float32 values typically in the range [-1.0, 1.0].
216
+
217
+ For mono audio: shape should be (num_samples,)
218
+ For stereo audio: shape should be (num_samples, 2)
219
+
220
+ Note:
221
+ This method should be called after start_playing() has been called.
222
+ The audio data will be played at the sample rate returned by
223
+ get_output_audio_samplerate().
224
+
225
+ """
73
226
  pass
74
227
 
75
228
  @abstractmethod
76
229
  def stop_playing(self) -> None:
77
- """Stop playing audio and release resources."""
230
+ """Stop playing audio and release resources.
231
+
232
+ This method should stop any ongoing audio playback and release
233
+ all associated resources. After calling this method, push_audio_sample()
234
+ calls will have no effect until start_playing() is called again.
235
+
236
+ Note:
237
+ Implementations should ensure proper cleanup to prevent resource leaks.
238
+
239
+ """
78
240
  pass
79
241
 
80
242
  @abstractmethod
@@ -83,6 +245,16 @@ class AudioBase(ABC):
83
245
 
84
246
  Args:
85
247
  sound_file (str): Path to the sound file to play.
248
+ Supported formats depend on the specific implementation.
249
+
250
+ Note:
251
+ This is a convenience method that handles the complete playback
252
+ of a sound file from start to finish. For more control over
253
+ audio playback, use start_playing(), push_audio_sample(),
254
+ and stop_playing() methods.
255
+
256
+ Example:
257
+ >>> audio.play_sound("/path/to/sound.wav")
86
258
 
87
259
  """
88
260
  pass
@@ -1,15 +1,15 @@
1
- """Allows tuning of the XMOS XVF3800 chip.
1
+ """Allows tuning of the XMOS XVF3800 chip integrated in the Reachy Mini Audio card.
2
2
 
3
3
  Example usage:
4
4
 
5
5
  # Read a parameter
6
- python reachy_host.py AUDIO_MGR_OP_L
6
+ python audio_control_utils.py AUDIO_MGR_OP_L
7
7
  # Output:
8
8
  # ReadCMD: cmdid: 143, resid: 35, response: array('B', [0, 8, 0])
9
9
  # AUDIO_MGR_OP_L: [0, 8, 0]
10
10
 
11
11
  # Write a parameter
12
- python reachy_host.py AUDIO_MGR_OP_L --values 3 0
12
+ python audio_control_utils.py AUDIO_MGR_OP_L --values 3 0
13
13
  # Output:
14
14
  # Writing to AUDIO_MGR_OP_L with values: [3, 0]
15
15
  # WriteCMD: cmdid: 15, resid: 35, payload: [3, 0]
@@ -320,7 +320,34 @@ class ReSpeaker:
320
320
 
321
321
 
322
322
  def find(vid: int = 0x2886, pid: int = 0x001A) -> ReSpeaker | None:
323
- """Find and return the ReSpeaker USB device with the given Vendor ID and Product ID."""
323
+ """Find and return the ReSpeaker USB device with the given Vendor ID and Product ID.
324
+
325
+ Args:
326
+ vid (int): USB Vendor ID to search for. Default: 0x2886 (XMOS).
327
+ pid (int): USB Product ID to search for. Default: 0x001A (XMOS XVF3800).
328
+
329
+ Returns:
330
+ ReSpeaker | None: A ReSpeaker object if the device is found,
331
+ None otherwise.
332
+
333
+ Note:
334
+ This function searches for USB devices with the specified Vendor ID
335
+ and Product ID using libusb backend. The default values target
336
+ XMOS XVF3800 devices used in ReSpeaker microphone arrays.
337
+
338
+ Example:
339
+ >>> from reachy_mini.media.audio_control_utils import find
340
+ >>>
341
+ >>> # Find default ReSpeaker device
342
+ >>> respeaker = find()
343
+ >>> if respeaker is not None:
344
+ ... print("Found ReSpeaker device")
345
+ ... respeaker.close()
346
+ >>>
347
+ >>> # Find specific device
348
+ >>> custom_device = find(vid=0x1234, pid=0x5678)
349
+
350
+ """
324
351
  dev = usb.core.find(idVendor=vid, idProduct=pid, backend=get_libusb1_backend())
325
352
  if not dev:
326
353
  return None
@@ -329,7 +356,35 @@ def find(vid: int = 0x2886, pid: int = 0x001A) -> ReSpeaker | None:
329
356
 
330
357
 
331
358
  def init_respeaker_usb() -> Optional[ReSpeaker]:
332
- """Initialize the ReSpeaker USB device. Looks for both new and beta device IDs."""
359
+ """Initialize the ReSpeaker USB device. Looks for both new and beta device IDs.
360
+
361
+ Returns:
362
+ Optional[ReSpeaker]: A ReSpeaker object if a compatible device is found,
363
+ None otherwise.
364
+
365
+ Note:
366
+ This function attempts to initialize a ReSpeaker microphone array by
367
+ searching for USB devices with known Vendor and Product IDs. It tries:
368
+ 1. New Reachy Mini Audio firmware (0x38FB:0x1001) - preferred
369
+ 2. Old ReSpeaker firmware (0x2886:0x001A) - with warning to update
370
+
371
+ The function handles USB backend errors gracefully and returns
372
+ None if no compatible device is found or if initialization fails.
373
+
374
+ Example:
375
+ >>> from reachy_mini.media.audio_control_utils import init_respeaker_usb
376
+ >>>
377
+ >>> # Initialize ReSpeaker device
378
+ >>> respeaker = init_respeaker_usb()
379
+ >>> if respeaker is not None:
380
+ ... print("ReSpeaker initialized successfully")
381
+ ... # Use the device...
382
+ ... doa = respeaker.read("DOA_VALUE_RADIANS")
383
+ ... respeaker.close()
384
+ ... else:
385
+ ... print("No ReSpeaker device found")
386
+
387
+ """
333
388
  try:
334
389
  # Try new firmware first
335
390
  dev = usb.core.find(
@@ -1,7 +1,45 @@
1
- """GStreamer camera backend.
1
+ """GStreamer audio backend.
2
+
3
+ This module provides an implementation of the AudioBase class using GStreamer.
4
+ It offers advanced audio processing capabilities including microphone input,
5
+ speaker output, and integration with the ReSpeaker microphone array for
6
+ Direction of Arrival (DoA) estimation.
7
+
8
+ The GStreamer audio backend supports:
9
+ - High-quality audio capture and playback
10
+ - ReSpeaker microphone array integration
11
+ - Direction of Arrival (DoA) estimation
12
+ - Advanced audio processing pipelines
13
+ - Multiple audio formats and sample rates
14
+
15
+ Note:
16
+ This class is typically used internally by the MediaManager when the GSTREAMER
17
+ backend is selected. Direct usage is possible but usually not necessary.
18
+
19
+ Example usage via MediaManager:
20
+ >>> from reachy_mini.media.media_manager import MediaManager, MediaBackend
21
+ >>>
22
+ >>> # Create media manager with GStreamer backend
23
+ >>> media = MediaManager(backend=MediaBackend.GSTREAMER, log_level="INFO")
24
+ >>>
25
+ >>> # Start audio recording
26
+ >>> media.start_recording()
27
+ >>>
28
+ >>> # Get audio samples
29
+ >>> samples = media.get_audio_sample()
30
+ >>> if samples is not None:
31
+ ... print(f"Captured {len(samples)} audio samples")
32
+ >>>
33
+ >>> # Get Direction of Arrival
34
+ >>> doa = media.get_DoA()
35
+ >>> if doa is not None:
36
+ ... angle, speech_detected = doa
37
+ ... print(f"Sound direction: {angle} radians, speech detected: {speech_detected}")
38
+ >>>
39
+ >>> # Clean up
40
+ >>> media.stop_recording()
41
+ >>> media.close()
2
42
 
3
- This module provides an implementation of the CameraBase class using GStreamer.
4
- By default the module directly returns JPEG images as output by the camera.
5
43
  """
6
44
 
7
45
  import os
@@ -108,6 +146,21 @@ class GStreamerAudio(AudioBase):
108
146
  self._bus_record.remove_watch()
109
147
  self._bus_playback.remove_watch()
110
148
 
149
+ def set_max_output_buffers(self, max_buffers: int) -> None:
150
+ """Set the maximum number of output buffers to queue in the player.
151
+
152
+ Args:
153
+ max_buffers (int): Maximum number of buffers to queue.
154
+
155
+ """
156
+ if self._appsrc is not None:
157
+ self._appsrc.set_property("max-buffers", max_buffers)
158
+ self._appsrc.set_property("leaky-type", 2) # drop old buffers
159
+ else:
160
+ self.logger.warning(
161
+ "AppSrc is not initialized. Call start_playing() first."
162
+ )
163
+
111
164
  def _init_pipeline_playback(self, pipeline: Gst.Pipeline) -> None:
112
165
  self._appsrc = Gst.ElementFactory.make("appsrc")
113
166
  self._appsrc.set_property("format", Gst.Format.TIME)
@@ -120,7 +173,6 @@ class GStreamerAudio(AudioBase):
120
173
  audioconvert = Gst.ElementFactory.make("audioconvert")
121
174
  audioresample = Gst.ElementFactory.make("audioresample")
122
175
 
123
- queue = Gst.ElementFactory.make("queue")
124
176
  audiosink: Optional[Gst.Element] = None
125
177
  if self._id_audio_card == -1:
126
178
  audiosink = Gst.ElementFactory.make("autoaudiosink") # use default speaker
@@ -132,14 +184,12 @@ class GStreamerAudio(AudioBase):
132
184
  audiosink = Gst.ElementFactory.make("alsasink")
133
185
  audiosink.set_property("device", f"hw:{self._id_audio_card},0")
134
186
 
135
- pipeline.add(queue)
136
187
  pipeline.add(audiosink)
137
188
  pipeline.add(self._appsrc)
138
189
  pipeline.add(audioconvert)
139
190
  pipeline.add(audioresample)
140
191
 
141
- self._appsrc.link(queue)
142
- queue.link(audioconvert)
192
+ self._appsrc.link(audioconvert)
143
193
  audioconvert.link(audioresample)
144
194
  audioresample.link(audiosink)
145
195
 
@@ -157,7 +207,10 @@ class GStreamerAudio(AudioBase):
157
207
  return True
158
208
 
159
209
  def start_recording(self) -> None:
160
- """Open the audio card using GStreamer."""
210
+ """Open the audio card using GStreamer.
211
+
212
+ See AudioBase.start_recording() for complete documentation.
213
+ """
161
214
  self._pipeline_record.set_state(Gst.State.PLAYING)
162
215
 
163
216
  def _get_sample(self, appsink: GstApp.AppSink) -> Optional[bytes]:
@@ -176,6 +229,8 @@ class GStreamerAudio(AudioBase):
176
229
  def get_audio_sample(self) -> Optional[npt.NDArray[np.float32]]:
177
230
  """Read a sample from the audio card. Returns the sample or None if error.
178
231
 
232
+ See AudioBase.get_audio_sample() for complete documentation.
233
+
179
234
  Returns:
180
235
  Optional[npt.NDArray[np.float32]]: The captured sample in raw format, or None if error.
181
236
 
@@ -186,35 +241,59 @@ class GStreamerAudio(AudioBase):
186
241
  return np.frombuffer(sample, dtype=np.float32).reshape(-1, 2)
187
242
 
188
243
  def get_input_audio_samplerate(self) -> int:
189
- """Get the input samplerate of the audio device."""
244
+ """Get the input samplerate of the audio device.
245
+
246
+ See AudioBase.get_input_audio_samplerate() for complete documentation.
247
+ """
190
248
  return self.SAMPLE_RATE
191
249
 
192
250
  def get_output_audio_samplerate(self) -> int:
193
- """Get the output samplerate of the audio device."""
251
+ """Get the output samplerate of the audio device.
252
+
253
+ See AudioBase.get_output_audio_samplerate() for complete documentation.
254
+ """
194
255
  return self.SAMPLE_RATE
195
256
 
196
257
  def get_input_channels(self) -> int:
197
- """Get the number of input channels of the audio device."""
258
+ """Get the number of input channels of the audio device.
259
+
260
+ See AudioBase.get_input_channels() for complete documentation.
261
+ """
198
262
  return self.CHANNELS
199
263
 
200
264
  def get_output_channels(self) -> int:
201
- """Get the number of output channels of the audio device."""
265
+ """Get the number of output channels of the audio device.
266
+
267
+ See AudioBase.get_output_channels() for complete documentation.
268
+ """
202
269
  return self.CHANNELS
203
270
 
204
271
  def stop_recording(self) -> None:
205
- """Release the camera resource."""
272
+ """Release the camera resource.
273
+
274
+ See AudioBase.stop_recording() for complete documentation.
275
+ """
206
276
  self._pipeline_record.set_state(Gst.State.NULL)
207
277
 
208
278
  def start_playing(self) -> None:
209
- """Open the audio output using GStreamer."""
279
+ """Open the audio output using GStreamer.
280
+
281
+ See AudioBase.start_playing() for complete documentation.
282
+ """
210
283
  self._pipeline_playback.set_state(Gst.State.PLAYING)
211
284
 
212
285
  def stop_playing(self) -> None:
213
- """Stop playing audio and release resources."""
286
+ """Stop playing audio and release resources.
287
+
288
+ See AudioBase.stop_playing() for complete documentation.
289
+ """
214
290
  self._pipeline_playback.set_state(Gst.State.NULL)
215
291
 
216
292
  def push_audio_sample(self, data: npt.NDArray[np.float32]) -> None:
217
- """Push audio data to the output device."""
293
+ """Push audio data to the output device.
294
+
295
+ See AudioBase.push_audio_sample() for complete documentation.
296
+ """
218
297
  if self._appsrc is not None:
219
298
  buf = Gst.Buffer.new_wrapped(data.tobytes())
220
299
  self._appsrc.push_buffer(buf)
@@ -226,6 +305,8 @@ class GStreamerAudio(AudioBase):
226
305
  def play_sound(self, sound_file: str) -> None:
227
306
  """Play a sound file.
228
307
 
308
+ See AudioBase.play_sound() for complete documentation.
309
+
229
310
  Todo: for now this function is mean to be used on the wireless version.
230
311
 
231
312
  Args: