Skip to content

feat(player): measure the bitrate while the track plays - #26

Merged
InstaZDLL merged 1 commit into
mainfrom
feat/live-bitrate
Oct 31, 2026
Merged

InstaZDLL merged 1 commit into
mainfrom
feat/live-bitrate

Conversation

@InstaZDLL

@InstaZDLL InstaZDLL commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Why

The bitrate chip showed the tags' figure, which lofty computes as the whole file's average and which never moves. A FLAC that opens on a quiet passage showed the same low number through its loud middle (reported: 524 kbps where the music runs around 1574 kbps).

What

  • waveflow-core bumped to 14ff457b (feat(core): count the bytes and frames a stream has decoded WaveFlow#997), which adds ActiveStream::packets_read: running totals of the compressed bytes and source frames of the packets decoded.
  • src/audio/bitrate.rs: BitrateMeter turns two readings of those totals into kbps once they hold a second of audio; BitrateQueue holds each reading until the output clock reaches it, as the spectrum frames wait.
  • The decoder takes a reading after each packet and restarts the window on a seek. The UI shows the live value and falls back to the tags until the first reading. A pause keeps the last value. DSD keeps the tags' figure, since its rate is constant.
  • docs/ARCHITECTURE.md: one bullet on how the chip is measured.

Tested

  • cargo fmt --check, cargo clippy --locked --all-targets -- -D warnings, cargo test --locked (78 tests, 4 new) on Windows.
  • Generated FLAC (5 s of silence, then noise): the tags give 443 kbps, live readings give 1 kbps during the silence and about 664 kbps during the noise, matching ffprobe -show_packets sums (about 660).
  • In the app (window capture): the chip reads 1 kbps at 0:03 and 215 kbps at 0:09 on a second test file, where the tags would show 148 kbps throughout.
  • Core bump, decoded to the end at 48 kHz: FLAC 44.1 kHz (199 089 ms, readings 845–1868 kbps), MP3 CBR (192 kbps throughout), DSD64 DSF (no readings, as intended), FLAC over a UNC path (\localhost\J$\…).
  • Not tested on Linux or macOS beyond what CI runs.

Summary by CodeRabbit

  • Nouvelles fonctionnalités
    • Le débit binaire s’affiche désormais en temps réel pendant la lecture, à mesure que les données audio sont lues. Avant la première mesure, l’application indique le débit moyen fourni par les métadonnées du fichier. En pause, elle conserve la dernière mesure disponible.
    • Pour certains fichiers, notamment ceux qui commencent par du silence, le débit affiché peut évoluer après le début de la lecture.

The format chip showed the tags' bitrate, the whole file's average: a
FLAC that opens on a quiet passage read the same low figure through its
loud middle. The decoder now sums the compressed bytes and frames of the
packets it decodes (waveflow-core's new `ActiveStream::packets_read`) and
takes a reading per second of audio, due when that second plays, as the
spectrum frames are. The tags' figure shows until the first reading; a
pause keeps the last one, a seek starts the window afresh. DSD keeps its
tags, its rate is constant.

Bumps waveflow-core to 14ff457b (WaveFlow #997), which adds the tally.
@github-actions github-actions Bot added scope: ui Windows, widgets, player and playlist panes, settings page (src/ui, app.rs, platform.rs) scope: deps Dependencies (Cargo.toml, Cargo.lock, toolchain) scope: docs Docs, README, release notes scope: audio Playback pipeline, decoding, library reads, lyrics, queue type: feat New feature size: l 200-500 lines labels Oct 31, 2026
@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 64a8803 and 12a5c9e.

Files ignored due to path filters: 1
  • Cargo.lock is excluded by !**/*.lock, !Cargo.lock, !*.lock
Files selected for processing: 7
  • Cargo.toml
  • docs/ARCHITECTURE.md
  • src/app.rs
  • src/audio/bitrate.rs
  • src/audio/decoder.rs
  • src/audio/mod.rs
  • src/audio/state.rs

Included review availability: This review used your included allowance. 0 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Walkthrough

L’application calcule le débit à partir des paquets lus pendant le décodage. Elle synchronise chaque mesure avec la position de lecture et affiche la dernière mesure arrivée à échéance, ou le débit moyen des métadonnées en l’absence de mesure.

Changes: Débit en temps réel

Layer / File(s) Summary
Calcul et mise en file des mesures
src/audio/bitrate.rs, src/audio/mod.rs
BitrateMeter calcule le débit sur des fenêtres d’au moins une seconde d’audio. BitrateQueue conserve au plus 32 mesures associées à leur position de lecture. Les tests couvrent le calcul, la réinitialisation et la sélection des mesures arrivées à échéance.
Production et synchronisation des mesures
src/audio/decoder.rs, src/audio/state.rs, Cargo.toml
La session de décodage mesure les paquets lus et met les résultats en file selon les échantillons attendus. SharedPlayback récupère les mesures dues et vide la file lors de la réinitialisation de l’horloge. La révision Git de waveflow-core est mise à jour.
Affichage du débit mesuré
src/app.rs, docs/ARCHITECTURE.md
L’application met à jour le débit affiché pendant la lecture. Elle privilégie cette mesure au débit moyen des métadonnées et la réinitialise au changement ou à l’effacement du morceau. La documentation décrit aussi le comportement en pause et avant la première mesure.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Session
  participant BitrateMeter
  participant SharedPlayback
  participant QuickPlayApp
  Session->>BitrateMeter: fournit les paquets lus et le taux d’échantillonnage
  BitrateMeter->>Session: retourne une mesure disponible
  Session->>SharedPlayback: met en file la mesure et sa position d’échéance
  QuickPlayApp->>SharedPlayback: récupère la mesure due pendant la lecture
  SharedPlayback->>QuickPlayApp: retourne la mesure due
Loading

Possibly related PRs

Suggested labels: type: feat, scope: ui, scope: deps, scope: docs, size: m

Merge Risk: Low · up to 12a5c

Seeking can temporarily show the previous position’s bitrate. Playback is unaffected, so the change is mergeable with awareness of this limitation.

Security architecture risk: Low · up to 12a5c

The inspected application changes keep bitrate measurements inside the player, with bounded memory use and no identified expansion of privileges or external access. The accompanying playback-library update could not be fully verified, so some uncertainty remains.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The inspected application-side exposure is confined to the existing player process and its playback display. No new tenant, service, credential, or persistent-data authority was identified in this flow. This conclusion does not establish the exposure of uninspected changes in the updated playback library.

Trust Boundaries and Controls

  • observed — The decoder produces readings and the UI consumes them under the shared queue mutex. Queue insertion and seek cleanup occur on the decoder thread, preventing a pre-seek producer operation from running after that seek's cleanup. A UI value already consumed can remain visible, but consuming a value cannot reinsert it into the queue.

Resilience and Maintainability Implications

  • observed — The bitrate queue holds at most 32 readings and evicts the oldest at capacity. Consumption removes superseded due readings. The audio callback does not acquire the new queue mutex, limiting memory growth and avoiding a new lock dependency on the real-time output path.
Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed Le titre décrit précisément l’ajout principal : la mesure du débit pendant la lecture. Il respecte aussi le format Conventional Commits avec le scope player.
Description check Passed La description explique clairement le problème, la solution, les changements techniques et les tests réalisés. Elle ne reprend pas tous les intitulés du modèle et ne fournit pas de checklist complète …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

La description explique clairement le problème, la solution, les changements techniques et les tests réalisés. Elle ne reprend pas tous les intitulés du modèle et ne fournit pas de checklist complète ni de lien GitHub formel, mais les informations principales sont présentes et suffisamment détaillées.

Full details: Docstring Coverage

Explanation

Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 10 functions across 5 files. (2 skipped: 2 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@InstaZDLL
InstaZDLL merged commit 813ad9f into main Oct 31, 2026
6 checks passed
@InstaZDLL
InstaZDLL deleted the feat/live-bitrate branch October 31, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: audio Playback pipeline, decoding, library reads, lyrics, queue scope: deps Dependencies (Cargo.toml, Cargo.lock, toolchain) scope: docs Docs, README, release notes scope: ui Windows, widgets, player and playlist panes, settings page (src/ui, app.rs, platform.rs) size: l 200-500 lines type: feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant