Repository navigation
Keep a segment's boundary time from overflowing and resync a source after its ASRC refuses - #95
Merged
Merged
Conversation
…fter its ASRC refuses A segment's elapsed time from T0 was one int64 count of picoseconds, which overflows after about 106.7 days of one anchor. It is now whole seconds plus the picoseconds past them, carried at each segment, so the boundary keeps its picosecond precision for any run; the math still runs only per format change and per instance start. When a live source sink's ASRC refused a chunk, the chunk was written unaltered but the ASRC's position did not move with it, so the start of its next output was cut as already written. The sink now restarts the correction after a refusal, engaged or not. Closes #24
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The focused fixes address both reported faults with targeted regression coverage and no identified blocking issues.
0 open findings
What changed in this PR
Addresses #24 by preventing long-running segment boundary overflow and restarting live-source correction after a resampler refusal. The separate within-segment overflow remains tracked in #94.
Changes:
- Splits boundary elapsed time into seconds and picoseconds while preserving rounding.
- Restarts correction after writing a refused chunk unaltered.
- Adds regression tests and extracts a shared sink test fixture.
| File | Description |
|---|---|
| tests/test_source_sink.cpp | Uses the shared sink fixture. |
| tests/test_source_sink_internals.cpp | Tests refusal recovery before and after correction starts. |
| tests/test_sched_timeline.cpp | Tests long-duration boundaries, rounding and carry. |
| tests/source_sink_rig.h | Provides the shared sink fixture and tone helpers. |
| tests/CMakeLists.txt | Registers white-box refusal tests. |
| src/source_sink.h | Documents correction restarts. |
| src/source_sink.cpp | Resets correction after resampler refusal. |
| src/source_clock.h | Clarifies the produced-frame counter documentation. |
| src/sched/timeline.h | Stores split boundary elapsed time. |
| src/sched/timeline.cpp | Accumulates and rounds split boundary time. |
| CLAUDE.md | Documents the shared test fixture. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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.
Summary
Two rare faults from #24: a segment's boundary time overflowed after about 106.7 days of one anchor, and a live source lost up to a chunk of audio after its ASRC refused one.
Change
sched::Segmentholds its time fromT0aselapsed_spluselapsed_ps(the picoseconds past the whole seconds, below 10^12) instead of one int64 count of picoseconds.add_segment()carries the remainder into the seconds;segment_output_index()rounds the absolute boundary instant as before, so rounding still never accumulates across segments and picosecond precision stays.add_segment()(perset_format()and anchor build) andsegment_output_index()(per instance start and format boundary): no multiply or divide is added per sample, cell or frame, andsegment_output_index()loses two divides.LiveSourceSink::correct(): when the ASRC refuses a chunk, the chunk is written unaltered and the correction restarts (engaged or not), instead of advancingwritten_past an ASRC position that did not move, which cut the next output.SinkRigmoves totests/source_sink_rig.h, shared by the sink's two test files. Folded:SourceAsrc::produced()'s doc now mentionsreset().offset_us()andtime_position()within one segment after about 278 days at 384 kHz, which runs per frame: Keep a segment's time and position math from overflowing in a run of months #94.Tests
SchedTimeline.SegmentOutputIndexMonthsIntoARun: a Control row at one hour, rows just under and past the old limit (106 and 107 days), a floored remainder, half-up rounding of the remainder and a carry into a whole second, asserting the split fields and the output index. Before the change the 107-day rows trip UBSan's signed overflow.LiveSourceSink.StartsTheCorrectionOverAfterTheAsrcRefusesand...BeforeIt(newtest_source_sink_internals.cpp, white-box): a chunk refused once the correction has started, and one refused before it; both fail before the change (about a chunk lost). The refusal is forced by a zero block size, since no real input makes micro-resampler refuse.Closes #24
Related: #94