livekit 1.2.1__py3-none-win_arm64.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 (71) hide show
  1. livekit/rtc/__init__.py +264 -0
  2. livekit/rtc/_ffi_client.py +321 -0
  3. livekit/rtc/_proto/__init__.py +0 -0
  4. livekit/rtc/_proto/audio_frame_pb2.py +159 -0
  5. livekit/rtc/_proto/audio_frame_pb2.pyi +1560 -0
  6. livekit/rtc/_proto/capture_pb2.py +70 -0
  7. livekit/rtc/_proto/capture_pb2.pyi +559 -0
  8. livekit/rtc/_proto/data_stream_pb2.py +171 -0
  9. livekit/rtc/_proto/data_stream_pb2.pyi +1498 -0
  10. livekit/rtc/_proto/data_track_pb2.py +120 -0
  11. livekit/rtc/_proto/data_track_pb2.pyi +1073 -0
  12. livekit/rtc/_proto/e2ee_pb2.py +81 -0
  13. livekit/rtc/_proto/e2ee_pb2.pyi +591 -0
  14. livekit/rtc/_proto/ffi_pb2.py +55 -0
  15. livekit/rtc/_proto/ffi_pb2.pyi +1246 -0
  16. livekit/rtc/_proto/handle_pb2.py +27 -0
  17. livekit/rtc/_proto/handle_pb2.pyi +51 -0
  18. livekit/rtc/_proto/participant_pb2.py +45 -0
  19. livekit/rtc/_proto/participant_pb2.pyi +313 -0
  20. livekit/rtc/_proto/room_pb2.py +311 -0
  21. livekit/rtc/_proto/room_pb2.pyi +3136 -0
  22. livekit/rtc/_proto/rpc_pb2.py +47 -0
  23. livekit/rtc/_proto/rpc_pb2.pyi +261 -0
  24. livekit/rtc/_proto/stats_pb2.py +123 -0
  25. livekit/rtc/_proto/stats_pb2.pyi +1514 -0
  26. livekit/rtc/_proto/track_pb2.py +76 -0
  27. livekit/rtc/_proto/track_pb2.pyi +544 -0
  28. livekit/rtc/_proto/track_publication_pb2.py +39 -0
  29. livekit/rtc/_proto/track_publication_pb2.pyi +145 -0
  30. livekit/rtc/_proto/video_frame_pb2.py +97 -0
  31. livekit/rtc/_proto/video_frame_pb2.pyi +838 -0
  32. livekit/rtc/_utils.py +187 -0
  33. livekit/rtc/apm.py +119 -0
  34. livekit/rtc/audio_filter.py +23 -0
  35. livekit/rtc/audio_frame.py +242 -0
  36. livekit/rtc/audio_mixer.py +247 -0
  37. livekit/rtc/audio_resampler.py +174 -0
  38. livekit/rtc/audio_source.py +191 -0
  39. livekit/rtc/audio_stream.py +354 -0
  40. livekit/rtc/data_stream.py +640 -0
  41. livekit/rtc/data_track.py +296 -0
  42. livekit/rtc/e2ee.py +320 -0
  43. livekit/rtc/encoded_video.py +127 -0
  44. livekit/rtc/event_emitter.py +215 -0
  45. livekit/rtc/frame_processor.py +37 -0
  46. livekit/rtc/jupyter.py +68 -0
  47. livekit/rtc/log.py +3 -0
  48. livekit/rtc/media_devices.py +596 -0
  49. livekit/rtc/participant.py +1171 -0
  50. livekit/rtc/platform_audio.py +426 -0
  51. livekit/rtc/py.typed +0 -0
  52. livekit/rtc/resources/LICENSE.md +4055 -0
  53. livekit/rtc/resources/__init__.py +1 -0
  54. livekit/rtc/resources/jupyter-html/index.html +101 -0
  55. livekit/rtc/resources/livekit_ffi.dll +0 -0
  56. livekit/rtc/resources/livekit_ffi.h +42 -0
  57. livekit/rtc/room.py +1304 -0
  58. livekit/rtc/rpc.py +244 -0
  59. livekit/rtc/synchronizer.py +202 -0
  60. livekit/rtc/track.py +264 -0
  61. livekit/rtc/track_publication.py +145 -0
  62. livekit/rtc/transcription.py +19 -0
  63. livekit/rtc/utils.py +138 -0
  64. livekit/rtc/version.py +1 -0
  65. livekit/rtc/video_frame.py +347 -0
  66. livekit/rtc/video_source.py +74 -0
  67. livekit/rtc/video_stream.py +191 -0
  68. livekit-1.2.1.dist-info/METADATA +80 -0
  69. livekit-1.2.1.dist-info/RECORD +71 -0
  70. livekit-1.2.1.dist-info/WHEEL +5 -0
  71. livekit-1.2.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,426 @@
1
+ # Copyright 2023 LiveKit, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ PlatformAudio - Platform audio device management via WebRTC's ADM
17
+
18
+ PlatformAudio provides access to the platform's audio devices (microphones and
19
+ speakers) via WebRTC's Audio Device Module (ADM). This is the recommended way
20
+ to handle audio in most applications because:
21
+
22
+ - Built-in echo cancellation (AEC), noise suppression (NS), and auto gain control (AGC)
23
+ - Automatic device enumeration and selection
24
+ - Efficient hardware-accelerated audio processing on supported platforms
25
+ - No need for external audio libraries
26
+
27
+ For custom audio processing pipelines where you need direct access to audio frames,
28
+ use the synthetic mode with AudioSource instead. See AudioSource for more details.
29
+
30
+ # Usage
31
+
32
+ ```python
33
+ from livekit import rtc
34
+
35
+ # Create PlatformAudio instance (enables ADM)
36
+ platform_audio = rtc.PlatformAudio()
37
+
38
+ # List available devices
39
+ print("Microphones:")
40
+ for device in platform_audio.recording_devices():
41
+ print(f" [{device.index}] {device.name} (ID: {device.id})")
42
+
43
+ print("Speakers:")
44
+ for device in platform_audio.playout_devices():
45
+ print(f" [{device.index}] {device.name} (ID: {device.id})")
46
+
47
+ # Select specific devices (optional - uses default if not called)
48
+ platform_audio.set_recording_device(mic_device.id)
49
+ platform_audio.set_playout_device(speaker_device.id)
50
+
51
+ # Create audio source for publishing
52
+ audio_source = platform_audio.create_audio_source()
53
+
54
+ # Create and publish track
55
+ track = rtc.LocalAudioTrack.create_audio_track("microphone", audio_source)
56
+ await room.local_participant.publish_track(track)
57
+ ```
58
+
59
+ # Limitations
60
+
61
+ - No direct access to captured audio frames (ADM sends directly to WebRTC)
62
+ - For frame-level processing, use synthetic mode with AudioSource.capture_frame()
63
+ """
64
+
65
+ from __future__ import annotations
66
+
67
+ from dataclasses import dataclass
68
+ from typing import List, Optional
69
+
70
+ from ._ffi_client import FfiHandle, FfiClient
71
+ from ._proto import audio_frame_pb2 as proto_audio_frame
72
+ from ._proto import ffi_pb2 as proto_ffi
73
+
74
+
75
+ class PlatformAudioError(Exception):
76
+ """Exception raised when PlatformAudio operations fail."""
77
+
78
+ pass
79
+
80
+
81
+ @dataclass
82
+ class AudioDeviceInfo:
83
+ """Information about an audio device.
84
+
85
+ Attributes:
86
+ index: Device index (0-based). Note: indices can change when devices are
87
+ added/removed, so prefer using `id` for device selection.
88
+ name: Device name as reported by the operating system.
89
+ id: Platform-specific unique device identifier (GUID). This is stable across
90
+ device additions/removals and should be preferred over index for device
91
+ selection.
92
+ """
93
+
94
+ index: int
95
+ name: str
96
+ id: str
97
+
98
+ @classmethod
99
+ def _from_proto(cls, proto: proto_audio_frame.AudioDeviceInfo) -> "AudioDeviceInfo":
100
+ return cls(index=proto.index, name=proto.name, id=proto.guid)
101
+
102
+
103
+ @dataclass
104
+ class PlatformAudioOptions:
105
+ """Audio processing options for PlatformAudio.
106
+
107
+ These options configure WebRTC's audio processing pipeline when using
108
+ PlatformAudio for microphone capture.
109
+
110
+ Attributes:
111
+ echo_cancellation: Enable acoustic echo cancellation (AEC) to remove
112
+ echo from speaker playback. Default: True.
113
+ noise_suppression: Enable noise suppression to remove background noise.
114
+ Default: True.
115
+ auto_gain_control: Enable automatic gain control to normalize audio levels.
116
+ Default: True.
117
+ prefer_hardware: Prefer hardware audio processing when available.
118
+ - iOS: Uses Voice Processing I/O (VPIO) for low-latency processing
119
+ - Android: Hardware support varies by device
120
+ - Desktop: Generally not available
121
+ Default: True on iOS, False on other platforms.
122
+ """
123
+
124
+ echo_cancellation: bool = True
125
+ noise_suppression: bool = True
126
+ auto_gain_control: bool = True
127
+ prefer_hardware: bool = False
128
+
129
+ def _to_proto(self) -> proto_audio_frame.AudioSourceOptions:
130
+ return proto_audio_frame.AudioSourceOptions(
131
+ echo_cancellation=self.echo_cancellation,
132
+ noise_suppression=self.noise_suppression,
133
+ auto_gain_control=self.auto_gain_control,
134
+ prefer_hardware=self.prefer_hardware,
135
+ )
136
+
137
+
138
+ class PlatformAudioSource:
139
+ """Audio source backed by PlatformAudio (WebRTC ADM).
140
+
141
+ This source captures audio from the selected microphone via the platform's
142
+ Audio Device Module. Unlike AudioSource (synthetic mode), frames are captured
143
+ and sent directly by the ADM - there is no `capture_frame()` method.
144
+
145
+ Use this with LocalAudioTrack.create_audio_track() to publish microphone audio.
146
+
147
+ Note: This class is created via PlatformAudio.create_audio_source() and should
148
+ not be instantiated directly.
149
+
150
+ Resource Management:
151
+ Call `close()` when done to immediately release native resources. If not
152
+ called, resources are released when the object is garbage collected, but
153
+ GC timing is non-deterministic and may cause issues on some platforms
154
+ (especially Windows) where audio device handles must be released promptly.
155
+ """
156
+
157
+ def __init__(self, ffi_handle: FfiHandle, info: proto_audio_frame.AudioSourceInfo):
158
+ self._ffi_handle = ffi_handle
159
+ self._info = info
160
+
161
+ @property
162
+ def _handle(self) -> int:
163
+ """Internal FFI handle for use with LocalAudioTrack.create_audio_track()."""
164
+ return self._ffi_handle.handle
165
+
166
+ def close(self) -> None:
167
+ """Release the native audio source resources.
168
+
169
+ Call this method when you are done using the audio source to immediately
170
+ release the underlying native handle. This is especially important on
171
+ Windows where audio device handles must be released promptly to avoid
172
+ interfering with other audio operations.
173
+
174
+ If `close()` is not called, resources will be released when the object
175
+ is garbage collected. However, Python's garbage collection timing is
176
+ non-deterministic, which can lead to:
177
+ - Audio device contention if creating new audio sources before old ones
178
+ are collected
179
+ - Test failures when running multiple audio tests in sequence
180
+ - Resource leaks in long-running applications that frequently create
181
+ and discard audio sources
182
+
183
+ It is safe to call `close()` multiple times; subsequent calls are no-ops.
184
+ """
185
+ self._ffi_handle.dispose()
186
+
187
+
188
+ class PlatformAudio:
189
+ """Platform audio device management via WebRTC's Audio Device Module (ADM).
190
+
191
+ PlatformAudio provides the recommended way to handle audio capture and playback
192
+ in LiveKit applications. It uses WebRTC's ADM for efficient, hardware-accelerated
193
+ audio processing with built-in echo cancellation, noise suppression, and
194
+ automatic gain control.
195
+
196
+ Key features:
197
+ - Device enumeration: List available microphones and speakers
198
+ - Device selection: Choose specific input/output devices
199
+ - Audio processing: Built-in AEC, NS, and AGC
200
+ - Automatic playout: Received audio is automatically played through speakers
201
+
202
+ Example:
203
+ ```python
204
+ # Create PlatformAudio (keeps ADM alive)
205
+ platform_audio = rtc.PlatformAudio()
206
+
207
+ # Enumerate and select devices
208
+ mics = platform_audio.recording_devices()
209
+ platform_audio.set_recording_device(mics[0].id)
210
+
211
+ # Create source and publish track
212
+ source = platform_audio.create_audio_source()
213
+ track = rtc.LocalAudioTrack.create_audio_track("mic", source)
214
+ await room.local_participant.publish_track(track)
215
+
216
+ # When done, close resources
217
+ source.close()
218
+ platform_audio.close()
219
+ ```
220
+
221
+ Resource Management:
222
+ Call `close()` when done to immediately release native ADM resources.
223
+ If not called, resources are released via garbage collection, but GC
224
+ timing is non-deterministic. On Windows especially, failing to promptly
225
+ release ADM resources can cause audio device contention and interfere
226
+ with subsequent audio operations (including synthetic AudioSource usage).
227
+ """
228
+
229
+ def __init__(self) -> None:
230
+ """Initialize PlatformAudio and enable the Audio Device Module.
231
+
232
+ Raises:
233
+ PlatformAudioError: If ADM initialization fails.
234
+ """
235
+ req = proto_ffi.FfiRequest()
236
+ req.new_platform_audio.SetInParent()
237
+
238
+ resp = FfiClient.instance.request(req)
239
+
240
+ if resp.new_platform_audio.HasField("error"):
241
+ raise PlatformAudioError(
242
+ f"Failed to initialize PlatformAudio: {resp.new_platform_audio.error}"
243
+ )
244
+
245
+ self._info = resp.new_platform_audio.platform_audio.info
246
+ self._ffi_handle = FfiHandle(resp.new_platform_audio.platform_audio.handle.id)
247
+
248
+ def recording_devices(self) -> List[AudioDeviceInfo]:
249
+ """Get available recording devices (microphones).
250
+
251
+ Returns:
252
+ List of AudioDeviceInfo for each available microphone.
253
+
254
+ Raises:
255
+ PlatformAudioError: If device enumeration fails.
256
+ """
257
+ req = proto_ffi.FfiRequest()
258
+ req.get_audio_devices.platform_audio_handle = self._ffi_handle.handle
259
+
260
+ resp = FfiClient.instance.request(req)
261
+
262
+ if resp.get_audio_devices.HasField("error") and resp.get_audio_devices.error:
263
+ raise PlatformAudioError(
264
+ f"Failed to enumerate recording devices: {resp.get_audio_devices.error}"
265
+ )
266
+
267
+ return [AudioDeviceInfo._from_proto(d) for d in resp.get_audio_devices.recording_devices]
268
+
269
+ def playout_devices(self) -> List[AudioDeviceInfo]:
270
+ """Get available playout devices (speakers/headphones).
271
+
272
+ Returns:
273
+ List of AudioDeviceInfo for each available speaker.
274
+
275
+ Raises:
276
+ PlatformAudioError: If device enumeration fails.
277
+ """
278
+ req = proto_ffi.FfiRequest()
279
+ req.get_audio_devices.platform_audio_handle = self._ffi_handle.handle
280
+
281
+ resp = FfiClient.instance.request(req)
282
+
283
+ if resp.get_audio_devices.HasField("error") and resp.get_audio_devices.error:
284
+ raise PlatformAudioError(
285
+ f"Failed to enumerate playout devices: {resp.get_audio_devices.error}"
286
+ )
287
+
288
+ return [AudioDeviceInfo._from_proto(d) for d in resp.get_audio_devices.playout_devices]
289
+
290
+ def set_recording_device(self, device_id: str) -> None:
291
+ """Select the recording device (microphone) to use.
292
+
293
+ Call this before creating audio tracks to select which microphone to use.
294
+ If not called, the system default microphone is used.
295
+
296
+ Args:
297
+ device_id: The device ID (GUID) from AudioDeviceInfo.id. Use the ID
298
+ rather than index for stable device selection across hot-plug events.
299
+
300
+ Raises:
301
+ PlatformAudioError: If device selection fails.
302
+ """
303
+ req = proto_ffi.FfiRequest()
304
+ req.set_recording_device.platform_audio_handle = self._ffi_handle.handle
305
+ req.set_recording_device.device_id = device_id
306
+
307
+ resp = FfiClient.instance.request(req)
308
+
309
+ if resp.set_recording_device.HasField("error") and resp.set_recording_device.error:
310
+ raise PlatformAudioError(
311
+ f"Failed to set recording device: {resp.set_recording_device.error}"
312
+ )
313
+
314
+ def set_playout_device(self, device_id: str) -> None:
315
+ """Select the playout device (speaker) to use.
316
+
317
+ Call this before connecting to a room to select which speaker to use
318
+ for audio output. If not called, the system default speaker is used.
319
+
320
+ Args:
321
+ device_id: The device ID (GUID) from AudioDeviceInfo.id. Use the ID
322
+ rather than index for stable device selection across hot-plug events.
323
+
324
+ Raises:
325
+ PlatformAudioError: If device selection fails.
326
+ """
327
+ req = proto_ffi.FfiRequest()
328
+ req.set_playout_device.platform_audio_handle = self._ffi_handle.handle
329
+ req.set_playout_device.device_id = device_id
330
+
331
+ resp = FfiClient.instance.request(req)
332
+
333
+ if resp.set_playout_device.HasField("error") and resp.set_playout_device.error:
334
+ raise PlatformAudioError(
335
+ f"Failed to set playout device: {resp.set_playout_device.error}"
336
+ )
337
+
338
+ def create_audio_source(
339
+ self, options: Optional[PlatformAudioOptions] = None
340
+ ) -> PlatformAudioSource:
341
+ """Create an audio source for publishing microphone audio.
342
+
343
+ The returned source captures audio from the selected microphone (or system
344
+ default) and can be used with LocalAudioTrack.create_audio_track() to
345
+ publish audio.
346
+
347
+ Args:
348
+ options: Audio processing options (AEC, NS, AGC, prefer_hardware).
349
+ If None, defaults are used (all processing enabled).
350
+
351
+ Returns:
352
+ PlatformAudioSource that can be passed to LocalAudioTrack.create_audio_track().
353
+
354
+ Raises:
355
+ PlatformAudioError: If source creation fails.
356
+
357
+ Example:
358
+ ```python
359
+ source = platform_audio.create_audio_source(
360
+ PlatformAudioOptions(
361
+ echo_cancellation=True,
362
+ noise_suppression=True,
363
+ auto_gain_control=True,
364
+ )
365
+ )
366
+ track = rtc.LocalAudioTrack.create_audio_track("microphone", source)
367
+ ```
368
+ """
369
+ if options is None:
370
+ options = PlatformAudioOptions()
371
+
372
+ req = proto_ffi.FfiRequest()
373
+ req.new_audio_source.type = proto_audio_frame.AudioSourceType.AUDIO_SOURCE_PLATFORM
374
+ req.new_audio_source.platform_audio_handle = self._ffi_handle.handle
375
+ req.new_audio_source.options.CopyFrom(options._to_proto())
376
+ # For platform audio, the ADM determines the actual sample rate and channels.
377
+ # These fields are ignored but required by older proto versions (will be optional
378
+ # in livekit-ffi >= 0.12.58). Use standard WebRTC defaults.
379
+ req.new_audio_source.sample_rate = 48000
380
+ req.new_audio_source.num_channels = 1
381
+
382
+ resp = FfiClient.instance.request(req)
383
+ source_info = resp.new_audio_source.source
384
+
385
+ return PlatformAudioSource(
386
+ FfiHandle(source_info.handle.id),
387
+ source_info,
388
+ )
389
+
390
+ def close(self) -> None:
391
+ """Release the native Audio Device Module resources.
392
+
393
+ Call this method when you are done using PlatformAudio to immediately
394
+ release the underlying ADM handle and associated native resources.
395
+
396
+ Why call close() explicitly?
397
+ Python's garbage collection is non-deterministic. If you rely on GC
398
+ to clean up PlatformAudio, the ADM may remain active longer than
399
+ expected. This can cause problems on some platforms (especially
400
+ Windows) where:
401
+
402
+ - Audio device handles are held longer than necessary, preventing
403
+ other applications or audio subsystems from accessing the devices
404
+ - Subsequent audio operations (including synthetic AudioSource) may
405
+ fail or behave unexpectedly due to ADM still being active
406
+ - Tests running in sequence may interfere with each other if the
407
+ previous test's ADM resources haven't been collected yet
408
+
409
+ What happens if close() is not called?
410
+ Resources will eventually be released when the PlatformAudio object
411
+ is garbage collected. This works fine in simple applications where
412
+ the object goes out of scope and is collected promptly. However, in
413
+ these scenarios you should call close() explicitly:
414
+
415
+ - Running multiple tests that use audio
416
+ - Switching between PlatformAudio and synthetic AudioSource
417
+ - Long-running applications that create/destroy audio resources
418
+ - Applications where prompt device release is important
419
+
420
+ It is safe to call `close()` multiple times; subsequent calls are no-ops.
421
+
422
+ Note:
423
+ Always close PlatformAudioSource instances before closing the parent
424
+ PlatformAudio instance.
425
+ """
426
+ self._ffi_handle.dispose()
livekit/rtc/py.typed ADDED
File without changes