Skip to main content

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:
  1. Device Starts Session: Creates a session record and sets recording status to “recording” in Redis
  2. Audio Chunk Upload: Device uploads audio chunks during recording for real-time transcription
  3. Device Stops Session: Automatically triggers finalisation of chunks, creates stitched audio, and sets recording status to “inactive”
The system uses Redis to coordinate recording status and prevent collisions between multiple clients attempting to record simultaneously.

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_id should be null)
Request Body:
Response:
Backend Process (start_session_impl):
  1. Device Validation: Verifies device exists and is paired
  2. User Verification: Confirms user exists and has workspace access
  3. Workspace Resolution:
    • Uses device’s default_workspace_id if user has access
    • Otherwise selects first accessible workspace
  4. Session Creation:
    • Creates a new session record with device_id set
    • Creates a device_session record to track the session lifecycle
    • Updates device.active_session_id to the new session
  5. Recording Status: Sets Redis recording status to “recording” with 1-hour TTL
Error Responses:
  • 400 Bad Request: Device not paired, user not found, or workspace access denied
  • 404 Not Found: Device not found
Security: No authentication required (device endpoint)

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 to false during recording)
Example Request:
Response:
Backend Process (upload_audio_impl):
  1. Session Validation: Confirms session exists
  2. Chunk Processing:
    • Stores chunk to S3 (or local filesystem)
    • Creates audio_chunks record with sequence number
    • Prevents duplicate sequence numbers
  3. Transcription Job:
    • Creates transcription job for immediate chunk processing
    • Queues job in Redis for background worker
  4. Real-time Processing: Worker transcribes chunk independently for live feedback
Key Points:
  • 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:
Backend Process (stop_session_impl):
  1. Device Validation: Verifies device exists and has active session
  2. 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 audio record
      • 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
  3. Recording Status: Sets Redis status to “inactive”
  4. Session Cleanup:
    • Marks device_session.ended_at timestamp
    • Clears device.active_session_id
Error Handling:
  • If finalisation fails, logs error but continues with session stop
  • If Redis update fails, logs warning but continues (Redis is for coordination, not critical)
Security: No authentication required (device endpoint)

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 session
  • paused: Recording temporarily paused (not used by devices currently)
Redis Key Format:
TTL: 3600 seconds (1 hour)

Status Lifecycle

  1. Session Start: Status set to "recording" when device starts session
  2. During Recording: Status remains "recording" (can be checked by web clients)
  3. 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
Example Check (web client):

Audio Chunk Upload and Finalisation

Chunked Upload Process

During recording, chunks are uploaded independently:
  1. Chunk Upload: Each chunk is stored as a separate audio_chunks record
  2. Immediate Transcription: Each chunk gets its own transcription job for real-time feedback
  3. Sequential Processing: Chunks are processed in parallel, not dependent on order

Finalisation Process

When the session stops, finalisation is automatically triggered: Process (finalise_chunks):
  1. Chunk Collection: Retrieves all chunks for session (is_final_stitch = false)
  2. Validation:
    • Ensures chunks exist
    • Prevents duplicate finalisation (checks for existing is_final_stitch = true)
  3. Audio Stitching:
    • Downloads all chunks from S3 (if configured)
    • Stitches chunks sequentially using audio processing pipeline
    • Uploads stitched file to S3 or local storage
  4. Database Updates:
    • Creates final audio record
    • Creates final chunk record (is_final_stitch = true, chunk_sequence = -1)
    • Links all original chunks to final audio via parent_audio_id
  5. Transcription Job: Creates transcription job for stitched audio
  6. Summarisation Job: Automatically creates summarisation job queued to Redis
Result:
  • Final stitched audio file available
  • All chunks linked to final audio
  • Transcription and summarisation jobs queued for processing

Finalisation Scenarios

  1. Normal Flow: Device uploads chunks, stops session → finalisation triggered
  2. No Chunks: Device starts and stops without uploading → no finalisation (handled gracefully)
  3. Already Finalised: Finalisation already completed → skipped (handled gracefully)

Data Model

Session Table

The session table stores session information:
  • id: UUID primary key
  • title: Session title (from device request)
  • workspace_id: Workspace association
  • device_id: Device that created the session (set for device-created sessions)
  • owner_user_id: Optional user owner (null for device sessions)
  • metadata: JSON metadata
  • created_at, updated_at: Timestamps

Device Session Table

The device_sessions table tracks device session lifecycle:
  • id: UUID primary key
  • device_id: Reference to device
  • session_id: Reference to session
  • started_at: Session start timestamp
  • ended_at: Session end timestamp (null until stopped)
Purpose: Tracks which device created which session and when it started/ended

Audio Chunks Table

The audio_chunks table stores individual uploaded chunks:
  • id: UUID primary key
  • session_id: Session reference
  • parent_audio_id: Reference to final stitched audio (set after finalisation)
  • chunk_sequence: Sequence number (0, 1, 2, … or -1 for final stitch)
  • filename: Chunk filename
  • file_path: Local file path or empty if S3
  • s3_key: S3 object key (if S3 configured)
  • duration_seconds: Optional duration
  • uploaded_at: Upload timestamp
  • is_final_stitch: Boolean flag (true for final stitched result)
Relationships:
  • 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

The audio table stores final stitched audio:
  • id: UUID primary key
  • session_id: Session reference
  • filename: Stitched filename
  • file_path: Local file path or empty if S3
  • s3_key: S3 object key
  • duration_seconds: Optional duration
  • uploaded_at: Upload timestamp
Relationship: One audio record per finalised session

Redis Recording Status

Stored in Redis with key pattern session_recording_status:{session_id}: Value: JSON string of RecordingStatus enum:
  • "inactive" - No recording
  • "recording" - Active recording
  • "paused" - Paused recording
TTL: 3600 seconds (1 hour)

API Endpoints Reference

POST /devices/:id/session/start

Starts a new recording session for a device. Path Parameters:
  • id: Device UUID
Request Body:
Response (200 OK):
Error Responses:
  • 400 Bad Request: Device not paired, user not found, or workspace access denied
  • 404 Not Found: Device not found
Side Effects:
  • 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
Request Body: None Response (200 OK):
Error Responses:
  • 404 Not Found: Device not found
Side Effects:
  • 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
Request: Multipart form data
  • audio: Audio file (binary)
  • chunk_sequence: Integer sequence number
  • is_final_chunk: Boolean (optional, defaults to false)
Response (200 OK):
Error Responses:
  • 400 Bad Request: Invalid request or processing error
  • 404 Not Found: Session not found
  • 409 Conflict: Duplicate chunk sequence
Side Effects:
  • 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
Query Parameters (optional):
  • status: Update status to this value ("inactive", "recording", or "paused")
Response (200 OK):
Error Responses:
  • 400 Bad Request: Invalid status or Redis error
  • 404 Not Found: Session not found
Use Cases:
  • 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:
  1. Session Start: Device sets status to “recording” when starting
  2. Status Check: Other clients (web interface) check status before starting
  3. Status Update: Web interface can update status to “paused” or “recording”
  4. Session Stop: Device sets status to “inactive” when stopping
Benefits:
  • 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:
  1. 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
  2. Redis Failures:
    • Redis is for coordination, not critical functionality
    • If Redis is unavailable, session management continues
    • Status coordination may be delayed until Redis recovers
  3. No Chunks Scenarios:
    • Device can start and stop without uploading chunks
    • Finalisation is skipped gracefully
    • Session record still created for tracking

Edge Cases

  1. Session Already Finalised: If finalisation was already triggered (e.g., via is_final_chunk=true in upload), stop session skips finalisation
  2. Multiple Stop Calls: Idempotent - multiple stop calls have no effect after first one
  3. Stale Sessions: Redis TTL ensures status expires after 1 hour if not updated
  4. Concurrent Uploads: Sequence number validation prevents duplicate chunks

Device Session vs Web Session

  • Device Sessions: Created via /devices/{id}/session/start, have device_id set
  • Web Sessions: Created via /sessions (POST), may have device_id null 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