Skip to content

feat(voice): universal talk waveform driven by real audio levels#102901

Merged
steipete merged 3 commits into
mainfrom
claude/voice-animation-universal-ecb6db
Jul 9, 2026
Merged

feat(voice): universal talk waveform driven by real audio levels#102901
steipete merged 3 commits into
mainfrom
claude/voice-animation-universal-ecb6db

Conversation

@steipete

@steipete steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Closes #102895.

Every platform had its own talk animation, and most of it was faked: iOS realtime routes rendered a flat wave (mic level never wired), agent speech pulsed on synthetic sine waves on iOS/macOS, Android's four voice visualizers were fully static hardcoded bar rows (while a real mic level already existed unused), watchOS had a static glyph, and voice-note recording showed no level feedback at all.

Why This Change Was Made

One canonical animation, real levels everywhere the platform allows:

  • Shared component: TalkWaveformView (Siri-style wave) moves to OpenClawChatUI with a phase contract — idle / thinking / listening(level:speechActive:) / speaking(level:). TalkWaveformMath is public and unit-tested; TalkWaveform.kt is an exact Compose port (same constants). The watch target compiles the same Swift file directly (it links no packages).
  • Real level sources added:
    • PCMPlaybackEnvelope (OpenClawKit): playback-time-aligned envelope from PCM chunks streaming through the app (gateway TTS PCM, ElevenLabs PCM, realtime relay output), metered in 50 ms windows so network bursts don't distort the wave.
    • AudioPlayerLevelMeter (OpenClawKit): AVAudioPlayer metering for buffered TTS clips (iOS TalkBufferedAudioPlayer, macOS TalkAudioPlayer, incl. MLX voice output).
    • iOS realtime relay now reports mic level from its existing RMS tap; the WebRTC route polls peer-connection stats (media-source / inbound-rtp audioLevel).
    • Voice notes: AVAudioRecorder metering on iOS/macOS; MediaRecorder.maxAmplitude polling on Android; the shared recording row shows the live wave.
    • Android talk: PCM16 mean-abs level for the realtime capture loop and for PCM written to the AudioTrack (playback-paced), plus speechActive from streaming user transcripts.
  • Fakes deleted: iOS constant-0.95 "speech detected" power and synthetic speaking pulse (kept only as the documented fallback for paths with no metering: AVSpeechSynthesizer, compressed streaming), macOS TalkWaveRings/TalkOrbitArcs, all Android static bar rows.
  • Honest fallbacks are typed: speaking(level: nil) means "no envelope available on this path" and renders the synthetic pulse; comments name the platform caps.

User Impact

The talk screen (iOS), talk orb (macOS), voice/dictation screens (Android), watch voice turns, and the voice-note recording row now show one consistent waveform that actually follows your voice while recording/listening and the agent's audio while speaking, on all realtime routes.

Evidence

  • apps/shared/OpenClawKit: swift build + swift test — TalkWaveformMathTests, TalkAudioLevelTests, VoiceNoteRecorderTests (incl. new live-level test) all pass.
  • apps/macos: swift build clean; focused talk tests (TalkAudioPlayer|TalkModeRuntimeSpeech|TalkModeConfigParsing|LowCoverageViewSmoke|TalkModeGatewayConfig) pass — 22 tests, 5 suites.
  • iOS: xcodegen + xcodebuild (OpenClaw scheme incl. the watch target) — BUILD SUCCEEDED. Note: the repo-wide SwiftFormat lint phase fails on current brew swiftformat 0.62.1 due to pre-existing drift in untouched files (LiveActivity, ShareExtension, chat transport, ...); every file in this diff lints clean under 0.62.1.
  • Android: :app:testPlayDebugUnitTest for TalkWaveformMathTest, AudioLevelsTest, VoiceNoteRecorderControllerTest, VoiceScreenLogicTest, TalkModeManagerTest — BUILD SUCCESSFUL.
  • Docs updated: docs/nodes/talk.md macOS overlay description.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: android App: android app: ios App: ios app: macos App: macos size: XL maintainer Maintainer-authored PR labels Jul 9, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ea6268d90b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

case .idle: .idle
case .thinking: .thinking
case .listening: .listening(level: self.level, speechActive: false)
case .speaking: .speaking(level: self.level)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pass nil for unmetered macOS speaking

When macOS speech uses paths without playback metering, such as playMP3 or playSystemVoice, the runtime only switches the phase to .speaking and never publishes a playback level, so TalkOverlayController.model.level remains 0. Passing that as .speaking(level: 0) disables the new TalkWaveformView synthetic fallback, causing MP3/system voice replies to render a flat low-power wave while audio is playing; carry an optional playback level through the overlay or pass nil for those unmetered speaking paths.

Useful? React with 👍 / 👎.

@clawsweeper

clawsweeper Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 9, 2026, 11:03 AM ET / 15:03 UTC.

Summary
The PR replaces platform-specific voice/talk visualizers with shared SwiftUI and Compose waveform implementations and wires microphone, playback, and voice-note level sources across iOS, watchOS, macOS, Android, and docs.

PR surface: Docs 0, Other +1231. Total +1231 across 38 files.

Reproducibility: yes. source inspection gives a high-confidence reproduction path for the blocker: macOS unmetered MP3/system speech sets the phase to speaking, leaves the overlay level at 0, and the PR maps that to .speaking(level: 0) instead of nil.

Review metrics: none identified.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #102895
Summary: The PR is the candidate implementation for the linked open issue requesting a unified real-level talk waveform across platforms.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Fix macOS unmetered speaking so MP3/system voice uses the nil synthetic fallback instead of level 0.
  • Post redacted real behavior proof showing the waveform following live audio on representative changed surfaces.
  • Resolve the base conflicts and rerun the focused platform builds/tests named in the PR body.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body lists builds and focused tests only; it still needs redacted screenshots, recordings, live logs, or other real app output showing the after-fix waveform behavior, and updating the PR body should trigger a fresh ClawSweeper review or a maintainer can comment @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] macOS MP3 and system-voice replies can render a flat low-power wave because unmetered speaking is passed as level 0 instead of nil.
  • [P1] The PR is currently conflicting with base, so maintainers need a refreshed merge result before relying on CI or final file-level review.
  • [P1] The change is visibly cross-platform but the PR body only lists builds and tests, not real waveform behavior proof from a running app.

Maintainer options:

  1. Fix macOS unmetered speaking before merge (recommended)
    Carry optional playback-level state through the macOS overlay or otherwise pass nil for MP3/system-voice speaking so the documented synthetic fallback is preserved.
  2. Accept the flat unmetered waveform
    Maintainers could intentionally accept a flat macOS waveform for unmetered speech paths, but that would contradict the PR's stated fallback contract.
  3. Pause until refreshed and proven
    Because the branch is conflicting and lacks real behavior proof, maintainers can pause the PR until the contributor refreshes it and posts visible runtime evidence.

Next step before merge

  • [P1] The PR has a protected maintainer label, merge conflicts, missing real behavior proof, and a concrete P2 blocker, so it needs contributor/maintainer follow-up rather than an autonomous repair lane.

Security
Cleared: No concrete security or supply-chain concern was found; the diff does not change dependencies, CI, secrets, permissions, or downloaded code execution paths.

Review findings

  • [P2] Pass nil for unmetered macOS speech — apps/macos/Sources/OpenClaw/TalkOverlayView.swift:164
Review details

Best possible solution:

Preserve the shared waveform direction, but carry optional playback-level state through the macOS overlay, resolve the merge conflicts, and add redacted real-device or simulator proof that the visible waveform follows live audio on the affected surfaces.

Do we have a high-confidence way to reproduce the issue?

Yes, source inspection gives a high-confidence reproduction path for the blocker: macOS unmetered MP3/system speech sets the phase to speaking, leaves the overlay level at 0, and the PR maps that to .speaking(level: 0) instead of nil.

Is this the best way to solve the issue?

No, not yet: the shared waveform approach is a maintainable direction, but the macOS overlay needs optional level semantics so unmetered paths keep the documented synthetic speaking fallback.

Full review comments:

  • [P2] Pass nil for unmetered macOS speech — apps/macos/Sources/OpenClaw/TalkOverlayView.swift:164
    The shared waveform only uses its synthetic speaking pulse when the level is nil, but the macOS overlay always passes the non-optional overlay level. playMP3 and playSystemVoice only switch to .speaking, so the level remains 0 and those replies render a flat low-power wave while audio plays; carry an optional level through the overlay or pass nil for unmetered paths.
    Confidence: 0.91

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 36227737c547.

Label changes

Label changes:

  • add P2: This is a normal-priority user-facing voice UI improvement with a concrete macOS behavior blocker and limited blast radius.
  • add merge-risk: 🚨 other: Green unit/build checks would not catch the visible macOS waveform regression on unmetered speech playback paths.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body lists builds and focused tests only; it still needs redacted screenshots, recordings, live logs, or other real app output showing the after-fix waveform behavior, and updating the PR body should trigger a fresh ClawSweeper review or a maintainer can comment @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P2: This is a normal-priority user-facing voice UI improvement with a concrete macOS behavior blocker and limited blast radius.
  • merge-risk: 🚨 other: Green unit/build checks would not catch the visible macOS waveform regression on unmetered speech playback paths.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body lists builds and focused tests only; it still needs redacted screenshots, recordings, live logs, or other real app output showing the after-fix waveform behavior, and updating the PR body should trigger a fresh ClawSweeper review or a maintainer can comment @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Docs 0, Other +1231. Total +1231 across 38 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 1 1 1 0
Config 0 0 0 0
Generated 0 0 0 0
Other 37 1872 641 +1231
Total 38 1873 642 +1231

What I checked:

Likely related people:

  • steipete: Recent GitHub history shows steipete touching the macOS talk overlay, iOS Talk mode, Android Talk mode, and related voice-note surfaces; this PR also continues that same cross-platform voice UI work. (role: recent area contributor and feature owner; confidence: high; commits: cf67e374c0da, d0f655811cdc, d931839e0c12; files: apps/macos/Sources/OpenClaw/TalkOverlayView.swift, apps/macos/Sources/OpenClaw/TalkModeRuntime.swift, apps/ios/Sources/Voice/TalkModeManager.swift)
  • ngutman: Recent iOS Talk history includes merged realtime playback and fallback work, which overlaps the iOS side of this PR's level-metering and Talk route changes. (role: adjacent iOS Talk contributor; confidence: medium; commits: 6897711d1991, 47dbc675e953; files: apps/ios/Sources/Voice/TalkModeManager.swift, apps/ios/Sources/Voice/TalkRealtimeWebRTCSession.swift)
  • NianJiuZst: Recent Android Talk and microphone lifecycle commits include NianJiuZst as author or co-author, making them a plausible reviewer for the Android level-routing side. (role: adjacent Android voice/talk contributor; confidence: medium; commits: a0c0f43ab372, e3f46d0926da; files: apps/android/app/src/main/java/ai/openclaw/app/voice/TalkModeManager.kt, apps/android/app/src/main/java/ai/openclaw/app/voice/MicCaptureManager.kt)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. labels Jul 9, 2026
steipete added 3 commits July 9, 2026 08:05
One shared Siri-style talk animation across iOS, watchOS, macOS, and
Android (TalkWaveformView + exact Compose port), replacing per-platform
fakes: synthetic speaking pulses, constant speech-detected power, static
Android bar rows, flat realtime listening. Listening/recording follow
live mic levels on every route; agent speech follows the real playback
envelope (AVAudioPlayer metering + playback-aligned PCM envelope +
WebRTC stats); voice-note recording shows a live capture wave.
@steipete
steipete force-pushed the claude/voice-animation-universal-ecb6db branch from 9327e49 to b579a6a Compare July 9, 2026 15:06
@steipete
steipete merged commit 20816f6 into main Jul 9, 2026
76 checks passed
@steipete
steipete deleted the claude/voice-animation-universal-ecb6db branch July 9, 2026 15:33
@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Simon-XYDT pushed a commit to Simon-XYDT/openclaw that referenced this pull request Jul 9, 2026
…nclaw#102901)

* feat(voice): universal talk waveform driven by real audio levels

One shared Siri-style talk animation across iOS, watchOS, macOS, and
Android (TalkWaveformView + exact Compose port), replacing per-platform
fakes: synthetic speaking pulses, constant speech-detected power, static
Android bar rows, flat realtime listening. Listening/recording follow
live mic levels on every route; agent speech follows the real playback
envelope (AVAudioPlayer metering + playback-aligned PCM envelope +
WebRTC stats); voice-note recording shows a live capture wave.

* fix(android): order waveform imports and sync native i18n inventory

* chore(i18n): resync native inventory after rebase
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…nclaw#102901)

* feat(voice): universal talk waveform driven by real audio levels

One shared Siri-style talk animation across iOS, watchOS, macOS, and
Android (TalkWaveformView + exact Compose port), replacing per-platform
fakes: synthetic speaking pulses, constant speech-detected power, static
Android bar rows, flat realtime listening. Listening/recording follow
live mic levels on every route; agent speech follows the real playback
envelope (AVAudioPlayer metering + playback-aligned PCM envelope +
WebRTC stats); voice-note recording shows a live capture wave.

* fix(android): order waveform imports and sync native i18n inventory

* chore(i18n): resync native inventory after rebase
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android app: ios App: ios app: macos App: macos docs Improvements or additions to documentation maintainer Maintainer-authored PR merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unify the talk voice animation across iOS/watchOS/macOS/Android and drive it with real audio levels

1 participant