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
LocalTracks can either be created using their constructors (see LocalAudioTrack
and LocalVideoTrack), or by using the create<...>Track(s) utility functions:createLocalAudioTrackfor capturing audio from a microphonecreateLocalVideoTrackfor capturing video from a webcamcreateLocalScreenTracksfor creating a screen capture trackcreateLocalTracksfor 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.TrackPublishedevent
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.setMicrophoneEnabledLocalParticipant.setCameraEnabledLocalParticipant.setScreenShareEnabled
Creating Tracks
Publishing/Unpublishing Tracks
Finding Tracks / TrackPublications
LocalParticipant.tracks/RemoteParticipant.tracksLocalParticipant.audioTracks/RemoteParticipant.audioTracksLocalParticipant.videoTracks/RemoteParticipant.videoTracksParticipant.isMicrophoneEnabledParticipant.isCameraEnabledParticipant.isScreenShareEnabledParticipant.getTrackParticipant.getTracksParticipant.getTrackByName
Subscribing to Tracks
RemoteTrackPublication.setSubscribedRemoteTrackPublication.isSubscribedRemoteTrackPublication.trackRemoteTrackPublication.audioTrackRemoteTrackPublication.videoTrack