{"id":51902414,"url":"https://github.com/linuxserver/pcmflux","last_synced_at":"2026-07-26T17:30:59.485Z","repository":{"id":301942732,"uuid":"1010720297","full_name":"linuxserver/pcmflux","owner":"linuxserver","description":"A performant web native audio delivery pipeline for pusleaudio sources. ","archived":false,"fork":false,"pushed_at":"2026-03-27T21:24:45.000Z","size":51,"stargazers_count":7,"open_issues_count":1,"forks_count":3,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-07-07T16:42:49.743Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/linuxserver.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"linuxserver","open_collective":"linuxserver"}},"created_at":"2025-06-29T17:02:37.000Z","updated_at":"2026-03-27T21:24:48.000Z","dependencies_parsed_at":"2025-06-29T18:42:53.482Z","dependency_job_id":"7c690d20-326f-4117-b489-5e7b19dd8555","html_url":"https://github.com/linuxserver/pcmflux","commit_stats":null,"previous_names":["linuxserver/pcmflux"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/linuxserver/pcmflux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxserver%2Fpcmflux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxserver%2Fpcmflux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxserver%2Fpcmflux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxserver%2Fpcmflux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linuxserver","download_url":"https://codeload.github.com/linuxserver/pcmflux/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linuxserver%2Fpcmflux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35922387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-26T02:00:06.503Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-26T17:30:59.380Z","updated_at":"2026-07-26T17:30:59.477Z","avatar_url":"https://github.com/linuxserver.png","language":"Python","funding_links":["https://github.com/sponsors/linuxserver","https://opencollective.com/linuxserver"],"categories":[],"sub_categories":[],"readme":"# pcmflux\n\n[![PyPI version](https://badge.fury.io/py/pcmflux.svg)](https://badge.fury.io/py/pcmflux)\n[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://linuxserver.github.io/pcmflux/)\n\npcmflux is a high-performance audio capture and encoding module for Python.\n\nIt is designed to capture system audio using PulseAudio, encode it into the Opus format, and stream it with low latency. A key optimization is its ability to detect and discard silent audio chunks, significantly reducing network traffic and CPU usage during periods of no sound.\n\n## Prerequisites\n\nThis package builds a native Rust extension (via `setuptools-rust`/PyO3). It requires a Rust toolchain (`cargo`/`rustc`) plus the development headers for PulseAudio and Opus on your system.\n\nOn Debian/Ubuntu, you can install them with:\n```bash\nsudo apt-get install libpulse-dev libopus-dev\n```\n\n## Core Features\n\n- **PulseAudio Capture:** Captures system audio via PulseAudio using the asynchronous `Context`/`Stream` record API with a manually-pumped mainloop.\n- **Opus Encoding:** Integrates the high-quality, low-latency Opus codec.\n- **Silence Detection:** Intelligently skips encoding and sending silent audio chunks.\n- **Native Audio Header:** With `omit_audio_header=False` (the default), the encoder prepends a 2-byte `[0x01, 0x00]` header to each chunk natively, so WebSocket transports avoid an extra Python copy. Set it to `True` for raw Opus (WebRTC/RTP).\n- **Optional RED redundancy (RFC 2198):** `red_distance` (0–4, default 0) prepends redundant copies of recent Opus payloads for lossy/unreliable transports; `0` disables it (the default for reliable WebSocket/TCP).\n- **Zero-copy Frames:** Each callback receives a native `AudioFrame` that owns the encoded chunk and supports the buffer protocol — `bytes(frame)` / `memoryview(frame)` / `len(frame)` — on **every supported Python version (3.9–3.14)**. `memoryview(frame)` aliases the buffer with no copy, and the frame keeps it alive until every view is released, so the hand-off is memory-safe.\n- **Tunable Capture:** Configurable `latency_ms`, validated `frame_duration_ms` (2.5/5/10/20/40/60 ms, default 20), VBR/CBR, and a toggleable silence gate.\n- **Multichannel Opus:** Mono, stereo, and 5.1 / 7.1 surround (via the Opus multistream API with Chromium-compatible channel layouts); `channels` accepts 1, 2, 6, or 8.\n- **Mic-Uplink Playback:** An `AudioPlayback` class decodes an inbound Opus stream (with optional RED recovery via `write_red`) and plays it into a PulseAudio sink — the reverse of capture, for client microphone audio. Playback is mono/stereo.\n- **Live Bitrate Updates:** Thread-safe `update_audio_bitrate()` adjusts the Opus bitrate during an active session.\n- **PyO3 Extension Module:** A native Rust `pcmflux` extension module (full CPython API, not Limited/abi3) provides PulseAudio capture + Opus encoding.\n- **Python Build System:** Uses `setuptools-rust` to build and package the `pcmflux` PyO3 extension.\n\n## Usage\n\n`AudioCapture.start_capture(settings, callback)` spawns a capture thread and\ninvokes `callback(frame)` once per *encoded* chunk. When the silence gate is on\n(`use_silence_gate=True`, the default), silent chunks are dropped before\nencoding and the callback is simply **not** called for them — it never receives\nan empty frame, so there's no silence to filter out. The `frame` is a zero-copy\n`AudioFrame` (buffer protocol + a `.pts` presentation timestamp in samples).\nCopy it out with `bytes(frame)` if it must outlive the callback, or pass\n`memoryview(frame)` for a zero-copy hand-off (keep the frame referenced for the\nduration of the send so its buffer stays alive).\n\n```python\nfrom pcmflux import AudioCapture, AudioCaptureSettings\n\ndef on_chunk(frame):\n    # Silence-gated chunks are never delivered (the callback is skipped for\n    # them), so there's no empty/\"silence\" frame to filter out here.\n    data = bytes(frame)          # copy out (header+Opus, or raw Opus per settings)\n    pts = frame.pts              # presentation timestamp, in samples\n    # send `data` to your client...\n\nsettings = AudioCaptureSettings()\nsettings.device_name = None      # None / \"\" =\u003e system default source\nsettings.frame_duration_ms = 20  # one of 2.5/5/10/20/40/60\n\ncapture = AudioCapture()\ncapture.start_capture(settings, on_chunk)\n# capture.update_audio_bitrate(96000)  # adjust the Opus bitrate while running\n# ...\ncapture.stop_capture()\n```\n\n### API notes\n\n- `update_audio_bitrate(bps)` stores the new Opus bitrate\n  atomically; the capture thread re-reads it on the next frame, so it only takes\n  effect during an **active** capture session. Calling it while no capture is\n  active is **not** an error — it is a silent no-op store, but the value does\n  **not** persist into the next session: the next `start_capture(settings, ...)`\n  snapshots the passed settings object and re-seeds the atomic bitrate mirror from\n  `settings.opus_bitrate`. To change the bitrate for a new\n  session, set `settings.opus_bitrate` before `start_capture()`; use\n  `update_audio_bitrate()` only to adjust a session that is already running.\n\n## Example Usage\n\nThe `example` directory contains a standalone demo that captures system audio, broadcasts it over a WebSocket, and plays it back in a web browser using the WebCodecs API.\n\nTo run the example:\n\n1.  Install the module: `pip3 install .`\n2.  Run the server: `cd example \u0026\u0026 python3 audio_to_browser.py`\n3.  Open `http://localhost:9001` in a modern web browser (Chrome, Edge, etc.).\n\nThe example client (`index.html`) strips the 2-byte `[0x01, 0x00]` header before decoding, and its `FRAME_DURATION_US` constant must match the server's `frame_duration_ms` (the value is not announced over the wire).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinuxserver%2Fpcmflux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinuxserver%2Fpcmflux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinuxserver%2Fpcmflux/lists"}