Skip to content

@mega-yfue/eufy-sdk / recordClip

Function: recordClip()

ts
function recordClip(
   session, 
   seconds, 
   opts?
): Promise<Buffer<ArrayBufferLike>>;

Record a clip — collect the live H.264/H.265 stream for seconds and mux it to a fragmented MP4 (same source as captureSnapshotFromShared, kept running and written to a container). Recording starts at the first complete keyframe so the clip is seekable. Requires ffmpeg.

Opens its OWN LiveStream over the session rather than joining the device's shared source, so it costs a second pull on a camera already streaming, and the shared path's release of a sibling's lingering pull does not reach it. recordFragments is the shared-consumer path.

The clip therefore starts at the SECOND keyframe, so parameter sets announced only with the first are dropped along with it — every frame is watched for an announcement, including the skipped ones, and the collected run is primed before muxing. This also settles the codec, which is sniffed from a config NAL: a run of bare slices would otherwise fall back to H.264 and mislabel an H.265 clip.

Bounded in both phases, so it always settles. The first phase is bounded by timeoutMs waiting for the keyframe the clip starts at; the second is bounded by the clip's own window, which is armed as a deadline the moment capture starts rather than being read off the next frame to arrive. A camera that goes quiet mid-clip delivers no further frame to compare a clock against — measured on an own-session camera that stopped 13.6 s into a stream with no stop and no error — so a clip whose end is decided inside a frame handler has no end at all, and the promise stays pending for the life of the process. The deadline answers with the run collected up to it: the window the caller asked for has elapsed, and frames the camera never sent cannot be waited into existence.

A pull whose SESSION goes away before that window elapses fails the clip instead, naming the close. No further frame can arrive on it, so there is nothing left to wait for, and a caller that asked for a clip of a stated length is told the session went away rather than handed a fragment as if it were the clip. A decode failure on the stream fails it the same way.

The error listener outlives the collection deliberately. An unhandled error on an emitter takes the host process down, and the stream is stopped only after the promise settles, so it stays attached and a late failure lands on an already-settled promise as the no-op it is.

Parameters

session

P2PSession

seconds

number

opts?

object & LiveStreamOptions = {}

Returns

Promise<Buffer<ArrayBufferLike>>

Independent and unofficial. Not affiliated with, endorsed by, or sponsored by Anker Innovations, Anker eufy, or eufy. "Anker eufy", "eufy" and "Anker" are trademarks of their respective owners. Use responsibly — rapid or failed logins can trigger captcha or temporary cooldowns.