Track is a named media stream declared by the model. Direction is from the client’s perspective:
RECVONLY receives from the model, and SENDONLY sends to it. TrackKind is VIDEO or AUDIO.
The
Track Javadoc
lists every operation.
The snippets below assume a connected Reactor reactor and imports from inc.reactor.sdk.
Find a track
Look up a known name after connecting, or filter the declared tracks:tracks() is empty before the session declares its tracks and after disconnecting. track(name)
throws if that name has not been declared, including before connecting. TrackList.byName(name)
instead returns an Optional<Track>. one() requires exactly one match and throws if there are
zero or multiple matches. You can also iterate, call asList(), or use stream().
A track exposes name(), kind(), direction(), and an optional mid().
Receive frames
Register a handler on a receiving track. Specify the lambda parameter type:onFrame is overloaded
for video and audio, so an untyped lambda is ambiguous.
frames.close() when you no longer need the handler. Registering a video handler on an audio
track, or any frame handler on a sending track, throws ReactorException. Registering any frame
handler in a stepped session throws too, because nothing streams there. Read those frames from the
StepResult that step() answers with.
Frame handlers run on a media delivery thread, independently of the control-event dispatcher. Copy
media before handing it to another thread or a UI. Keep any application queue bounded: a slow video
handler causes intermediate frames to be dropped in favor of the newest one.
A video’s
timestampUs() uses the sender’s clock, so compare it only with timestamps from that same
sender. It is not a local wall-clock time. userData() returns an optional copy of the sender’s tag
that can outlive the callback.
Send frames
Choose a sending track and awaitpublish() before pushing data. Track names depend on the model;
this example finds its single video input:
width * height * 4 bytes in B, G, R, A order. An overload accepts
userData and captureTimeUs after the dimensions. Use reactor.timeMicros() for an explicit
capture time, or null for now.
For audio, call pushFrame(short[] pcm, int sampleRate, int channels) on a published audio input.
Samples are interleaved signed 16-bit PCM. Supported rates are 8,000, 16,000, 24,000, 32,000,
44,100, and 48,000 Hz, with one or two channels. The sample count must divide evenly by the channel
count.
In a stepped session, pushFrame sends nothing. It buffers the frame for the next step(), which
carries every frame pushed since the one before it. The buffer holds one data-channel message’s
worth of bytes, so the SDK drops the oldest frames when you push faster than steps run.
isPublished() reports whether a sender is ready. publishState() returns UNPUBLISHED,
PUBLISHING, or PUBLISHED. Pushing before publication completes, after unpublishing, or to a
receiving track throws. Publication does not survive reconnect: await publish() again before
sending more frames.
Pause and bitrate
pause() and resume() return CompletableFuture<Void>. isPaused() reports the current state.
setBitrate(minBps, maxBps) sets track bitrate bounds in bits per second; negative values leave the
corresponding bound unset. resume() is also how a client built with
.autoResumeTracks(false) starts the receiving
tracks it wants.
The base SDK does not capture or play device audio. You can use the optional
inc.reactor:reactor-sdk-audio
module for microphone and speaker helpers.