Device Meeting Flow
This document describes the complete process of starting and managing a meeting session from an ESP32 device, including audio chunk upload, automatic finalisation, and coordination with recording status.Overview
The device meeting flow allows ESP32 devices to start recording sessions, upload audio in chunks for real-time transcription, and automatically finalise recordings when the session stops. The flow coordinates between device session management and audio chunk processing:- Device Starts Session: Creates a session record and sets recording status to “recording” in Redis
- Audio Chunk Upload: Device uploads audio chunks during recording for real-time transcription
- Device Stops Session: Automatically triggers finalisation of chunks, creates stitched audio, and sets recording status to “inactive”
Complete Meeting Flow
Device-Side Flow
Step 1: Start Session
The device initiates a recording session by calling the start session endpoint. Endpoint:POST /devices/{device_id}/session/start
Prerequisites:
- Device must be paired (have a
user_id) - Device should not have an active session (
active_session_idshould benull)
start_session_impl):
- Device Validation: Verifies device exists and is paired
- User Verification: Confirms user exists and has workspace access
- Workspace Resolution:
- Uses device’s
default_workspace_idif user has access - Otherwise selects first accessible workspace
- Uses device’s
- Session Creation:
- Creates a new
sessionrecord withdevice_idset - Creates a
device_sessionrecord to track the session lifecycle - Updates
device.active_session_idto the new session
- Creates a new
- Recording Status: Sets Redis recording status to “recording” with 1-hour TTL
400 Bad Request: Device not paired, user not found, or workspace access denied404 Not Found: Device not found
Step 2: Upload Audio Chunks
During the recording session, the device uploads audio in chunks for real-time transcription. Endpoint:POST /sessions/{session_id}/upload-audio
Request Format: Multipart form data
audio: Audio file (WAV format, PCM, mono, 16 kHz, 16-bit)chunk_sequence: Sequence number (0, 1, 2, …)is_final_chunk: Boolean (set tofalseduring recording)
upload_audio_impl):
- Session Validation: Confirms session exists
- Chunk Processing:
- Stores chunk to S3 (or local filesystem)
- Creates
audio_chunksrecord with sequence number - Prevents duplicate sequence numbers
- Transcription Job:
- Creates transcription job for immediate chunk processing
- Queues job in Redis for background worker
- Real-time Processing: Worker transcribes chunk independently for live feedback
- Chunks are processed independently for real-time transcription
- Each chunk gets its own transcription job
- Sequence numbers must be sequential and unique per session
Step 3: Stop Session
The device stops the recording session, which triggers automatic finalisation of uploaded chunks. Endpoint:POST /devices/{device_id}/session/stop
Request: No body required
Response:
stop_session_impl):
- Device Validation: Verifies device exists and has active session
- Chunk Finalisation (if chunks exist):
- Checks for pending chunks (
is_final_stitch = false) - Calls
finalise_chunks()to:- Stitch all chunks into single audio file
- Create final
audiorecord - Create transcription job for stitched audio
- Create summarisation job automatically
- Link all chunks to final audio via
parent_audio_id
- Handles gracefully if no chunks exist or already finalised
- Checks for pending chunks (
- Recording Status: Sets Redis status to “inactive”
- Session Cleanup:
- Marks
device_session.ended_attimestamp - Clears
device.active_session_id
- Marks
- If finalisation fails, logs error but continues with session stop
- If Redis update fails, logs warning but continues (Redis is for coordination, not critical)
Redis Recording Status Coordination
Recording Status Lifecycle
The recording status is managed in Redis to coordinate between multiple clients and prevent collisions: Status Values:inactive: No recording in progress (default)recording: Active recording sessionpaused: Recording temporarily paused (not used by devices currently)
Status Lifecycle
- Session Start: Status set to
"recording"when device starts session - During Recording: Status remains
"recording"(can be checked by web clients) - Session Stop: Status set to
"inactive"after finalisation completes
Collision Prevention
The recording status prevents multiple clients from recording simultaneously:- Web Interface: Checks status before starting recording, shows “Recording in progress” if active
- Device: Sets status when starting, ensuring other clients see active recording
- Coordination: Redis acts as distributed lock for recording state
Audio Chunk Upload and Finalisation
Chunked Upload Process
During recording, chunks are uploaded independently:- Chunk Upload: Each chunk is stored as a separate
audio_chunksrecord - Immediate Transcription: Each chunk gets its own transcription job for real-time feedback
- Sequential Processing: Chunks are processed in parallel, not dependent on order
Finalisation Process
When the session stops, finalisation is automatically triggered: Process (finalise_chunks):
- Chunk Collection: Retrieves all chunks for session (
is_final_stitch = false) - Validation:
- Ensures chunks exist
- Prevents duplicate finalisation (checks for existing
is_final_stitch = true)
- Audio Stitching:
- Downloads all chunks from S3 (if configured)
- Stitches chunks sequentially using audio processing pipeline
- Uploads stitched file to S3 or local storage
- Database Updates:
- Creates final
audiorecord - Creates final chunk record (
is_final_stitch = true,chunk_sequence = -1) - Links all original chunks to final audio via
parent_audio_id
- Creates final
- Transcription Job: Creates transcription job for stitched audio
- Summarisation Job: Automatically creates summarisation job queued to Redis
- Final stitched audio file available
- All chunks linked to final audio
- Transcription and summarisation jobs queued for processing
Finalisation Scenarios
- Normal Flow: Device uploads chunks, stops session → finalisation triggered
- No Chunks: Device starts and stops without uploading → no finalisation (handled gracefully)
- Already Finalised: Finalisation already completed → skipped (handled gracefully)
Data Model
Session Table
Thesession table stores session information:
id: UUID primary keytitle: Session title (from device request)workspace_id: Workspace associationdevice_id: Device that created the session (set for device-created sessions)owner_user_id: Optional user owner (null for device sessions)metadata: JSON metadatacreated_at,updated_at: Timestamps
Device Session Table
Thedevice_sessions table tracks device session lifecycle:
id: UUID primary keydevice_id: Reference to devicesession_id: Reference to sessionstarted_at: Session start timestampended_at: Session end timestamp (null until stopped)
Audio Chunks Table
Theaudio_chunks table stores individual uploaded chunks:
id: UUID primary keysession_id: Session referenceparent_audio_id: Reference to final stitched audio (set after finalisation)chunk_sequence: Sequence number (0, 1, 2, … or -1 for final stitch)filename: Chunk filenamefile_path: Local file path or empty if S3s3_key: S3 object key (if S3 configured)duration_seconds: Optional durationuploaded_at: Upload timestampis_final_stitch: Boolean flag (true for final stitched result)
- Multiple chunks per session (
is_final_stitch = false) - One final chunk per session (
is_final_stitch = true) - All chunks link to final audio via
parent_audio_id
Audio Table
Theaudio table stores final stitched audio:
id: UUID primary keysession_id: Session referencefilename: Stitched filenamefile_path: Local file path or empty if S3s3_key: S3 object keyduration_seconds: Optional durationuploaded_at: Upload timestamp
Redis Recording Status
Stored in Redis with key patternsession_recording_status:{session_id}:
Value: JSON string of RecordingStatus enum:
"inactive"- No recording"recording"- Active recording"paused"- Paused recording
API Endpoints Reference
POST /devices/:id/session/start
Starts a new recording session for a device.
Path Parameters:
id: Device UUID
400 Bad Request: Device not paired, user not found, or workspace access denied404 Not Found: Device not found
- Creates session and device_session records
- Sets
device.active_session_id - Sets Redis recording status to “recording”
POST /devices/:id/session/stop
Stops an active recording session for a device.
Path Parameters:
id: Device UUID
404 Not Found: Device not found
- Triggers chunk finalisation if chunks exist
- Sets Redis recording status to “inactive”
- Marks
device_session.ended_at - Clears
device.active_session_id
POST /sessions/:session_id/upload-audio
Uploads an audio chunk to a session.
Path Parameters:
session_id: Session UUID
audio: Audio file (binary)chunk_sequence: Integer sequence numberis_final_chunk: Boolean (optional, defaults to false)
400 Bad Request: Invalid request or processing error404 Not Found: Session not found409 Conflict: Duplicate chunk sequence
- Creates audio_chunk record
- Creates transcription job for chunk
- If
is_final_chunk=true, triggers finalisation
GET /sessions/:session_id/recording-status
Gets or updates the recording status for a session.
Path Parameters:
session_id: Session UUID
status: Update status to this value ("inactive","recording", or"paused")
400 Bad Request: Invalid status or Redis error404 Not Found: Session not found
- Check if recording is in progress (collision prevention)
- Update status (used by web interface)
- Get current status for UI display
Key Points
Collision Prevention Mechanism
The Redis recording status acts as a distributed lock:- Session Start: Device sets status to “recording” when starting
- Status Check: Other clients (web interface) check status before starting
- Status Update: Web interface can update status to “paused” or “recording”
- Session Stop: Device sets status to “inactive” when stopping
- Prevents multiple simultaneous recordings
- Provides real-time status visibility
- Works across multiple API instances (distributed)
Error Handling and Graceful Degradation
The system handles errors gracefully:-
Finalisation Failures:
- If finalisation fails, session stop still succeeds
- Errors are logged but don’t block session cleanup
- Chunks remain available for manual finalisation if needed
-
Redis Failures:
- Redis is for coordination, not critical functionality
- If Redis is unavailable, session management continues
- Status coordination may be delayed until Redis recovers
-
No Chunks Scenarios:
- Device can start and stop without uploading chunks
- Finalisation is skipped gracefully
- Session record still created for tracking
Edge Cases
-
Session Already Finalised: If finalisation was already triggered (e.g., via
is_final_chunk=truein upload), stop session skips finalisation - Multiple Stop Calls: Idempotent - multiple stop calls have no effect after first one
- Stale Sessions: Redis TTL ensures status expires after 1 hour if not updated
- Concurrent Uploads: Sequence number validation prevents duplicate chunks
Device Session vs Web Session
- Device Sessions: Created via
/devices/{id}/session/start, havedevice_idset - Web Sessions: Created via
/sessions(POST), may havedevice_idnull or set later - Both Support: Chunked audio upload and finalisation work for both session types
References
- Backend routes:
crates/api/src/routes/device/device_routes.rs - Backend models:
crates/api/src/routes/device/device_routes_models.rs - Session handlers:
crates/api/src/util/session_handlers.rs - Audio upload:
crates/api/src/routes/session/session_routes_audio.rs - Database models:
crates/core/src/db/session.rs,crates/core/src/db/device_session.rs,crates/core/src/db/audio_chunk.rs