proc-tap 0.2.0__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.
@@ -0,0 +1,444 @@
1
+ Metadata-Version: 2.4
2
+ Name: proc-tap
3
+ Version: 0.2.0
4
+ Summary: Cross-platform process-level audio capture library
5
+ Author-email: m96-chan <y_harada@technologies.moe>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/m96-chan/ProcTap
8
+ Project-URL: Repository, https://github.com/m96-chan/ProcTap
9
+ Project-URL: Issues, https://github.com/m96-chan/ProcTap/issues
10
+ Keywords: audio,capture,wasapi,windows,linux,macos,pulseaudio,coreaudio,process,loopback
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: Microsoft :: Windows
15
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 10
16
+ Classifier: Operating System :: Microsoft :: Windows :: Windows 11
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Operating System :: MacOS
19
+ Classifier: Operating System :: MacOS :: MacOS X
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Programming Language :: C++
26
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Capture/Recording
27
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
28
+ Requires-Python: >=3.10
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: pulsectl>=23.5.0; sys_platform == "linux"
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest; extra == "dev"
34
+ Requires-Dist: mypy; extra == "dev"
35
+ Requires-Dist: types-setuptools; extra == "dev"
36
+ Provides-Extra: docs
37
+ Requires-Dist: mkdocs-material>=9.0.0; extra == "docs"
38
+ Requires-Dist: mkdocstrings[python]>=0.24.0; extra == "docs"
39
+ Provides-Extra: linux
40
+ Requires-Dist: pulsectl>=23.5.0; extra == "linux"
41
+ Dynamic: license-file
42
+
43
+ <div align="center">
44
+
45
+ # ๐Ÿ“ก ProcTap
46
+
47
+ **Cross-Platform Per-Process Audio Capture**
48
+
49
+ [![PyPI version](https://img.shields.io/pypi/v/proc-tap?color=blue&logo=pypi&logoColor=white)](https://pypi.org/project/proc-tap/)
50
+ [![Python versions](https://img.shields.io/pypi/pyversions/proc-tap?logo=python&logoColor=white)](https://pypi.org/project/proc-tap/)
51
+ [![Downloads](https://img.shields.io/pypi/dm/proc-tap?logo=pypi&logoColor=white)](https://pypi.org/project/proc-tap/)
52
+ [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux*%20%7C%20macOS*-blue)](https://github.com/m96-chan/ProcTap)
53
+
54
+ [![Build wheels](https://github.com/m96-chan/ProcTap/actions/workflows/build-wheels.yml/badge.svg)](https://github.com/m96-chan/ProcTap/actions/workflows/build-wheels.yml)
55
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
56
+ [![Code style](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
57
+ [![GitHub stars](https://img.shields.io/github/stars/m96-chan/ProcTap?style=social)](https://github.com/m96-chan/ProcTap/stargazers)
58
+
59
+ ---
60
+
61
+ ProcTap is a Python library for per-process audio capture with platform-specific backends.
62
+
63
+ **Capture audio from a specific process only** โ€” without system sounds or other app audio mixed in.
64
+ Ideal for VRChat, games, DAWs, browsers, and AI audio analysis pipelines.
65
+
66
+ ### Platform Support
67
+
68
+ | Platform | Status | Backend | Notes |
69
+ |----------|--------|---------|-------|
70
+ | **Windows** | โœ… **Fully Supported** | WASAPI (C++ native) | Windows 10/11 (20H1+) |
71
+ | **Linux** | ๐Ÿงช **Experimental** | PulseAudio/PipeWire | Basic support, sink monitor capture |
72
+ | **macOS** | ๐Ÿงช **Experimental** | Core Audio Process Tap | macOS 14.4+ (Sonoma) required |
73
+
74
+ <sub>\* Linux and macOS support are experimental with limitations (see requirements). Windows is currently the only fully functional platform.</sub>
75
+
76
+ </div>
77
+
78
+ ---
79
+
80
+ ## ๐Ÿš€ Features
81
+
82
+ - ๐ŸŽง **Capture audio from a single target process**
83
+ (VRChat, games, browsers, Discord, DAWs, streaming tools, etc.)
84
+
85
+ - ๐ŸŒ **Cross-platform architecture**
86
+ โ†’ Windows (fully supported) | Linux (experimental) | macOS (experimental, 14.4+)
87
+
88
+ - โšก **Platform-optimized backends**
89
+ โ†’ Windows: ActivateAudioInterfaceAsync (modern WASAPI)
90
+ โ†’ Linux: PulseAudio/PipeWire (experimental)
91
+ โ†’ macOS: Core Audio Process Tap API (macOS 14.4+)
92
+
93
+ - ๐Ÿงต **Low-latency, thread-safe audio engine**
94
+ โ†’ 44.1 kHz / stereo / 16-bit PCM format (Windows)
95
+
96
+ - ๐Ÿ **Python-friendly high-level API**
97
+ - Callback-based streaming
98
+ - Async generator streaming (`async for`)
99
+
100
+ - ๐Ÿ”Œ **Native extensions for high-performance**
101
+ โ†’ C++ extension on Windows for optimal throughput
102
+
103
+ ---
104
+
105
+ ## ๐Ÿ“ฆ Installation
106
+
107
+ **From PyPI**:
108
+
109
+ ```bash
110
+ pip install proc-tap
111
+ ```
112
+
113
+ **Platform-specific dependencies are automatically installed:**
114
+ - Windows: No additional dependencies
115
+ - Linux: `pulsectl` is automatically installed, but you also need system packages:
116
+ ```bash
117
+ # Ubuntu/Debian
118
+ sudo apt-get install pulseaudio-utils
119
+
120
+ # Fedora/RHEL
121
+ sudo dnf install pulseaudio-utils
122
+ ```
123
+
124
+ ๐Ÿ“š **[Read the Full Documentation](https://m96-chan.github.io/ProcTap/)** for detailed guides and API reference.
125
+
126
+ **From TestPyPI** (for testing pre-releases):
127
+
128
+ ```bash
129
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ proctap
130
+ ```
131
+
132
+ **From Source**:
133
+
134
+ ```bash
135
+ git clone https://github.com/m96-chan/ProcTap
136
+ cd ProcTap
137
+ pip install -e .
138
+ ```
139
+
140
+ ---
141
+
142
+ ## ๐Ÿ›  Requirements
143
+
144
+ **Windows (Fully Supported):**
145
+ - Windows 10 / 11 (20H1 or later)
146
+ - Python 3.10+
147
+ - WASAPI support
148
+ - **No admin privileges required**
149
+
150
+ **Linux (Experimental):**
151
+ - Linux with PulseAudio or PipeWire (with pulseaudio-compat)
152
+ - Python 3.10+
153
+ - `pulsectl` library: **automatically installed with `pip install proc-tap`**
154
+ - `parec` command: install with `sudo apt-get install pulseaudio-utils`
155
+ - โš ๏ธ **EXPERIMENTAL:** Basic PulseAudio support implemented
156
+ - โš ๏ธ **LIMITATION:** Currently captures from entire sink monitor (may include other apps)
157
+
158
+ **macOS (Experimental):**
159
+ - macOS 14.4 (Sonoma) or later
160
+ - Python 3.10+
161
+ - Swift CLI helper binary (proctap-macos)
162
+ - Audio capture permission
163
+ - โš ๏ธ **EXPERIMENTAL:** Core Audio Process Tap API support implemented
164
+ - โš ๏ธ **REQUIREMENT:** Requires macOS 14.4+ for Process Tap API
165
+
166
+ ---
167
+
168
+ ## ๐Ÿงฐ Basic Usage (Callback API)
169
+
170
+ ```python
171
+ from proctap import ProcTap, StreamConfig
172
+
173
+ def on_chunk(pcm: bytes, frames: int):
174
+ print(f"Received {len(pcm)} bytes ({frames} frames)")
175
+
176
+ pid = 12345 # Target process ID
177
+
178
+ tap = ProcTap(pid, StreamConfig(), on_data=on_chunk)
179
+ tap.start()
180
+
181
+ input("Recording... Press Enter to stop.\n")
182
+
183
+ tap.close()
184
+ ```
185
+
186
+ ---
187
+
188
+ ## ๐Ÿ” Async Usage (Async Generator)
189
+
190
+ ```python
191
+ import asyncio
192
+ from proctap import ProcTap
193
+
194
+ async def main():
195
+ tap = ProcTap(pid=12345)
196
+ tap.start()
197
+
198
+ async for chunk in tap.iter_chunks():
199
+ print(f"PCM chunk size: {len(chunk)} bytes")
200
+
201
+ asyncio.run(main())
202
+ ```
203
+
204
+ ---
205
+
206
+ ## ๐Ÿ“„ API Overview
207
+
208
+ ### `class ProcTap`
209
+
210
+ **Control Methods:**
211
+
212
+ | Method | Description |
213
+ |--------|-------------|
214
+ | `start()` | Start WASAPI per-process capture |
215
+ | `stop()` | Stop capture |
216
+ | `close()` | Release native resources |
217
+
218
+ **Data Access:**
219
+
220
+ | Method | Description |
221
+ |--------|-------------|
222
+ | `iter_chunks()` | Async generator yielding PCM chunks |
223
+ | `read(timeout=1.0)` | Synchronous: read one chunk (blocking) |
224
+
225
+ **Properties:**
226
+
227
+ | Property | Type | Description |
228
+ |----------|------|-------------|
229
+ | `is_running` | bool | Check if capture is active |
230
+ | `pid` | int | Get target process ID |
231
+ | `config` | StreamConfig | Get stream configuration |
232
+
233
+ **Utility Methods:**
234
+
235
+ | Method | Description |
236
+ |--------|-------------|
237
+ | `set_callback(callback)` | Change or remove audio callback |
238
+ | `get_format()` | Get audio format info (dict) |
239
+
240
+ ### Audio Format
241
+
242
+ **Note:** The native extension uses a **fixed audio format** (hardcoded in C++):
243
+
244
+ | Parameter | Value | Description |
245
+ |-----------|-------|-------------|
246
+ | Sample Rate | **44,100 Hz** | CD quality (fixed) |
247
+ | Channels | **2** | Stereo (fixed) |
248
+ | Bit Depth | **16-bit** | PCM format (fixed) |
249
+
250
+ The `StreamConfig` class exists for API compatibility but does not change the native backend format.
251
+
252
+ ---
253
+
254
+ ## ๐ŸŽฏ Use Cases
255
+
256
+ - ๐ŸŽฎ Record audio from one game only
257
+ - ๐Ÿ•ถ Capture VRChat audio cleanly (without system sounds)
258
+ - ๐ŸŽ™ Feed high-SNR audio into AI recognition models
259
+ - ๐Ÿ“น Alternative to OBS "Application Audio Capture"
260
+ - ๐ŸŽง Capture DAW/app playback for analysis tools
261
+
262
+ ---
263
+
264
+ ## ๐Ÿ“š Example: Save to WAV
265
+
266
+ ```python
267
+ from proctap import ProcTap
268
+ import wave
269
+
270
+ pid = 12345
271
+
272
+ wav = wave.open("output.wav", "wb")
273
+ wav.setnchannels(2)
274
+ wav.setsampwidth(2) # 16-bit PCM
275
+ wav.setframerate(44100) # Native format is 44.1 kHz
276
+
277
+ def on_data(pcm, frames):
278
+ wav.writeframes(pcm)
279
+
280
+ with ProcTap(pid, on_data=on_data):
281
+ input("Recording... Press Enter to stop.\n")
282
+
283
+ wav.close()
284
+ ```
285
+
286
+ ---
287
+
288
+ ## ๐Ÿ“š Example: Synchronous Read API
289
+
290
+ ```python
291
+ from proctap import ProcTap
292
+
293
+ tap = ProcTap(pid=12345)
294
+ tap.start()
295
+
296
+ try:
297
+ while True:
298
+ chunk = tap.read(timeout=1.0) # Blocking read
299
+ if chunk:
300
+ print(f"Got {len(chunk)} bytes")
301
+ # Process audio data...
302
+ else:
303
+ print("Timeout, no data")
304
+ except KeyboardInterrupt:
305
+ pass
306
+ finally:
307
+ tap.close()
308
+ ```
309
+
310
+ ---
311
+
312
+ ## ๐Ÿง Linux Example
313
+
314
+ ```python
315
+ from proctap import ProcessAudioTap, StreamConfig
316
+ import wave
317
+
318
+ pid = 12345 # Your target process ID
319
+
320
+ # Create WAV file
321
+ wav = wave.open("linux_capture.wav", "wb")
322
+ wav.setnchannels(2)
323
+ wav.setsampwidth(2)
324
+ wav.setframerate(44100)
325
+
326
+ def on_data(pcm, frames):
327
+ wav.writeframes(pcm)
328
+
329
+ # Create stream config (Linux backend respects these settings)
330
+ config = StreamConfig(sample_rate=44100, channels=2)
331
+
332
+ try:
333
+ with ProcessAudioTap(pid, config=config, on_data=on_data):
334
+ print("โš ๏ธ Make sure the process is actively playing audio!")
335
+ input("Recording... Press Enter to stop.\n")
336
+ finally:
337
+ wav.close()
338
+ ```
339
+
340
+ **Linux-specific requirements:**
341
+ - Install system package: `sudo apt-get install pulseaudio-utils` (provides `parec` command)
342
+ - Python dependency `pulsectl` is automatically installed with `pip install proc-tap`
343
+ - The target process must be actively playing audio
344
+ - See [examples/linux_basic.py](examples/linux_basic.py) for a complete example
345
+
346
+ ---
347
+
348
+ ## ๐ŸŽ macOS Example
349
+
350
+ ```python
351
+ from proctap import ProcessAudioTap, StreamConfig
352
+ import wave
353
+
354
+ pid = 12345 # Your target process ID
355
+
356
+ # Create WAV file
357
+ wav = wave.open("macos_capture.wav", "wb")
358
+ wav.setnchannels(2)
359
+ wav.setsampwidth(2)
360
+ wav.setframerate(48000) # macOS backend default is 48 kHz
361
+
362
+ def on_data(pcm, frames):
363
+ wav.writeframes(pcm)
364
+
365
+ # Create stream config (macOS backend respects these settings)
366
+ config = StreamConfig(sample_rate=48000, channels=2)
367
+
368
+ try:
369
+ with ProcessAudioTap(pid, config=config, on_data=on_data):
370
+ print("โš ๏ธ Make sure the process is actively playing audio!")
371
+ print("โš ๏ธ On first run, macOS will prompt for permission.")
372
+ input("Recording... Press Enter to stop.\n")
373
+ finally:
374
+ wav.close()
375
+ ```
376
+
377
+ **macOS-specific requirements:**
378
+ - macOS 14.4 (Sonoma) or later
379
+ - Swift CLI helper binary (proctap-macos) - automatically built during installation if Swift toolchain available
380
+ - Audio capture permission - macOS will prompt on first run
381
+ - The target process must be actively playing audio
382
+ - See [examples/macos_basic.py](examples/macos_basic.py) for a complete example
383
+
384
+ **Building the Swift helper manually:**
385
+ ```bash
386
+ cd swift/proctap-macos
387
+ swift build -c release
388
+ cp .build/release/proctap-macos ../../src/proctap/bin/
389
+ ```
390
+
391
+ ---
392
+
393
+ ## ๐Ÿ— Build From Source
394
+
395
+ ```bash
396
+ git clone https://github.com/m96-chan/ProcTap
397
+ cd ProcTap
398
+ pip install -e .
399
+ ```
400
+
401
+ **Windows Build Requirements:**
402
+ - Visual Studio Build Tools
403
+ - Windows SDK
404
+ - CMake (if you modularize the C++ code)
405
+
406
+ **Linux/macOS:**
407
+ - No C++ compiler required (pure Python)
408
+ - Note: Backends are not yet functional on these platforms
409
+
410
+ ---
411
+
412
+ ## ๐Ÿค Contributing
413
+
414
+ Contributions are welcome! We have structured issue templates to help guide your contributions:
415
+
416
+ - ๐Ÿ› [**Bug Report**](../../issues/new?template=bug_report.yml) - Report bugs or unexpected behavior
417
+ - โœจ [**Feature Request**](../../issues/new?template=feature_request.yml) - Suggest new features or enhancements
418
+ - โšก [**Performance Issue**](../../issues/new?template=performance.yml) - Report performance problems or optimizations
419
+ - ๐Ÿ”ง [**Type Hints / Async**](../../issues/new?template=type_hints_async.yml) - Improve type annotations or async functionality
420
+ - ๐Ÿ“š [**Documentation**](../../issues/new?template=documentation.yml) - Improve docs, examples, or guides
421
+
422
+ **Special Interest:**
423
+ - PRs from WASAPI/C++ experts are especially appreciated
424
+ - **Linux backend improvements** (PulseAudio/PipeWire per-app isolation)
425
+ - **macOS backend testing** (Core Audio Process Tap on macOS 14.4+)
426
+ - Cross-platform testing and compatibility
427
+ - Performance profiling and optimization
428
+
429
+ ---
430
+
431
+ ## ๐Ÿ“„ License
432
+
433
+ ```
434
+ MIT License
435
+ ```
436
+
437
+ ---
438
+
439
+ ## ๐Ÿ‘ค Author
440
+
441
+ **m96-chan**
442
+ Windows Audio / VRChat Tools / Python / C++
443
+ https://github.com/m96-chan
444
+
@@ -0,0 +1,15 @@
1
+ proc_tap-0.2.0.dist-info/licenses/LICENSE,sha256=FiyqJ_4TNSUs7HHCiqXCutVSrbJfsZdPXv9NKA5MVeM,1091
2
+ proctap/__init__.py,sha256=wK06NgXN8ruwGLjMd3WrkcHi34jyGWzqG7QUE8Gr7Pk,376
3
+ proctap/_native.pyi,sha256=hGjzU9yBw2Iq0Vi4jH0-vUi9p0-0-SXDgYggIwpzgXU,1986
4
+ proctap/core.py,sha256=FGGgv_GvP0qnyOox2nRrZXpLU_zecHu6NeJT65eLK14,7003
5
+ proctap/backends/__init__.py,sha256=xsd1W0GqYeOxGK8sFIOoQ4kRv9Pac3Gyf-vpVmEIgeM,1921
6
+ proctap/backends/base.py,sha256=uXVHkHXCOnSJeqfkGdYLZjTyUKIbnXDXwvuUGDa3MM8,1832
7
+ proctap/backends/linux.py,sha256=TfCiycX3ZR16pC-b9UyCQhxBpoWsBi65OZSiyihfm4E,16756
8
+ proctap/backends/macos.py,sha256=-zcBwgcb573icfSptTCym6QXRTg8L2y1BrYC7WInhQk,11524
9
+ proctap/backends/windows.py,sha256=av54ybDlmw98_vU5tChh9BaQmRCtHSlt-ojMnByT5R0,2401
10
+ proctap/contrib/__init__.py,sha256=bOWsaQpMCFzTjFSbeGwMsU6sZTIzv6tytzIKIPMmvC8,371
11
+ proctap/contrib/discord_source.py,sha256=ke7tf1Pno6UWcP-2RlOFFlvcBzM2PQz5CmkgIRtarQI,12130
12
+ proc_tap-0.2.0.dist-info/METADATA,sha256=gCl8b3amKNKz39E5hXl59Cwfl3LTyPwj4StfTbpWpOU,12997
13
+ proc_tap-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
+ proc_tap-0.2.0.dist-info/top_level.txt,sha256=kVtWrrRDOidR8WST84nlggk_gaKSGlrlgIdgezwbJw0,8
15
+ proc_tap-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Yusuke Harada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ proctap
proctap/__init__.py ADDED
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("proc-tap")
7
+ except PackageNotFoundError:
8
+ # ้–‹็™บไธญใฎ editable install ใ‚„ใƒ“ใƒซใƒ‰ๅ‰ใชใฉ
9
+ __version__ = "0.0.0"
10
+
11
+ from .core import ProcessAudioTap, StreamConfig
12
+
13
+ __all__ = ["ProcessAudioTap", "StreamConfig", "__version__"]
proctap/_native.pyi ADDED
@@ -0,0 +1,83 @@
1
+ """Type stubs for _native C++ extension module."""
2
+
3
+ from typing import Optional
4
+
5
+ class ProcessLoopback:
6
+ """
7
+ Native C++ implementation of WASAPI process-specific audio capture.
8
+
9
+ Uses ActivateAudioInterfaceAsync for per-process loopback recording
10
+ on Windows 10 20H1+ / Windows 11.
11
+ """
12
+
13
+ def __init__(self, process_id: int) -> None:
14
+ """
15
+ Initialize ProcessLoopback for a specific process.
16
+
17
+ Args:
18
+ process_id: Target process ID to capture audio from
19
+
20
+ Raises:
21
+ RuntimeError: If initialization fails
22
+ """
23
+ ...
24
+
25
+ def start(self) -> None:
26
+ """
27
+ Start audio capture.
28
+
29
+ Raises:
30
+ RuntimeError: If capture fails to start
31
+ """
32
+ ...
33
+
34
+ def stop(self) -> None:
35
+ """
36
+ Stop audio capture.
37
+
38
+ Raises:
39
+ RuntimeError: If capture fails to stop
40
+ """
41
+ ...
42
+
43
+ def read(self) -> Optional[bytes]:
44
+ """
45
+ Read captured audio data.
46
+
47
+ Returns:
48
+ PCM audio data as bytes, or None if no data is available
49
+
50
+ Note:
51
+ Returns raw PCM data in the format specified by get_format()
52
+ """
53
+ ...
54
+
55
+ def get_format(self) -> dict[str, int]:
56
+ """
57
+ Get audio format information.
58
+
59
+ Returns:
60
+ Dictionary with keys:
61
+ - 'sample_rate': Sample rate in Hz (e.g., 48000)
62
+ - 'channels': Number of channels (e.g., 2 for stereo)
63
+ - 'bits_per_sample': Bits per sample (e.g., 16)
64
+ """
65
+ ...
66
+
67
+ def is_process_specific(self) -> bool:
68
+ """
69
+ Check if process-specific capture is active.
70
+
71
+ Returns:
72
+ True if capturing from specific process, False if system-wide fallback
73
+ """
74
+ ...
75
+
76
+ def get_last_error(self) -> str:
77
+ """
78
+ Get the last error message.
79
+
80
+ Returns:
81
+ Error message string, or empty string if no error
82
+ """
83
+ ...
@@ -0,0 +1,71 @@
1
+ """
2
+ Backend selection module for ProcTap.
3
+
4
+ Automatically selects the appropriate audio capture backend based on the
5
+ current operating system.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import sys
11
+ import platform
12
+ from typing import TYPE_CHECKING
13
+
14
+ if TYPE_CHECKING:
15
+ from .base import AudioBackend
16
+
17
+
18
+ def get_backend(
19
+ pid: int,
20
+ sample_rate: int = 44100,
21
+ channels: int = 2,
22
+ sample_width: int = 2,
23
+ ) -> "AudioBackend":
24
+ """
25
+ Get the appropriate audio capture backend for the current platform.
26
+
27
+ Args:
28
+ pid: Process ID to capture audio from
29
+ sample_rate: Sample rate in Hz (default: 44100)
30
+ channels: Number of channels (default: 2 for stereo)
31
+ sample_width: Bytes per sample (default: 2 for 16-bit)
32
+
33
+ Returns:
34
+ Platform-specific AudioBackend implementation
35
+
36
+ Raises:
37
+ NotImplementedError: If the current platform is not supported
38
+ ImportError: If the backend for the current platform cannot be loaded
39
+
40
+ Note:
41
+ Windows backend uses fixed format (44100Hz, 2ch, 16-bit) and ignores
42
+ sample_rate, channels, and sample_width parameters.
43
+ """
44
+ system = platform.system()
45
+
46
+ if system == "Windows":
47
+ from .windows import WindowsBackend
48
+ # Windows backend uses fixed format from C++ extension
49
+ return WindowsBackend(pid)
50
+
51
+ elif system == "Linux":
52
+ from .linux import LinuxBackend
53
+ return LinuxBackend(
54
+ pid=pid,
55
+ sample_rate=sample_rate,
56
+ channels=channels,
57
+ sample_width=sample_width,
58
+ )
59
+
60
+ elif system == "Darwin": # macOS
61
+ from .macos import MacOSBackend
62
+ return MacOSBackend(pid)
63
+
64
+ else:
65
+ raise NotImplementedError(
66
+ f"Platform '{system}' is not supported. "
67
+ "Supported platforms: Windows, Linux (in development), macOS (planned)"
68
+ )
69
+
70
+
71
+ __all__ = ["get_backend", "AudioBackend"]