Session Review — Developer Guide¶
Technical documentation for the session review system.
Overview¶
The session review screen (session_review_screen.dart) provides post-session analysis of bird detection data. It operates on a LiveSession object and supports playback, editing, manual species addition, annotations, recording trimming, and export.
File Structure¶
lib/features/history/
session_review_screen.dart # Main screen + state management
session_export.dart # Export logic (CSV, JSON, Raven Pro, ZIP)
widgets/
session_review_widgets.dart # Private widget classes (part file)
Data Models¶
DetectionRecord¶
Stored in lib/features/live/live_session.dart:
| Field | Type | Description |
|---|---|---|
scientificName |
String |
Species scientific name |
commonName |
String |
Species common name (English) |
confidence |
double |
0.0–1.0 confidence score |
timestamp |
DateTime |
Wall-clock detection time |
audioClipPath |
String? |
Path to audio clip (optional) |
source |
DetectionSource |
auto (model) or manual (user-added) |
Static constants unknownSpeciesName and unknownCommonName are used for unknown/unidentifiable species.
SessionAnnotation¶
| Field | Type | Description |
|---|---|---|
text |
String |
Free-form annotation text |
createdAt |
DateTime |
When the annotation was created |
offsetInRecording |
double? |
Seconds from session start (null = global) |
LiveSession Extensions¶
| Field | Type | Default | Description |
|---|---|---|---|
annotations |
List<SessionAnnotation> |
[] |
User annotations |
trimStartSec |
double? |
null |
Trim start offset (seconds) |
trimEndSec |
double? |
null |
Trim end offset (seconds) |
Detection Counting (Live Mode)¶
Detection accumulation during live sessions uses card-visibility-based counting rather than time-window merging:
- The
LiveControllermaintains_activeCardSpecies: Map<String, DetectionRecord>tracking species with visible cards. - Each inference cycle determines three sets:
- Appeared: species in current detections but not in active set → new
DetectionRecord - Ongoing: species in both → update confidence if higher
- Disappeared: species in active set but not current → remove from tracking
- Only
appearedspecies create new detection records. This means a bird calling continuously counts as one detection, and a gap (card removal + reappearance) creates a second detection.
Spectrogram¶
The review spectrogram is computed dynamically to balance RAM usage and CPU performance, especially for long sessions:
- Standard Rendering (Sessions < 128 MB Decoded PCM):
- The entire audio file is decoded and resampled to the model's sample rate (32 kHz).
- The spectrogram is pre-computed as a single full-session
ui.Imageusing a 2048-point FFT (yielding ~12 Hz/bin frequency resolution, showing formants and harmonics clearly) with a 1024-point hop. -
_ReviewSpectrogramPainterblits a 10-second viewport centered on the playback position, with aTickeranimating playhead movements at up to 60 fps. -
Lazy Chunk Loading (Sessions ≥ 128 MB Decoded PCM): To prevent massive RAM allocations and out-of-memory crashes on hour-long sessions, the app uses a lazy-loading tile pipeline:
- The session is divided into 30-second chunks. Only chunks visible in (or immediately adjacent to) the current viewport are loaded.
- Up to 12 chunks are cached in memory; older/farthest chunks are evicted dynamically.
-
The decode and FFT calculations run inside a background isolate (
Isolate.run/_runSpectrogramChunkIsolate) to prevent the UI thread from dropping frames during scroll or pinch-to-zoom actions. -
FLAC-to-WAV Transcoding Optimization: FLAC files do not have a constant-bitrate layout or a seek table, meaning range-decoding requires sequentially decoding the file from the beginning—leading to O(N²) time complexity for lazy chunk loading on long sessions. To avoid this:
- If a session is large (≥ 128 MB PCM) and recorded in FLAC format, the app runs a one-time sequential transcode to a temporary WAV file in a background isolate (
_runFlacTranscodeIsolate). - The lazy spectrogram pipeline then uses the temporary WAV file, enabling fast O(1) random-access seek-and-read operations for individual chunks.
- The temporary WAV file is session-scoped and deleted when the review screen is disposed.
Trim System¶
Trimming is metadata-only — the original recording is not modified:
_TrimOverlayrenders draggable start/end handles over the spectrogram._TrimOverlayPainterdraws dimmed regions and handle graphics.- Apply Trim: removes detections outside
[trimStartSec, trimEndSec]from_detections, updates_speciesGroups, marks dirty. - Reset Trim: sets both offsets to null.
- The export system includes
trimStartSec/trimEndSecin JSON output.
Add Species Overlay¶
_AddSpeciesOverlay is a full-screen route using TaxonomyService.search():
- Search: real-time substring match on common + scientific names (limit 30).
- Insert modes: global (at session start), at timestamp (playhead position), replace (swaps an existing detection).
- Unknown/Other: quick action using
DetectionRecord.unknownSpeciesName. - Returns
_AddSpeciesResultwith the chosen species and mode.
Annotations¶
_AnnotationsSection provides a collapsible section:
- Input field with global/timestamp toggle.
- Each annotation stored as
SessionAnnotationin the session. - Exported as
annotations.txtin ZIP bundles. - Persisted to JSON alongside detections.
Export Pipeline¶
session_export.dart builds export files:
| Format | Function | Notes |
|---|---|---|
| CSV | _buildCsvExport() |
Header + rows, tab-delimited |
| JSON | buildJsonExport() |
Full session data including annotations, trim, source |
| Raven Pro | _buildRavenExport() |
Selection table format |
| ZIP | Bundle mode | Recording + CSV + JSON + Raven + annotations.txt |
The _buildAnnotationsText() helper formats annotations as plain text with timestamp labels.
Session Lifecycle (App Focus)¶
WidgetsBindingObserver on _LiveScreenState:
paused/inactive→ auto-pause session, set_pausedByLifecycle = trueresumed→ auto-resume if_pausedByLifecycle- 10-minute
Timertriggers a continue/stop dialog
Localization¶
All user-facing strings use ARB keys prefixed with session:
sessionAddSpecies,sessionSearchSpecies,sessionInsertGlobally, etc.sessionAnnotations,sessionAddAnnotation,sessionAnnotationGlobalsessionTrimRecording,sessionTrimApply,sessionTrimReset,sessionTrimWarningsessionHelpTitle,sessionHelpOverview,sessionHelpAddSpecies, etc.sessionDurationWarningTitle,sessionDurationWarningMessage,sessionContinue
Translations are provided in all UI locale ARB files: English, German, Czech, Spanish, French, Italian, and Portuguese.