Skip to content

fix: volume control now working correctly#25

Merged
exddc merged 6 commits intomainfrom
fix_volume_control
Mar 3, 2026
Merged

fix: volume control now working correctly#25
exddc merged 6 commits intomainfrom
fix_volume_control

Conversation

@exddc
Copy link
Owner

@exddc exddc commented Mar 3, 2026

Summary by CodeRabbit

  • New Features

    • System version API exposing Chime, OS, and config versions.
    • Web UI shows Chime, OS, and config versions (new version strip).
    • Audio playback now falls back to software volume-scaling when hardware mixer control is unavailable.
  • Chores

    • Project version bumped to 0.1.2; config version bumped to 2.
    • Deployment script can optionally build and include Web UI assets; local build tooling and source discovery adjusted.

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new /api/v1/system/version endpoint (backend + frontend) exposing chime, OS, and config versions; implements amixer probing with a software WAV-scaling fallback and playback-thread cleanup in the aplay audio player; increments version/config values; and updates deploy/local scripts to optionally build Web UI assets.

Changes

Cohort / File(s) Summary
Version Configuration
buildroot/version.env, chime/VERSION
Bumped CHIME_CONFIG_VERSION and updated chime package version string.
Backend API — System Version Endpoint
chime/include/chime/webd_web_server.h, chime/src/webd/web_server.cpp
Added WebServer::HandleGetSystemVersion() and routing for /api/v1/system/version; added file/key-value reading helpers and logic to return JSON with chime_version, os_version, and config_version.
Audio Player Enhancement
chime/include/chime/audio_player.h, chime/src/audio/aplay_audio_player.cpp
Added destructor and thread synchronization members; added amixer probing across candidate controls, in-memory WAV parsing and software volume-scaling, temporary scaled-WAV creation, playback thread cleanup, and fallback flow when amixer fails.
Build & Deployment Scripts
scripts/deploy.sh, scripts/local_chime.sh
Added LOCAL_CHIME_SCRIPT and build_webui_assets; optionally build/deploy Web UI assets when --with-webd is used; adjusted local chime source inclusion/exclusion and added early exit on help.
Frontend — Version Display
webui/src/App.svelte, webui/src/app.css
Added SystemVersionResponse type, state fields and startup fetch for /api/v1/system/version, UI version-strip, and CSS rules for the version strip.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Browser as Browser (Web UI)
  participant Webd as Web Server (webd)
  participant FS as Filesystem
  Browser->>Webd: GET /api/v1/system/version
  Webd->>FS: Read kAppVersionPath or kReleaseInfoPath
  Webd->>FS: Read VIRTUALCHIME_OS_VERSION[_FULL]
  Webd->>FS: Read CHIME_CONFIG_VERSION (key/value fallback)
  Webd-->>Browser: 200 {"chime_version","os_version","config_version"}
Loading
sequenceDiagram
  autonumber
  participant Player as AplayAudioPlayer
  participant Amixer as amixer (hardware)
  participant TempFS as Temp File / WAV
  participant Aplay as aplay (process)
  Player->>Amixer: TrySetVolumeWithAmixer(volume)
  alt Amixer succeeds
    Amixer-->>Player: success (control)
    Player->>Aplay: spawn aplay with original file
  else Amixer fails and volume < 100%
    Player->>Player: Scale PCM WAV in-memory -> CreateSoftwareScaledWav()
    Player->>TempFS: write temp WAV
    Player->>Aplay: spawn aplay with temp WAV
    Player->>TempFS: cleanup temp WAV after playback
  end
  Aplay-->>Player: playback complete / error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰 I hop through bytes and WAVs so bright,
I sniff the mixer, tweak the night,
Versions dotted, shown in view,
Chime, OS, Config — tidy and new,
I nibble bugs and bound with delight.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.03% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'fix: volume control now working correctly' focuses narrowly on volume control, but the changeset encompasses multiple features beyond that: system version endpoint, version bumps, web UI updates, and deployment script enhancements. Consider whether the title should reflect the broader scope (e.g., 'feat: add system version endpoint and improve volume control') or if volume control is truly the primary change requiring clarification.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix_volume_control

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (2)
scripts/deploy.sh (1)

211-216: Prefer invoking the helper script via bash instead of requiring execute bit.
Line 212 uses -x; this can fail on checkouts where mode bits are lost even though the script exists and is valid.

Suggested patch
 build_webui_assets() {
-    [ -x "$LOCAL_CHIME_SCRIPT" ] || error "Local build script not found at $LOCAL_CHIME_SCRIPT"
+    [ -f "$LOCAL_CHIME_SCRIPT" ] || error "Local build script not found at $LOCAL_CHIME_SCRIPT"
     log "Building web UI assets..."
-    "$LOCAL_CHIME_SCRIPT" webui-build
+    bash "$LOCAL_CHIME_SCRIPT" webui-build
     [ -d "$WEBUI_DIST_DIR" ] || error "Web UI build completed but dist directory missing at $WEBUI_DIST_DIR"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/deploy.sh` around lines 211 - 216, In build_webui_assets, the script
should not require the execute bit on $LOCAL_CHIME_SCRIPT; replace the -x check
with a file existence/readability check (e.g., -f or -r) and invoke the helper
explicitly with bash (bash "$LOCAL_CHIME_SCRIPT" webui-build) instead of calling
it directly; keep the existing failure branches but update the error message to
reference inability to run the script via bash if invocation fails, and still
validate the $WEBUI_DIST_DIR after the build.
webui/src/App.svelte (1)

446-454: Avoid fully silent failure for system-version fetch.

The fallback is correct, but the catch currently suppresses all visibility into why it failed. Please keep fallback behavior and add a lightweight warning for troubleshooting.

🔧 Minimal observability improvement
-          loadSystemVersion().catch(() => {
+          loadSystemVersion().catch((error) => {
             chimeVersion = "unknown";
             osVersion = "unknown";
             configVersion = "unknown";
+            console.warn("Failed to load /api/v1/system/version", error);
           }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@webui/src/App.svelte` around lines 446 - 454, The catch on the
loadSystemVersion() call silently swallows errors; keep the fallback assignments
to chimeVersion/osVersion/configVersion but also emit a lightweight warning with
the error to aid troubleshooting. Modify the catch attached to
loadSystemVersion() (the Promise.all entry calling
loadSystemVersion().catch(...)) to console.warn (or use the app logger if
available) with a short message like "loadSystemVersion failed" and include the
caught error object, then still set chimeVersion/osVersion/configVersion =
"unknown". Ensure you only add minimal logging and do not change the existing
fallback behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@chime/src/audio/aplay_audio_player.cpp`:
- Around line 114-124: The WAV chunk bounds check can overflow when computing
chunk_end = chunk_data + chunk_size; update the check to first validate
chunk_size against SIZE_MAX and the remaining buffer length so addition cannot
wrap: compute chunk_data = chunk_header + 8, then if
(static_cast<std::size_t>(chunk_size) > wav_bytes->size() - chunk_data) { set
error and return false; } (avoid performing chunk_data + chunk_size until after
this safe check and only then compute chunk_end = chunk_data +
static_cast<std::size_t>(chunk_size)). Apply the same pattern to the other
occurrences that use chunk_header/chunk_size/chunk_data/chunk_end (the later
blocks around the sample-scaling code).
- Around line 1-16: The file aplay_audio_player.cpp is failing CI due to
formatting; run clang-format (project style) on that translation unit (e.g.,
clang-format -i aplay_audio_player.cpp) and commit the reformatted file so
include ordering/spacing and function bodies (around the audio playback
implementation that uses symbols from chime::audio_player / any aplay_*
functions) match the project's style; ensure you reformat the entire file
including the include block and the code regions flagged in CI so clang-format
no longer fails.
- Around line 214-224: The code currently calls mkstemp(temp_path) to get a
secure file descriptor (fd) but then closes fd and later reopens the file path
via WriteFileBytes, creating a TOCTOU race; instead use the fd returned by
mkstemp directly (or fdopen) to write wav_bytes and avoid closing/reopening the
path. Update the sequence around mkstemp/temp_path/fd so WriteFileBytes no
longer reopens by path but writes to the existing fd (or accept a new helper
that takes fd), then close and optionally unlink the file descriptor after the
write is complete.

In `@chime/src/webd/web_server.cpp`:
- Around line 49-50: The file fails the clang-format CI check; run the
repository's configured clang-format (same version as CI) on the source
containing the constants kReleaseInfoPath and kAppVersionPath and the other
affected sections (around functions/blocks that include lines ~267-315,
~960-968, ~1207-1233) to apply the project's style rules, then stage and commit
the formatted file so the CI check passes; ensure you do not change logic, only
formatting.

---

Nitpick comments:
In `@scripts/deploy.sh`:
- Around line 211-216: In build_webui_assets, the script should not require the
execute bit on $LOCAL_CHIME_SCRIPT; replace the -x check with a file
existence/readability check (e.g., -f or -r) and invoke the helper explicitly
with bash (bash "$LOCAL_CHIME_SCRIPT" webui-build) instead of calling it
directly; keep the existing failure branches but update the error message to
reference inability to run the script via bash if invocation fails, and still
validate the $WEBUI_DIST_DIR after the build.

In `@webui/src/App.svelte`:
- Around line 446-454: The catch on the loadSystemVersion() call silently
swallows errors; keep the fallback assignments to
chimeVersion/osVersion/configVersion but also emit a lightweight warning with
the error to aid troubleshooting. Modify the catch attached to
loadSystemVersion() (the Promise.all entry calling
loadSystemVersion().catch(...)) to console.warn (or use the app logger if
available) with a short message like "loadSystemVersion failed" and include the
caught error object, then still set chimeVersion/osVersion/configVersion =
"unknown". Ensure you only add minimal logging and do not change the existing
fallback behavior.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3825b9b and 58ffe5d.

📒 Files selected for processing (9)
  • buildroot/version.env
  • chime/VERSION
  • chime/include/chime/webd_web_server.h
  • chime/src/audio/aplay_audio_player.cpp
  • chime/src/webd/web_server.cpp
  • scripts/deploy.sh
  • scripts/local_chime.sh
  • webui/src/App.svelte
  • webui/src/app.css

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@chime/src/audio/aplay_audio_player.cpp`:
- Around line 173-183: In the bits_per_sample == 16 branch (the loop that
iterates with i += 2 using data_size, data_offset and wav_bytes), add an
explicit validation that data_size is even and treat an odd data_size as
malformed input (e.g., return false or propagate an error) instead of silently
truncating the last byte; perform this check before the loop and reference the
same variables (bits_per_sample, data_size, data_offset, wav_bytes) and the
WriteLe16 path so the function consistently rejects odd-sized 16-bit PCM chunks.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58ffe5d and 8d3e2c1.

📒 Files selected for processing (4)
  • chime/src/audio/aplay_audio_player.cpp
  • chime/src/webd/web_server.cpp
  • scripts/deploy.sh
  • webui/src/App.svelte
🚧 Files skipped from review as they are similar to previous changes (1)
  • webui/src/App.svelte

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@chime/src/audio/aplay_audio_player.cpp`:
- Around line 297-340: The detached lambda captures this and accesses logger_
and playing_, causing use-after-free if AplayAudioPlayer is destroyed during
playback; fix by making playback thread a member (e.g., add std::thread
playback_thread_ in AplayAudioPlayer), start it without detach (assign to
playback_thread_), and join it in AplayAudioPlayer::~AplayAudioPlayer() to
ensure safe teardown; additionally, copy all needed variables (path,
effective_volume) into the lambda by value and avoid using member state inside
the thread (use local temporaries instead of logger_/playing_ or provide
thread-safe access) or use the weak_ptr capture pattern if you prefer shared
ownership.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d3e2c1 and 038ed10.

📒 Files selected for processing (1)
  • chime/src/audio/aplay_audio_player.cpp

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@chime/src/audio/aplay_audio_player.cpp`:
- Around line 312-355: The playback lambda (playback_thread_) can throw and
leave playing->store(false) unexecuted; wrap the entire lambda body in a
try/catch that catches std::exception and a catch(...) fallback, log the
exception via logger->Error, and always run cleanup in a finally-like scope
(ensure playing->store(false) and removal of temporary_scaled_path happen even
on exception); reference the existing symbols playback_thread_, playing,
temporary_scaled_path, TrySetVolumeWithAmixer, CreateSoftwareScaledWav,
std::remove and ensure any resources are cleaned and errors logged before
rethrowing or swallowing as appropriate.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 038ed10 and 4597999.

📒 Files selected for processing (2)
  • chime/include/chime/audio_player.h
  • chime/src/audio/aplay_audio_player.cpp

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
chime/src/audio/aplay_audio_player.cpp (1)

265-274: Consider logging which controls failed before returning empty result.

When all mixer controls fail, debugging audio issues could be easier if individual failures were logged at debug level. Currently, only a summary warning is logged later in Play().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@chime/src/audio/aplay_audio_player.cpp` around lines 265 - 274, In
TrySetVolumeWithAmixer, iterate kMixerControlCandidates as now but on each
nonzero system() result emit a debug-level log recording the control_name and
the failed amixer command (use the project's existing logger used in Play(),
e.g., processLogger or the module logger) before continuing; if all fail, the
function should still return {} but now the per-control failures are logged to
aid debugging. Ensure the log message includes the control name and the
attempted command or return code so Play()'s summary warning has detailed prior
context.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@chime/src/audio/aplay_audio_player.cpp`:
- Around line 265-274: In TrySetVolumeWithAmixer, iterate
kMixerControlCandidates as now but on each nonzero system() result emit a
debug-level log recording the control_name and the failed amixer command (use
the project's existing logger used in Play(), e.g., processLogger or the module
logger) before continuing; if all fail, the function should still return {} but
now the per-control failures are logged to aid debugging. Ensure the log message
includes the control name and the attempted command or return code so Play()'s
summary warning has detailed prior context.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4597999 and fb97de2.

📒 Files selected for processing (1)
  • chime/src/audio/aplay_audio_player.cpp

@exddc exddc merged commit c8a63a5 into main Mar 3, 2026
4 checks passed
@exddc exddc deleted the fix_volume_control branch March 3, 2026 14:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant