- Add session recording metadata and mux filter builder in src/recorder/sessionRecording.ts. - Update SegmentMetadata to include recordingSessionId in src/types.ts and src/recorder/metadata.ts. - Modify recorder lifecycle to track sessions, register segments, and finalize recordings on stop. - Create tests for session recording functionality in tests/recorder/sessionRecording.test.ts and tests/recorder/metadata.test.ts. - Document session recording design and implementation plan in docs/superpowers/specs/2026-05-16-session-full-recording-design.md and docs/superpowers/plans/2026-05-16-session-full-recording.md.
3.7 KiB
Session Full Recording Design
Context
The recorder currently writes per-user OGG segments under recordings/<userId>/. Each segment has JSON metadata with user identity, bot flag, segment timing, and filename. The requested addition is a second recording view: one full-session OGG from the time the bot joins a voice channel until it leaves, while preserving the current per-user recording files.
Bot/self audio is excluded before segment creation, so session-level output should only include human participants.
Goals
- Track one recording session from successful voice join until disconnect/leave.
- Preserve existing per-user OGG segment behavior.
- Create a background full-session OGG/Opus mix after the session ends.
- Store session metadata with duration, participants, segment references, output status, and full recording path.
- Keep muxing failures isolated from voice connection shutdown.
Non-goals
- Real-time mixed full-session recording.
- Replacing per-user segment recording.
- Dashboard UI for session playback in this phase.
- Database-backed mux job retries in this phase.
Output structure
A completed session writes:
recordings/
sessions/
<recordingSessionId>/
full.ogg
session.json
recordingSessionId is based on guild ID, channel ID, and session start time: <guildId>-<channelId>-<sessionStartTime>.
session.json contains:
sessionIdguildIdchannelIdchannelNamestartTimeendTimedurationMsstatus:completed,failed, oremptyoutputFile: relative path tofull.oggwhen presentparticipants: non-bot users observed in the sessionsegments: per-user segment metadata references with absolute timingerror: failure message when muxing fails
Per-user segment JSON also records the shared recordingSessionId so full-session muxing can identify which files belong to the same join/leave session.
Lifecycle
startRecording()creates a session object after the voice connection reaches ready state.- Each non-bot speaking user still gets the existing per-user
SegmentManagerflow. - Each finished segment is registered with the active session using its metadata path, OGG path, user ID, start time, and end time.
stopRecording(guildId)or connection destruction finalizes the active session withendTime.- Finalization starts muxing in the background and does not block disconnect.
- Muxing writes
session.jsonwithempty,completed, orfailedstatus.
Muxing design
The post-processor reads all registered segment metadata for the session. It builds an ffmpeg filter_complex that delays each input by segment.startTime - session.startTime milliseconds, mixes all delayed inputs with amix, and encodes the result to OGG/Opus.
For a session with no human segments, muxing skips ffmpeg and writes session.json with status: "empty" and the full session duration.
For successful muxing, it writes full.ogg and session.json with status: "completed".
For failed muxing, it writes session.json with status: "failed" and the error message.
Error handling
- Failure to write
session.jsonis logged and does not crash shutdown. - ffmpeg failure is captured in metadata as
status: "failed". - Missing or empty segment files are skipped from the mix and recorded as skipped references if needed.
- Background mux errors never reject
stopRecording().
Testing
- Unit test session metadata creation from join to stop.
- Unit test bot/self users do not register participants or segments.
- Unit test mux filter generation with timeline offsets.
- Unit test empty sessions write
status: "empty"without calling ffmpeg. - Unit test stop triggers background finalization without awaiting ffmpeg.