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.
- proc_tap-0.2.0.dist-info/METADATA +444 -0
- proc_tap-0.2.0.dist-info/RECORD +15 -0
- proc_tap-0.2.0.dist-info/WHEEL +5 -0
- proc_tap-0.2.0.dist-info/licenses/LICENSE +21 -0
- proc_tap-0.2.0.dist-info/top_level.txt +1 -0
- proctap/__init__.py +13 -0
- proctap/_native.pyi +83 -0
- proctap/backends/__init__.py +71 -0
- proctap/backends/base.py +77 -0
- proctap/backends/linux.py +521 -0
- proctap/backends/macos.py +373 -0
- proctap/backends/windows.py +85 -0
- proctap/contrib/__init__.py +17 -0
- proctap/contrib/discord_source.py +381 -0
- proctap/core.py +222 -0
|
@@ -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
|
+
[](https://pypi.org/project/proc-tap/)
|
|
50
|
+
[](https://pypi.org/project/proc-tap/)
|
|
51
|
+
[](https://pypi.org/project/proc-tap/)
|
|
52
|
+
[](https://github.com/m96-chan/ProcTap)
|
|
53
|
+
|
|
54
|
+
[](https://github.com/m96-chan/ProcTap/actions/workflows/build-wheels.yml)
|
|
55
|
+
[](LICENSE)
|
|
56
|
+
[](https://github.com/psf/black)
|
|
57
|
+
[](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,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"]
|