feat: ai.poly:voice — WebRTC voice calling SDK#8
Merged
Conversation
Zakariya1057
force-pushed
the
mes-185-webrtc-android
branch
6 times, most recently
from
June 30, 2026 15:25
45851a5 to
a9b59f1
Compare
Zakariya1057
force-pushed
the
mes-185-webrtc-android
branch
2 times, most recently
from
June 30, 2026 16:42
34c10af to
d5aeb9b
Compare
New :polyvoice module (ai.poly:voice) — live two-way WebRTC voice calls to a
PolyAI agent, alongside ai.poly:messaging. Bumps the SDK to 0.9.0 (first
ai.poly:voice publish, with ai.poly:messaging:0.9.0).
- Hexagonal ports/adapters over libwebrtc + OkHttp; a pure CallCoordinator
state machine (auth → session → link → ICE → signaling → peer → offer),
signaling wire codec, trickle-ICE buffering, connection-timeout +
disconnect-grace, signaling-drop reconnect with backoff, idempotent teardown.
- Audio: MODE_IN_COMMUNICATION + focus. Output routing is accessory-aware by
default — follows a connected wired/Bluetooth headset, auto-switches on
plug/unplug, falls back to speaker/earpiece; a picker (call.audio +
setAudioDevice) pins any output or returns to automatic. API 31+
communication-device model + the legacy SCO path; route mutation serialized
under a lock. Audio-focus interruptions: transient → mute/restore,
permanent / incoming call → end with PolyError.Voice.Interrupted.
- Credentials: Configuration.apiKey (X-Token) + a required, distinct
VoiceOptions.webrtcToken. Session create reports platform + a detected
device_type (mobile/tablet), consistent with ai.poly:messaging.
- Public API mirrors :polymessaging idioms (Kotlin suspend + Java
Callback/Executor overloads); ships consumer R8 keep rules. JVM tests over
port fakes.
polymessaging: additive PolyError.Voice.Disconnected + Interrupted; PolyCall
KDoc points to the voice artifact (no other ABI change).
Examples reorganized into examples/chat/{compose,views} and
examples/voice/{compose,views} — a tap-to-call demo with the audio-output
picker (incl. an Auto option) and a microphone foreground service (+ wake
lock) so calls survive backgrounding.
Docs: a dedicated polyvoice/README.md voice guide (permissions, credentials,
audio output, interruptions, backgrounding, R8); the root README keeps a
concise voice quickstart that links to it.
Zakariya1057
force-pushed
the
mes-185-webrtc-android
branch
from
June 30, 2026 16:50
d5aeb9b to
02e15ab
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Adds
ai.poly:voice(the:polyvoicemodule) — live two-way WebRTC voice calls to a PolyAIagent, the on-device counterpart to
ai.poly:messaging. Ships as a separate artifact so chat-only appsstay lean (the call path pulls in the native libwebrtc audio engine).
This also bumps the SDK to 0.9.0 — tagging
v0.9.0after merge publishesai.poly:messaging:0.9.0and the first-ever
ai.poly:voice:0.9.0.What's new
:polyvoicemodule — hexagonal ports/adapters (mirrors:polymessaging):CallCoordinatorstate machine (auth → session → link → ICE → signaling → peer → offer),signaling wire codec, trickle-ICE buffering (both directions), connection-timeout + disconnect-grace,
signaling-drop reconnect with backoff (1s/2s/4s ×3), idempotent teardown.
automatically and auto-switches when you plug/unplug one mid-call, falling back to speaker (or
earpiece). A picker (
call.audio+setAudioDevice) lets users pin any output and return toautomatic via
setAudioDevice(null)— API 31+ communication-device model + the legacy SCO path, withlive change events. All route mutation is serialized under a lock against the coordinator thread.
incoming phone call → end with
PolyError.Voice.Interrupted.Configuration.apiKey(X-Token) + a required, distinctVoiceOptions.webrtcToken(the gateway auth token). Session create reports
platform=android+ a detecteddevice_type(mobile/tablet), consistent with
ai.poly:messaging.:polymessagingidioms — Kotlinsuspendand JavaCallback/Executoroverloads on everything. Ships consumer R8 keep rules for the JNI surface.
:polymessaging— additive only:PolyError.Voice.Disconnected+Interrupted;PolyCallKDocnow points at the voice artifact. ABI otherwise unchanged.
Examples reorganized into
examples/chat/{compose,views}andexamples/voice/{compose,views}— atap-to-call demo with the audio-output picker (incl. an Auto option) and a microphone foreground
service (+ wake lock) so calls survive backgrounding.
Docs — a dedicated
polyvoice/README.mdguide (permissions, credentials,audio output, interruptions, backgrounding, R8); the root README keeps a concise voice quickstart that
links to it.
Testing
:polyvoiceover port fakes (signaling codec, the full coordinator statemachine, ICE buffering, timeouts, disconnect-grace + reconnect, mute, audio-device selection, focus
interruptions,
platform/device_typeon session create) + the:polymessagingsuite; bothapiChecks green. CI runsbuild test lint apiCheck.Bluetooth), incoming-call interruption (ends with
Interrupted), and backgrounded-call survival(foreground service + wake lock) all verified.
under a lock.
Notes
YOUR_API_KEY/YOUR_WEBRTC_TOKENplaceholders (set them in thePolyVoice.call(...)block) — no committed credentials.examples/compose|views→examples/chat/...) shows as git renames — most ofthe file count is moves; the substantive surface is
polyvoice/+examples/voice/.