Core Concepts
Engine / EngineConfig / modes / state machine / callbacks / file layout fields and invariants.
Concepts
Engines
IRecordingEngine (legacy 3.x surface) and IAgoraMediaRtcRecorder (4.x surface) are two published faces of the same capability, both driven by the same recording pipeline:
host media frames ──▶ RecordingPipeline ──▶ IRecordingSink ──▶ output (MP4 / egress job)
│
└── state machine + callbacks + output verificationSinks
The sink decides where the recording goes and is injected by the host:
| Sink | Reality | Output |
|---|---|---|
FfmpegFileSink | Real: pipes YUV420p frames into the system ffmpeg, writes an H.264 MP4 | <storageDir>/<name>.mp4 |
EgressWorkerSink | Real: drives the co-located egress worker REST API | the egress job's files[] |
There is no null sink: without an injected sink the pipeline refuses to start (-ERR_NOT_INITIALIZED), and Stop may only enter stopped when the output passes verification (exists, non-empty, valid container header, positive ffprobe duration).
Sessions and outputs
One join/leave (or startRecording/stopRecording) is one session and one RecordingOutput: path, bytes, duration, container and verdict. Only output.verified == true means a playable file landed on disk.
Where frames come from
The SDK bundles no Agora RTC media stack, so frames are supplied by the host:
- legacy face:
RecordingEngine::PushVideoFrameafterjoinChannel, or install anIFrameSourceand callPumpFrames; - 4.x face:
RtcRecorder::PushVideoFrameafterstartRecording; - with the egress sink no frames are needed (the worker records the room).
Both the product docs and the acceptance notes must state this boundary: the recording pipeline is real, joining an Agora channel is not.