fal.wma.App to manage the session and fal.wma.AiortcPeer to connect a Python media pipeline.
Deploy your first app
Start with the generated-video example. It runs on a CPU and requires no camera, model weights, or GPU. You can change its colors and speed while the video streams.1. Install and authenticate
Use Python 3.12 for this walkthrough. Create a virtual environment, then install the SDK:.venv\Scripts\Activate.ps1.
If your package index cannot find 1.81.4, wait for the PyPI publishing workflow to finish.
A GitHub release can exist before its package is available on PyPI.
The wma extra installs local WebRTC dependencies. WMA apps also receive aiortc in their runner requirements.
Your account needs deployment access and WMA bridge access. Installing the package does not grant either permission.
2. Download and deploy the video example
Download the example from the matching SDK release:3. Connect in the playground
- Open your deployed app in the fal dashboard.
- Select its
/start-sessionplayground. - Select Connect and wait for the video.
- Select Fast sunset, then select Send message.
- Confirm that the colors and speed change.
- Select Disconnect to end the session.
Choose an example
Each example includes a realtime contract and deployment requirements. Download the file, then deploy the named class with--auth private.
The camera examples need browser camera permission. Motion measurements use pixel differences, not an object detector.
For your own frontend, follow Connect a browser to WMA.
Build your own app
Subclassfal.wma.App and implement create_backend(session). Return an AiortcPeer, or implement PeerBackend for your own transport.
The following complete app echoes typed control messages. Save it as wma_echo.py.
AiortcPeer receives the peer connection. Attach outgoing tracks with pc.addTrack(track).
Register a pc.on("track") handler to process incoming media. The video and camera examples demonstrate both patterns.
Describe your app for the playground
Declarerealtime_contract on every app that needs the WMA playground.
The SDK generates AsyncAPI and links it from the /start-session OpenAPI operation through x-fal-realtime.
This metadata enables Connect/Disconnect controls, message forms, examples, and media previews.
Use Pydantic models for client_messages and server_messages. Add MessageExample entries for commands that customers can try.
Use MediaContract to describe the actual media tracks. Track directions are always from the client’s perspective:
For example, a camera-to-video app declares:
Session lifecycle and cleanup
The client sends its offer through the WMA bridge. The bridge forwards it to your app’sPOST /start-session endpoint.
The response streams the answer and keeps the HTTP connection open for the session’s lifetime.
Media and control messages travel through WebRTC, either directly or through TURN.
Closing the session closes its backend and finalizes deferred usage. Do not add application heartbeat or close routes for this lifecycle.
Keep mutable state inside create_backend so different sessions do not share controls accidentally.
Use session.create_task() for background work that must stop with the session.
Bind resources with session.bind_backend(backend) before setup work that can fail.
AiortcPeer stops its attached outgoing tracks during cleanup. Use a separate relay subscription when sessions share a media source.
It limits the initial connection wait to 35 seconds. Set disconnected_grace_seconds if you want a bounded wait after a transient disconnect.
session.send(message) returns False when the channel cannot accept a message or its buffer is full.
Drop stale updates or retry later. A worker thread’s True result confirms queue acceptance, not delivery to the client.
ICE, billing, and deployment
UseRunnerIceConfig.from_bridge() with the forwarded offer, as shown above. It validates the supplied ICE servers before use.
TURN permits connections on networks where a direct path fails. A successful local connection does not prove that TURN works.
For metered application usage, call session.add_billable_units(n) for delivered work.
Use session.cap_billable_units(n) before finalization if cleanup identifies undelivered work.
Deferred usage is zero on setup failures by default. Runner compute can still incur charges.
Billing report failures require operational follow-up.
The base app includes the FAL_KEY secret for its billing reporter. Preserve it if your subclass overrides secrets.
Configure the required runner secrets and endpoint pricing before using deferred billing.
Your browser application’s API key belongs on its server, never in browser code.
Before customer handoff, verify these behaviors against the deployed app:
- Connect with the intended client and network.
- Exchange the declared controls and media.
- Test TURN on a network that requires relay connectivity.
- Disconnect and reconnect with a new session.
- Confirm that cleanup stops background work and releases resources.
- Confirm the settled billing amount for delivered work.
Troubleshooting
See the SDK guide for module details and custom backend responsibilities.