Skip to content

fix: prevent WAL files from getting future timestamps during SD card sync#4842

Closed
mdmohsin7 wants to merge 2 commits intomainfrom
fix/wal-future-timestamps
Closed

fix: prevent WAL files from getting future timestamps during SD card sync#4842
mdmohsin7 wants to merge 2 commits intomainfrom
fix/wal-future-timestamps

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

Problem

WAL files created during SD card sync sometimes get future timestamps. The backend rejects files with future dates, causing users to get stuck in an infinite sync loop — WALs can never be synced because their timestamps are in the future.

Root Causes

1. timerStart incremented before first chunk flush

In both BLE and WiFi chunk loops, timerStart += sdcardChunkSizeSecs (60s) was executed before the first chunk was written. This shifted every chunk's timestamp 60 seconds into the future.

2. Remainder chunk adds unnecessary 60 seconds

After the chunk loop, any remaining partial data also added a full 60 seconds to timerStart, even though the data might contain only a few seconds of audio. Combined with issue #1, this caused the final timestamp to overshoot DateTime.now().

Example: 65 seconds of audio → timerStart starts at now - 65, increments total 120s → final timestamp = now + 55 (55 seconds in the future!)

3. BLE path hardcoded 100 fps

chunkSize = sdcardChunkSizeSecs * 100 assumed 100 fps, but the production Omi device uses opusFS320 codec at 50 fps. This made BLE chunks contain 120s of audio while timestamps only advanced 60s, creating wrong timestamp ranges. The WiFi path already used wal.codec.getFramesPerSecond() correctly.

Fix

  1. Move timerStart += sdcardChunkSizeSecs to after the flush call in both BLE and WiFi chunk loops
  2. Remove timerStart += sdcardChunkSizeSecs from remainder handling in both paths (timerStart is already correct after the loop)
  3. Replace hardcoded 100 with wal.codec.getFramesPerSecond() in BLE chunk size calculation

Minimal diff: 1 file changed, 3 insertions, 5 deletions.

…sync

Three fixes in sdcard_wal_sync.dart:

1. Move timerStart increment to AFTER flush in both BLE and WiFi chunk
   loops. Previously, timerStart was incremented BEFORE writing the first
   chunk, shifting all timestamps forward by 60 seconds.

2. Remove timerStart increment from remainder (partial) chunk handling
   in both BLE and WiFi paths. The remainder should use the current
   timerStart as-is, not add another 60 seconds.

3. Replace hardcoded 100 fps with wal.codec.getFramesPerSecond() in BLE
   path chunk size calculation. The hardcoded value was wrong for
   opusFS320 codec (50 fps), causing chunks to contain 120s of audio
   while timestamps only advanced 60s.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly addresses a critical bug that caused future timestamps on WAL files during SD card sync, which could lead to infinite sync loops. The changes properly adjust the timestamp logic for both BLE and WiFi sync paths by moving the timestamp increment to after chunk processing and using the correct frame rate for chunk size calculation. My review identified a critical flaw in the error handling within the WiFi sync path, where suppressed exceptions could lead to data corruption. The detailed comment with a suggested fix to re-throw these exceptions has been retained as it aligns with best practices for robust error handling.

try {
var file = await _flushToDisk(wal, chunk, timerStart);
await _registerSingleChunk(wal, file, timerStart);
timerStart += sdcardChunkSizeSecs;
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.

critical

While moving the timestamp increment to after a successful flush is correct, the error handling in the surrounding try-catch block (lines 1141-1147) has a critical flaw. If an error occurs in the try block before this line, the exception is caught and suppressed. The loop continues, but since timerStart was not incremented, the next chunk of data will be processed with a stale timestamp, leading to data corruption.

A similar issue exists for the final chunk handling (lines 1153-1158). An error there is also suppressed, leading to silent data loss.

Both exceptions should be re-thrown to terminate the sync gracefully.

Suggested changes:

  1. For the main loop:
// Suggested change for lines 1141-1147
try {
  var file = await _flushToDisk(wal, chunk, timerStart);
  await _registerSingleChunk(wal, file, timerStart);
  timerStart += sdcardChunkSizeSecs;
} catch (e) {
  Logger.debug('SDCardWalSync WiFi: Error flushing chunk: $e');
  rethrow;
}
  1. For the final chunk:
// Suggested change for lines 1153-1158
try {
  var file = await _flushToDisk(wal, chunk, timerStart);
  await _registerSingleChunk(wal, file, timerStart);
} catch (e) {
  Logger.debug('SDCardWalSync WiFi: Error flushing final chunk: $e');
  rethrow;
}

@beastoin
Copy link
Copy Markdown
Collaborator

Hey 👋 — looking forward to seeing this come together! When you are ready to move this out of draft, a quick demo (screenshot, video, or terminal output) showing it working on your local/dev environment would be great.

In the AI era, writing code is the easy part — a live demo is the minimum bar for a good PR. No rush since it is still a draft, just a heads-up! 🙏

@beastoin
Copy link
Copy Markdown
Collaborator

@mdmohsin7 There hasn't been any activity on this draft for 3+ days; to keep the repo current, closing this now. Reopen when it's ready.


by AI for @beastoin

@beastoin beastoin closed this Mar 10, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Hey @mdmohsin7 👋

Thank you so much for taking the time to contribute to Omi! We truly appreciate you putting in the effort to submit this pull request.

After careful review, we've decided not to merge this particular PR. Please don't take this personally — we genuinely try to merge as many contributions as possible, but sometimes we have to make tough calls based on:

  • Project standards — Ensuring consistency across the codebase
  • User needs — Making sure changes align with what our users need
  • Code best practices — Maintaining code quality and maintainability
  • Project direction — Keeping aligned with our roadmap and vision

Your contribution is still valuable to us, and we'd love to see you contribute again in the future! If you'd like feedback on how to improve this PR or want to discuss alternative approaches, please don't hesitate to reach out.

Thank you for being part of the Omi community! 💜

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.

2 participants