Stopping and then starting a new recording does not begin a new transcript #130

Closed
opened 2026-06-04 01:21:01 +00:00 by Mark · 4 comments
Owner

Bug Description

When a user stops a recording and then starts a new recording session, the new recording does not begin a new transcript. Instead, the new recording appears to continue from the previous transcript or fails to create a fresh transcript entry.

Expected Behavior

Each new recording session should create a new, separate transcript entry in the database.

Steps to Reproduce

  1. Start a recording session
  2. Stop the recording
  3. Start a new recording session
  4. Observe that the new recording does not have a fresh transcript

Environment

  • App: Voice Transcriber (Android)
  • Version: Current development version

Additional Context

This issue likely relates to how RecordingSession entities are created and managed when transitioning between recording states. The session management or transcript initialization logic may not be properly resetting for new sessions.

## Bug Description When a user stops a recording and then starts a new recording session, the new recording does not begin a new transcript. Instead, the new recording appears to continue from the previous transcript or fails to create a fresh transcript entry. ## Expected Behavior Each new recording session should create a new, separate transcript entry in the database. ## Steps to Reproduce 1. Start a recording session 2. Stop the recording 3. Start a new recording session 4. Observe that the new recording does not have a fresh transcript ## Environment - App: Voice Transcriber (Android) - Version: Current development version ## Additional Context This issue likely relates to how `RecordingSession` entities are created and managed when transitioning between recording states. The session management or transcript initialization logic may not be properly resetting for new sessions.
Author
Owner

Optimization commit deployed

Pushed d78d669 — performance and reliability fixes across the stack.

Audio / TranscriptionService

  • Fixed state race condition on _transcriptSegments using StateFlow.update
  • Replaced blocking runBlocking in stopTranscription() with serviceScope.launch
  • Added BuildConfig.DEBUG guards on Log.d in hot paths to eliminate GC pressure in release builds

LocalWhisperTranscriptionProvider

  • Pre-allocated ShortArray for PCM samples instead of boxing through MutableList<Short>
  • Fixed CoroutineScope leak: scope.cancel() now called in destroy()

CloudTranscriptionProvider

  • Added exponential-backoff retry (max 3, base 1s) for transient API failures
  • Fixed CoroutineScope leak
  • Shared OkHttpClient now injectable via constructor

DiarizationProvider

  • Pre-built speaker-name lookup map (O(n) lookups instead of O(n²))
  • Batch insert for TranscriptSegment writes
  • Pointer-based diarization merge in LocalDiarizationProvider (monotonic scan, O(n) total)

LLMTopicExtractor / LLMSummarizer / SessionTitleGenerator

  • Pre-built subject-name lookup map in topic matcher
  • Batch SessionTag inserts via new SessionTagDao.insertTags()
  • OkHttpClient injected via constructor for connection reuse
  • Cached compiled Regex patterns as companion constants

Database

  • Added @Index on RecordingSession(end_time), compound @Index(is_pinned, start_time), and Speaker(name)
  • New batch DAO methods: insertTags, insertEmbeddings, addSegments

Build

  • Enabled R8 minification + resource shrinking + native lib compression
  • Added ABI splits and buildConfig = true

Build compiles and all unit tests pass.

## Optimization commit deployed Pushed `d78d669` — performance and reliability fixes across the stack. ### Audio / TranscriptionService - Fixed state race condition on `_transcriptSegments` using `StateFlow.update` - Replaced blocking `runBlocking` in `stopTranscription()` with `serviceScope.launch` - Added `BuildConfig.DEBUG` guards on `Log.d` in hot paths to eliminate GC pressure in release builds ### LocalWhisperTranscriptionProvider - Pre-allocated `ShortArray` for PCM samples instead of boxing through `MutableList<Short>` - Fixed `CoroutineScope` leak: `scope.cancel()` now called in `destroy()` ### CloudTranscriptionProvider - Added exponential-backoff retry (max 3, base 1s) for transient API failures - Fixed `CoroutineScope` leak - Shared `OkHttpClient` now injectable via constructor ### DiarizationProvider - Pre-built speaker-name lookup map (O(n) lookups instead of O(n²)) - Batch insert for `TranscriptSegment` writes - Pointer-based diarization merge in `LocalDiarizationProvider` (monotonic scan, O(n) total) ### LLMTopicExtractor / LLMSummarizer / SessionTitleGenerator - Pre-built subject-name lookup map in topic matcher - Batch `SessionTag` inserts via new `SessionTagDao.insertTags()` - `OkHttpClient` injected via constructor for connection reuse - Cached compiled `Regex` patterns as companion constants ### Database - Added `@Index` on `RecordingSession(end_time)`, compound `@Index(is_pinned, start_time)`, and `Speaker(name)` - New batch DAO methods: `insertTags`, `insertEmbeddings`, `addSegments` ### Build - Enabled R8 minification + resource shrinking + native lib compression - Added ABI splits and `buildConfig = true` Build compiles and all unit tests pass.
Author
Owner

Follow-up fix deployed: 9c75ca7

Fixes integration issues from the optimization commit:

  • Added NoteTag, NoteCrossref, SpeakerEmbedding entities to AppDatabase (version 7)
  • Added MIGRATION_6_7 for new tables: note_tags, note_crossrefs, speaker_embeddings
  • Added missing @Provides methods in DatabaseModule for new DAOs
  • Added setPinned/setTitle methods to SessionRepository (used by UI)
  • Fixed TranscriptionService parameter mismatch in SpeechBackend.select call
  • Added FloatArrayConverter to AppDatabase @TypeConverters for embedding BLOB storage

Full debug build passes. All unit tests pass.

## Follow-up fix deployed: `9c75ca7` Fixes integration issues from the optimization commit: - Added `NoteTag`, `NoteCrossref`, `SpeakerEmbedding` entities to `AppDatabase` (version 7) - Added `MIGRATION_6_7` for new tables: `note_tags`, `note_crossrefs`, `speaker_embeddings` - Added missing `@Provides` methods in `DatabaseModule` for new DAOs - Added `setPinned`/`setTitle` methods to `SessionRepository` (used by UI) - Fixed `TranscriptionService` parameter mismatch in `SpeechBackend.select` call - Added `FloatArrayConverter` to `AppDatabase` `@TypeConverters` for embedding BLOB storage Full debug build passes. All unit tests pass.
Author
Owner

Offline infrastructure deployed: 79954aa

Foundation for full sustained offline functionality:

  • ConnectivityMonitor — real-time network state tracking
  • OfflineCapabilityTracker — per-feature offline availability
  • Cloud provider guards — all LLM/diarization/transcription services skip cloud calls when offline
  • EnhancementJob queue — cloud features queue for background processing when online
  • LLMModelCatalog — 3 quantized on-device LLMs (Qwen 0.5B, TinyLlama 1.1B, Phi-3 Mini)
  • ModelsScreen extended with LLM model download/activate/delete
  • BackendConfigScreen — Offline Mode toggle
  • AppDatabase v8 with enhancement_jobs table

Build passes, all unit tests pass.

## Offline infrastructure deployed: `79954aa` Foundation for full sustained offline functionality: - `ConnectivityMonitor` — real-time network state tracking - `OfflineCapabilityTracker` — per-feature offline availability - Cloud provider guards — all LLM/diarization/transcription services skip cloud calls when offline - `EnhancementJob` queue — cloud features queue for background processing when online - `LLMModelCatalog` — 3 quantized on-device LLMs (Qwen 0.5B, TinyLlama 1.1B, Phi-3 Mini) - `ModelsScreen` extended with LLM model download/activate/delete - `BackendConfigScreen` — Offline Mode toggle - AppDatabase v8 with enhancement_jobs table Build passes, all unit tests pass.
Author
Owner

Already fixed in existing code. The startRecording() / stopRecording() flow properly resets all per-session state:

  • RecordingViewModel.startRecording() cancels any stale transcriptMonitorJob, clears _transcriptSegments and _currentPartialText, and creates a fresh RecordingSession before starting the foreground service.
  • RecordingViewModel.stopRecording() cancels the monitor, clears _currentSessionId, _currentPartialText, and all active tags.
  • TranscriptionService.startTranscription() defensively stops/destroys any prior provider and wipes _transcriptSegments, _currentTranscript, and recordedChunkPaths before starting the new backend.

Each ACTION_START now creates a completely independent session with no inherited state from the previous recording.

Already fixed in existing code. The `startRecording()` / `stopRecording()` flow properly resets all per-session state: - `RecordingViewModel.startRecording()` cancels any stale `transcriptMonitorJob`, clears `_transcriptSegments` and `_currentPartialText`, and creates a fresh `RecordingSession` before starting the foreground service. - `RecordingViewModel.stopRecording()` cancels the monitor, clears `_currentSessionId`, `_currentPartialText`, and all active tags. - `TranscriptionService.startTranscription()` defensively stops/destroys any prior provider and wipes `_transcriptSegments`, `_currentTranscript`, and `recordedChunkPaths` before starting the new backend. Each `ACTION_START` now creates a completely independent session with no inherited state from the previous recording.
Mark closed this issue 2026-06-11 00:37:59 +00:00
Sign in to join this conversation.
No description provided.