Skip to content

eufy-mega / core/contracts / TalkbackHandle

Interface: TalkbackHandle

A live talkback session: audio pushed from the host to a camera's speaker, the mirror of LiveStreamHandle's inbound feed.

Audio must be AAC-LC, 16 kHz, mono, in ADTS frames — what the device's path is fixed at, so a stream at another rate or channel count is rejected rather than resampled (it would otherwise play at the wrong pitch and speed). Feed it either way:

  • ADTS AAC — the default. Chunk boundaries are irrelevant; frames are recovered from the stream, so piping an encoder's output straight in works.
  • PCM — only when the handle was opened with an AacEncoder, which then does the conversion. write takes 16-bit little-endian mono PCM at 16 kHz instead.

Frames are paced at their own playback rate (64 ms each) rather than flushed as fast as they arrive, so feeding a file plays it at speed instead of overrunning the device. A live source keeps the queue near-empty and is unaffected.

Example

ts
const talk = await cam.talkback!();
talk.on("error", (err) => console.error(err.message));
talk.on("finished", () => void talk.stop());
fs.createReadStream("greeting.aac").pipe(talk.writable());

Properties

pending

ts
readonly pending: number;

How many frames are still queued for the wire — 0 once everything written has reached it.

Methods

end()

ts
end(): void;

Declare the input finished, so a drained queue can report the clip complete. writable() calls this from its final, so a piped source needs no explicit call; an imperative write caller does. Writing after this is an error, not more audio — open a new talkback for a new clip.

Returns

void


on()

Call Signature

ts
on(event, listener): this;

The clip is complete: the input has ended (via end or the writable's final) AND every queued frame has reached the wire. Fires once — the natural moment to stop a finite clip.

This deliberately does NOT fire on a merely-empty queue. A realtime source keeps the queue near empty by design, so "queue is empty" arrives after the very first frame and stopping on it would cut the clip to 64 ms. Use pending if you want the instantaneous depth.

Parameters
event

"finished"

listener

() => void

Returns

this

Call Signature

ts
on(event, listener): this;

The path closed — either you called stop, or the media session it rides inside ended and took it with it. It always fires exactly once, so it is a teardown hook rather than a signal that something went wrong; a caller that stopped it already knows.

Parameters
event

"stop"

listener

() => void

Returns

this

Call Signature

ts
on(event, listener): this;

A frame the device would not play (wrong sample rate or channel count, or over its length limit), an encoder failure, or an audio frame the device never acknowledged — the channel is ordered, so an unacknowledged frame can stall playback behind it. Non-fatal: the session stays open.

Parameters
event

"error"

listener

(err) => void

Returns

this

Call Signature

ts
on(event, listener): this;

Battery cameras only: the media session talkback rides inside has reached its power budget and will auto-stop after the notice's grace period, taking the audio with it. Call extend() to keep talking. Without a listener the session stops on schedule, which protects the battery.

Parameters
event

"budget"

listener

(notice) => void

Returns

this


stop()

ts
stop(): Promise<void>;

Close the path, dropping anything still queued. Idempotent.

Returns

Promise<void>


writable()

ts
writable(): Writable;

A node:stream Writable over write, for piping a file or an encoder's stdout. Applies backpressure while the pacing queue is full, so a fast source cannot outrun playback.

Returns

Writable


write()

ts
write(chunk): void;

Queue audio — ADTS frames, or PCM when an encoder was supplied. Partial frames are held.

Parameters

chunk

Buffer

Returns

void

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