Skip to main content

PocketStation for Python

Capture one desktop application and an optional microphone as separate live audio stems. Use the same native Session for Python model code, browser delivery, and one recording file per stem.

PyPI Python License

desktop application ─┐
system audio ────────┼─ native Session ─┬─ Python model code
microphone ──────────┤                  ├─ Relay and a browser
generated PCM ───────┘                  └─ separate recording stems

PocketStation runs capture, frame timing, routing, recording, and Relay publication in Rust. Python owns the application and provider code. A slow Python integration cannot run on the operating-system capture callback.

Capture a desktop application

You need Python 3.11 or newer, a supported desktop operating system, and one running application that is producing audio.

python -m pip install pocketstation
import pocketstation

with pocketstation.capture(application="Spotify") as live:
    for frame in live.audio:
        print(frame.source_id, frame.stem_id)

Replace Spotify with the display name or application identifier shown by the operating system. You may also pass a positive process ID. Selection must match one running application; PocketStation does not guess when several processes match.

The context manager starts one native Session and joins it when the block exits. No microphone opens and no file is written unless you request them.

Capture the complete output mix

Use a Session directly when the workflow intentionally needs every sound playing through the computer:

import pocketstation as pks

session = pks.Session()
system_audio = session.capture(pks.Source.system_audio())
system_audio.send(session.polled_audio())

with session.start() as running:
    for frame in running.audio:
        print(frame.source_id, frame.stem_id)

Use Source.application(...) instead when unrelated desktop audio must remain outside the Session.

Add a microphone or recording

import pocketstation

with pocketstation.capture(
    application="Zoom",
    microphone=True,
    record_to="recordings",
) as live:
    for frame in live.audio:
        print(frame.source_id, frame.stem_id)

The application and microphone keep different source and stem identities. Recording writes a separate stem for each source and reports its final result when the Session stops.

Use a microphone device ID instead of True when the application must select a specific input. See capture one application for source discovery, permissions, and asyncio.

Use each source independently

One Session can send a stem to more than one destination:

  • iterate over frames in Python;
  • transcribe or process audio with an Operator;
  • publish audio with a Connector;
  • send a named AudioBus through Relay;
  • record the original source;
  • add generated PCM without mixing it into captured audio.

Every destination receives source, stream, stem, sequence, timestamp, clock, and discontinuity information. Application and microphone audio do not have to be mixed before model processing or remote delivery.

The default Python audio queue holds 32 frames. If Python stops reading and the queue fills, new frames are dropped and the Session reports the queue depth, dropped-frame count, and discontinuity. Other destinations continue according to their own delivery settings.

Build a voice workflow

pocketstation.voice defines the interfaces for streaming transcription, response generation, speech synthesis, speech detection, and duplex voice models. Provider packages implement those interfaces; PocketStation does not embed a model catalog or API key.

Use separate providers when the application chooses each stage:

conversation = session.conversation(
    input=microphone,
    output=assistant,
    stt=transcriber,
    llm=response_model,
    tts=synthesizer,
    vad=speech_detector,
)

Use one duplex provider when it accepts audio and returns audio through one stateful connection:

conversation = session.conversation(
    input=microphone,
    output=assistant,
    voice_model=voice_model,
)

The two forms cannot be combined. Provider capabilities are checked before the Session starts. Generated speech enters the Session through audio_input(), so it can be recorded, published, observed, or removed from pending local output without stopping microphone capture.

This API does not provide model intelligence or a hosted inference service. Optional portable processing and explicit device AEC have separate Session APIs in the development candidate; published 0.1.5 wheels do not include them. Provider-side cancellation and receiver playout remain separate observations; PocketStation does not report that a person stopped hearing audio unless the receiver can prove it.

Read compose a voice workflow for transcript revisions, provider capabilities, interruption, retained history, and current limits.

Debug a voice interruption

examples/debug_voice_ai.py shows the complete Session declaration. It connects a physical microphone to OpenAI Realtime, returns assistant PCM to PocketStation, publishes named buses through Relay, captures the browser application playing the assistant, and records the three sources separately.

python -m pip install 'pocketstation[voice-agent-debug]'
export OPENAI_API_KEY='...'
python examples/debug_voice_ai.py

Speak while the assistant is replying. The final report separates provider events from what PocketStation observed:

  • microphone capture and continuity;
  • transcript and response events reported by the provider;
  • assistant PCM accepted by the Session;
  • pending output removed after cancellation;
  • Relay and browser WebRTC observations;
  • the browser application's captured output;
  • finalized recording stems.

The example does not prove the exact loudspeaker sample a person heard, AEC, or provider-history truncation. Those fields remain unavailable when the provider or receiver cannot report them. Read the example instructions before running it.

Transcribe both sides of a voice application

The transcription example sends application and microphone audio through one faster-whisper model while keeping the resulting text attributed to its source:

python -m pip install 'pocketstation[transcription]'
python examples/transcribe_voice_app.py

The program asks which running application to inspect. It opens the default microphone because that example explicitly requests both sides. It does not start Relay or record audio.

faster-whisper processes finite audio windows and emits final transcripts. This is batch transcription, not a claim of streaming interim text or voice-agent turn handling. The adapter is example code and imports faster_whisper.WhisperModel only when transcription starts.

Stream any application to a browser

python examples/stream_any_app_audio.py

Choose a running application. The example publishes it as one named AudioBus, waits for Relay readiness, and prints a single-use word code and browser URL. It does not open a microphone or record audio.

The example uses PocketStation's small, rate-limited demonstration services unless you set POCKETSTATION_CONTROL_URL to a control plane you operate. The control plane supplies the authoritative Relay endpoints, so application code does not configure them separately. The demonstration is not a hosted service or SLA and can return HTTP 429 when its configured capacity is in use.

Send audio to your own provider

A Connector sends Session audio to an API, socket, file, or provider. Pass one async function when the connection is already open:

import pocketstation as pks
import pocketstation.aio as pks_aio


async def send_audio(frame: pks.AudioFrame) -> None:
    await socket.send(frame.samples)


destination = pks_aio.Connector(send=send_audio)
application.send_to(destination)

Use a class when the Connector opens and closes provider resources:

class WebSocketConnector(pks_aio.Connector):
    def __init__(self, url: str, token: str) -> None:
        self.url = url
        self.token = token

    async def start(self) -> None:
        self.socket = await connect(self.url, token=self.token)

    async def send(self, frame: pks.AudioFrame) -> None:
        await self.socket.send(frame.samples)

    async def stop(self) -> None:
        await self.socket.close()

One Connector object represents one configured provider connection:

destination = WebSocketConnector(url, token)
application.send_to(destination)
microphone.send_to(destination)

PocketStation calls start() once, sends both source-aware stems, and calls stop() once. Each stem retains its own delivery queue and observations. Create another Connector object when credentials, failure handling, or shutdown must be independent.

The integration guide covers deadlines, failures, sync Connectors, Sources, Operators, Endpoints, native extensions, and managed processes. The manifest and driver APIs are for distributable integrations that need typed configuration or custom service status; they are not required for a normal Python Connector.

Write PCM into a Session

Use audio_input() for generated speech, call audio, or decoded network media:

session = pocketstation.Session(recording_root="recordings")
assistant = session.audio_input("assistant")
assistant.output.record("assistant")

with session.start():
    assistant.write(samples)

Core preallocates the input buffers. A write reports whether it was accepted, full, closed, cancelled, or invalid. Read application-owned audio before selecting a queue capacity or cancelling pending output.

Handle permissions and source changes

PocketStation does not prompt during import or discovery. Check microphone permission without prompting with pocketstation.sources.microphone_permission_observation(), then let source opening report the operating system's final result. Application and microphone capture use separate permissions.

PocketStation reports a missing or stalled source; it does not choose a replacement. For a microphone in a running Session, the host can select a device and explicitly replace it without changing the logical stem or routes:

from pocketstation import Source

device_id = input("Selected microphone device ID: ")
selected_microphone = Source.microphone_id(device_id)
replacement = running.replace_microphone_source(microphone, selected_microphone)
print(replacement.source_id, replacement.source_generation)

reopen_microphone_source(microphone, selected_microphone) instead closes the old capture before reacquiring; if reopening fails, that microphone remains detached while unrelated sources continue. Both calls also accept a deliberate Source.microphone_default() selector. A successful call means the new source attached, not that a frame has arrived: inspect running.metrics().source_activities and evaluate it with your own SourceActivityPolicy. After a timeout, inspect source_replacements because the runtime may complete the operation later. Application-source recovery still requires a new Session. Store a discovered source only for its reported persistence scope.

See platform operations for permission states, persistence, recovery, and native dependencies.

Sync and asyncio

pocketstation and pocketstation.aio control the same Rust Session. The asyncio API adds awaitable lifecycle, streams, Relay calls, provider callbacks, and audio writes; it does not create another capture or routing engine.

Python callbacks enter the interpreter and pay Python scheduling and conversion costs. Capture, routing, recording, and the shared Relay Connector remain native. Python-authored model and provider code does not have identical cost to Rust code.

Platform support

Area Published support and evidence
Python 3.11 and newer
macOS Apple silicon installed wheel; physical application and microphone capture; 10 ms voice capture; deployed Relay; Chromium; multistem recording on the recorded host
macOS Intel published wheel and package tests
Linux x86-64 and ARM64 published wheels; Core application selection and 10 ms capture in automated Ubuntu environments; physical-device qualification remains separate
Windows x86-64 and ARM64 published wheels; Core selection and 10 ms capture in a Windows 11 ARM64 VM; physical-device and latency qualification remain separate
WAN and TURN not yet qualified

Version 0.1.5 uses PocketStation Core 1.1.11 and the shared Relay Connector 0.1.5. Installed runtime checks cover CPython 3.11–3.14 on the six native targets, except Windows ARM64, which is tested on 3.13–3.14. Device results in the table are separate retained measurements. Public availability and exact release receipts are recorded on PyPI and GitHub Releases.

Reading native audio into Python copies samples into Python-owned bytes before exposing a memoryview. The view avoids another Python-side copy; the Rust-to-Python call is not zero-copy.

Continue from the task you have

Task Guide
Capture one application Python quickstart
Write generated or received PCM Application audio
Process audio and typed signals Operators and signals
Record stems and inspect delivery Record and observe
Compose voice providers Voice
Publish through Relay Relay
Create an integration Integrations
Understand Session queues and shutdown Session behavior
Understand source identity and time Source identity
Prepare or troubleshoot a platform Platform support and troubleshooting
Find a public Python API API map
Check an upgrade Release notes

Develop the SDK

uv sync --extra transcription
uv run pytest -q
uv run ruff check python tests examples
uv run ruff format --check python tests examples
uv run mypy python tests/qualification/typing_contract.py examples

License

PocketStation SDK source is available under the MIT license. Native wheels include dependencies with their own terms; see third-party notices.

Read support, security, and contributing for reporting and development expectations.

Version 0.1.6 uses Core 1.1.13 for live audio history, recording clips and optional AEC APIs. See the recording guide and echo processing guide for the APIs and their support limits.

Metadata

Release files for pocketstation 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pocketstation 0.1.6
File Size Uploaded
pocketstation-0.1.6.tar.gz 506.1 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pocketstation 0.1.6
File
pocketstation-0.1.6-cp311-abi3-win_arm64.whl CPython 3.11 abi3 Windows ARM64 Details
pocketstation-0.1.6-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
pocketstation-0.1.6-cp311-abi3-manylinux_2_34_x86_64.whl CPython 3.11 abi3 Linux glibc 2.34+ x86-64 Details
pocketstation-0.1.6-cp311-abi3-manylinux_2_34_aarch64.whl CPython 3.11 abi3 Linux glibc 2.34+ ARM64 Details
pocketstation-0.1.6-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
pocketstation-0.1.6-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 41.5 MB

Release files / pocketstation-0.1.6.tar.gz

Download URL pocketstation-0.1.6.tar.gz
Size 506.1 kB
Tags Source
SHA-256 checksum
How to use checksums
6973082bb9cc73e939b85c66e274060d5b92b7318b4364aa91110dc516d60f36
BLAKE2b-256 checksum
How to use checksums
879fa70071166ecdf7928d548731d6de0554f9ff065d3b7967d26872f017ed73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / pocketstation-0.1.6-cp311-abi3-win_arm64.whl

Download URL pocketstation-0.1.6-cp311-abi3-win_arm64.whl
Size 4.7 MB
Tags CPython 3.11 Windows ARM64 abi3
SHA-256 checksum
How to use checksums
1da291b2b4a38d3fed4697ba512309a59e9a12694e812cd4dd0a13d80b32c2d5
BLAKE2b-256 checksum
How to use checksums
a33b78c8164765454a8df72c839abfb183bcc462f59c85bff750fa971ce9ddda
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / pocketstation-0.1.6-cp311-abi3-win_amd64.whl

Download URL pocketstation-0.1.6-cp311-abi3-win_amd64.whl
Size 4.8 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
3d6064da290ef23ca886cb3b61793d1d7826f104663acfc60b65fe3662c942b5
BLAKE2b-256 checksum
How to use checksums
7518d44eb79fbfe9bc479b2e69d493aaa360154bc94e8b2f2420adc59ffd7501
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / pocketstation-0.1.6-cp311-abi3-manylinux_2_34_x86_64.whl

Download URL pocketstation-0.1.6-cp311-abi3-manylinux_2_34_x86_64.whl
Size 10.5 MB
Tags CPython 3.11 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
d31b645d136392a0ffa96c71b8d0c7a7c07b2d0e0635675fe5f2ead45d6c0e2d
BLAKE2b-256 checksum
How to use checksums
dd586364399662041a08d5faf80129eeec0c102418e56702118775c28efe71df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / pocketstation-0.1.6-cp311-abi3-manylinux_2_34_aarch64.whl

Download URL pocketstation-0.1.6-cp311-abi3-manylinux_2_34_aarch64.whl
Size 9.9 MB
Tags CPython 3.11 Linux glibc 2.34+ ARM64 abi3
SHA-256 checksum
How to use checksums
111ee53def51b5204dd752546dcdf7f98a1ac181fbb9f73a3fdc710705e5bf63
BLAKE2b-256 checksum
How to use checksums
525205f6e3b18cca1e241495679ea5ffc36718ac74f5db369d69775ad66b3f56
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / pocketstation-0.1.6-cp311-abi3-macosx_11_0_arm64.whl

Download URL pocketstation-0.1.6-cp311-abi3-macosx_11_0_arm64.whl
Size 5.4 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
8dd581e9d994752823785a2b3f5173ffd218198cab81a54f429a2d4bdd6c077a
BLAKE2b-256 checksum
How to use checksums
edb3112551e57003920fa52ae1678da9162a9569db7c5d39fcc90361e21c13a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release files / pocketstation-0.1.6-cp311-abi3-macosx_10_12_x86_64.whl

Download URL pocketstation-0.1.6-cp311-abi3-macosx_10_12_x86_64.whl
Size 5.7 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
1ac5d2984b1460197aad08e88d953423c67611657cd2190b15b5e5ecd2ebdd6d
BLAKE2b-256 checksum
How to use checksums
8a9bfeb17d47abdc89a9b99b6686fe9725fbd08560821cfe645504cff3cb88be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.6 This release

7 release files

0.1.5

7 release files

0.1.4

7 release files

0.1.3

7 release files

0.1.2

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page