Publishing and Subscribing Tracks
This guide explains how to publish audio and video tracks to a room, and how to subscribe to tracks published by other participants.
Whenever a user wants to share their microphone input, webcam feed, or screen, a track is created and published to a room.
Already connected participants will then be notified of a new track publication. If they want to receive that track,
they simply subscribe to it and will start receiving the track's data.
The Engage SDK has some handy wrapper methods taking care of creating and publishing tracks for you, like
LocalParticipant.setMicrophoneEnabled(true)
and
LocalParticipant.setCameraEnabled(true)
.For a more fine-grained control, you can also create tracks manually and publish them to a room.
Tracks
A
Track
is a representation of an audio or video stream, e.g. from a microphone or webcam, which can be sent to a room and received by other participants.
A Track
with a local media source is called a LocalTrack
, while a Track
received from a remote participant is called a RemoteTrack
.Kinds and Sources
A
Track.Kind
can be either audio
or video
.
Tracks from an audio source are represented by the classes LocalAudioTrack
and RemoteAudioTrack
.
Their kind
member is set to "audio"
or Track.Kind.Audio
.
Similar, tracks from video sources are represented by LocalVideoTrack
and RemoteVideoTrack
.
Their kind
member is set to "video"
or Track.Kind.Video
.A
Track.Source
can be either camera
, microphone
, or screen_share
. The source
member of a Track
is set to one of these values.Creating a LocalTrack
LocalTrack
s can either be created using their constructors (see LocalAudioTrack
and LocalVideoTrack
), or by using the create<...>Track(s)
utility functions:createLocalAudioTrack
for capturing audio from a microphonecreateLocalVideoTrack
for capturing video from a webcamcreateLocalScreenTracks
for creating a screen capture trackcreateLocalTracks
for creating both microphone and webcam tracks at the same time
Using
createLocalTracks
to
capture both audio and video at the same time will prompt the user for
permission to access their microphone and webcam only once.import {
createLocalAudioTrack,
createLocalVideoTrack,
createLocalScreenTracks,
} from "@atmokyaudio/engage-client";
async function captureMicrophone(deviceID?: string) {
const audioTrack = await createLocalAudioTrack({ deviceID });
return audioTrack;
}
async function captureWebcam() {
const videoTrack = await createLocalVideoTrack();
return videoTrack;
}
async function createScreenCapture() {
const screenTrack = await createLocalScreenTracks()[0];
return screenTrack;
}
Checkout the
DeviceManager
for
getting a list of available audio and video devices.You can create local tracks before joining a room, so the user can preview
their audio and video input before joining.
Publications
In order to share a
LocalTrack
with other participants, it needs to be published to a room.
This is done by calling LocalParticipant.publishTrack
.captureMicrophone().then((audioTrack) => {
localParticipant.publishTrack(audioTrack).then((publication) => {
console.log("Published microphone track");
});
});
Participants already connected to the room will be notified of the new track publication
by the
RoomEvent.TrackPublished
event
emitted by the room, or alternatively by the ParticipantEvent.TrackPublished
event emitted by the publishing participant. When a user joins a room after the track has
been published, they won't receive these events, but can access all already available
publications by traversing RemoteParticipant.tracks
,
or for specific track kinds RemoteParticipant.audioTracks
and RemoteParticipant.videoTracks
.
These containers map a track's SID (unique server-generated identifier) to the
corresponding RemoteTrackPublication
.
The LocalParticipant
also has these containers
holding the local tracks published to a room.Tracks can be unpublished by calling
LocalParticipant.unpublishTrack(localTrack)
:// Example for unpublishing the local microphone track
// find local audio track publication with microphone as source
const microphoneTrack = localParticipant.getTrack(Track.Source.Microphone);
// unpublish track
if (microphoneTrack) {
localParticipant
.unpublishTrack(microphoneTrack.track)
.then((publication: LocalTrackPublication | undefined) => {
if (publication) {
console.log("unpublished microphone track");
}
});
}
Subscriptions
Important note: Audio tracks from microphones are automatically subscribed
to, see
AudioConnectionManager
.Subscribing to a RemoteTrack
In order to receive a
RemoteTrack
, it needs to be subscribed to.Find the corresponding RemoteTrackPublication
You first need to get ahold of the
RemoteTrackPublication
you want to subscribe to.
This can be done by traversing the RemoteParticipant.tracks
container (or the more specific audioTracks
or videoTracks
subsets).If the desired track hasn't been published yet, you can set up a
ParticipantEvent.TrackPublished
/ RoomEvent.TrackPublished
event listener to get notified of new publications.Subscribe
Just call
RemoteTrackPublication.setSubscribed(true)
and the SDK is starting the subscription process.Handle subscription events
Your subscription is ready and the track is being received when the
TrackEvent.Subscribed
event is emitted by the RemoteTrackPublication
. This event will also be re-emitted by
the RemoteParticipant
and even the Room
itself.Let's say we want to subscribe to the video tracks of a remote participant:
// 1. create useful event handlers
// handling newly published tracks
const handleRemoteTrackPublished = (publication: RemoteTrackPublication) => {
if (publication.kind === Track.Kind.Video) {
// subscribe to the video track
publication.setSubscribed(true);
}
};
// handling subscribed tracks
const handleVideoTrackSubscribed = (track: RemoteVideoTrack, publication: RemoteTrackPublication) => {
console.log("Successfully subscribed to video track", track);
console.log("This track is part of the following publication", publication);
console.log("Let's display it in a video element");
const videoElement = /** create or get an HTML video element */;
track.attach(videoElement);
};
// 2. attach them to the remote participant
remoteParticipant.on(ParticipantEvent.TrackPublished, handleRemoteTrackPublished);
remoteParticipant.on(ParticipantEvent.TrackSubscribed, handleVideoTrackSubscribed);
// 3. subscribe to all already published video tracks
remoteParticipant.videoTracks.forEach((publication) => {
publication.setSubscribed(true);
});
Note, that we have attached the event handlers to the
RemoteParticipant
instance.
You can also make them more general and attach them to the Room
instance, which will
re-emit the events with the RemoteParticipant
instance the event originated from.In the example above, the
remoteParticipant
variable could come from a RoomEvent.ParticipantConnected
event handler,
or when iterating over Room.participants
when joining the room.room.participants.forEach((remoteParticipant) => {
// ...
});
Unsubscribing
Unsubscribing is fairly easy, simply call
RemoteTrackPublication.setSubscribed(false)
and the SDK will stop receiving the track's data.Related Functions, Methods, and Events
All-in-one wrappers
LocalParticipant.setMicrophoneEnabled
LocalParticipant.setCameraEnabled
LocalParticipant.setScreenShareEnabled
Creating Tracks
Publishing/Unpublishing Tracks
Finding Tracks / TrackPublications
LocalParticipant.tracks
/RemoteParticipant.tracks
LocalParticipant.audioTracks
/RemoteParticipant.audioTracks
LocalParticipant.videoTracks
/RemoteParticipant.videoTracks
Participant.isMicrophoneEnabled
Participant.isCameraEnabled
Participant.isScreenShareEnabled
Participant.getTrack
Participant.getTracks
Participant.getTrackByName
Subscribing to Tracks
RemoteTrackPublication.setSubscribed
RemoteTrackPublication.isSubscribed
RemoteTrackPublication.track
RemoteTrackPublication.audioTrack
RemoteTrackPublication.videoTrack