PrivMX DOCS
JavaScript

Working with Streams

Use StreamApi to manage Stream Rooms and real-time media streams.

Streams allow users to communicate in real time using audio, video, and desktop sharing inside Stream Rooms. Each Context can contain any number of Stream Rooms with a unique identifier (streamRoomId) used to distinguish them.

About Streams

The public API exposed to library users is StreamApi. It combines two areas of responsibility:

  • Stream Room management
  • live media publishing and remote stream subscriptions

Before working with Streams, follow the Getting Started Guide. It will show you how to set up your project to work with PrivMX Bridge. Sample code on this page is based on the initial assumptions.

Working with Streams

When working with Streams, you will use:

  • StreamApi - provides methods used to manage Stream Rooms and WebRTC streams
JavaScript
await Endpoint.setup();
const connection = await Endpoint.connect(userPrivKey, solutionId, bridgeUrl);
const eventApi = await Endpoint.createEventApi(connection);
const streamApi = await Endpoint.createStreamApi(connection, eventApi);

Creating Stream Rooms

createStreamRoom(...) creates a new Stream Room inside a given Context. Like other PrivMX Modules, a Stream Room uses users, managers, publicMeta, and privateMeta.

Creating a basic Stream Room:

JavaScript
// creating Stream Room
const streamRoomId = await streamApi.createStreamRoom(
    contextId,
    defaultUsers,
    defaultUsers,
    new Uint8Array(),
    new Uint8Array()
);
console.log("CREATED_STREAM_ROOM_ID", streamRoomId);

Listing and Reading Stream Rooms

Use listStreamRooms(...) for paged room listing and getStreamRoom(...) to fetch a single room.

You can fetch Stream Rooms exactly as you do with other Modules: by Context, by ID, or using paging parameters.

JavaScript
// listing Stream Rooms
const streamRooms = await streamApi.listStreamRooms(contextId, defaultQuery);
console.log("STREAM_ROOMS", streamRooms.readItems);

The returned StreamRoom object contains room metadata, members, managers, version, policy, and timestamps.

Modifying Stream Rooms

To update a room, use updateStreamRoom(...). Just like with Threads, Stores, Inboxes, and KVDBs, updates overwrite the existing room definition, so you should pass the full set of room parameters.

JavaScript
// updating Stream Room
await streamApi.updateStreamRoom(
    streamRoomId,
    defaultUsers,
    defaultUsers,
    streamRoom.publicMeta,
    Utils.serializeObject({name: "new-name"}),
    streamRoom.version,
    false,
    false,
    streamRoom.policy,
);
const updatedStreamRoom = await streamApi.getStreamRoom(streamRoomId);
console.log("UPDATED_STREAM_ROOM", updatedStreamRoom);

Joining Stream Rooms

Before publishing a local stream or subscribing to remote streams, you need to join the room. Use joinStreamRoom(...) when entering a room.

JavaScript
// joining Stream Room
await streamApi.joinStreamRoom(streamRoomId);

Publishing Local Streams

After joining a room, the usual publish flow is:

  1. Create a local stream handle with createStream(...).
  2. Add one or more tracks with addTrack(...).
  3. Publish the prepared stream using publishStream(...).
JavaScript
// creating local stream handle
const streamHandle = await streamApi.createStream(streamRoomId);
console.log("STREAM_HANDLE", streamHandle);

// registering audio levels listener
await streamApi.addAudioLevelStatsListener((stats) => {
    console.log("AUDIO_LEVELS", stats);
});

// adding microphone track
let localMediaStream: MediaStream | undefined;
let audioTrack: MediaStreamTrack | undefined;
if (navigator.mediaDevices?.getUserMedia) {
    try {
        localMediaStream = await navigator.mediaDevices.getUserMedia({audio: true, video: false});
        audioTrack = localMediaStream.getAudioTracks()[0];
        if (audioTrack) {
            await streamApi.addStreamTrack(streamHandle, {track: audioTrack});
        }
    }
    catch (error) {
        console.warn("addStreamTrack(track)", error);
    }
}

// publishing stream
let publishResult: Types.StreamPublishResult | undefined;
try {
    publishResult = await streamApi.publishStream(streamHandle, (state) => {
        console.log("STREAM_STATE", state);
    });
    console.log("PUBLISH_RESULT", publishResult);
}
catch (error) {
    console.warn("publishStream", error);
}

If you later add or remove tracks, use updateStream(...) to apply the staged changes.

JavaScript
// updating published stream
const dataTrackId = await streamApi.addStreamTrack(streamHandle, {createDataChannel: true});
console.log("DATA_TRACK_ID", dataTrackId);
const updateResult = await streamApi.updateStream(streamHandle);
console.log("UPDATE_RESULT", updateResult);

Subscribing to Remote Streams

To receive remote media:

  1. Call listStreams(streamRoomId) to see what is currently available.
  2. Build StreamSubscription objects for selected streams or tracks.
  3. Subscribe with subscribeToRemoteStreams(...).
  4. Register a listener with addRemoteStreamListener(...) to handle incoming tracks and media data.
JavaScript
// listing published streams after publish
const streamsAfterPublish = await streamApi.listStreams(streamRoomId);
console.log("STREAMS_AFTER_PUBLISH", streamsAfterPublish);

// subscribing to remote streams
const remoteStream = streamsAfterPublish[0];
const subscription: Types.StreamSubscription = {
    streamId: remoteStream.id,
};

await streamApi.subscribeToRemoteStreams(streamRoomId, [subscription]);
console.log("REMOTE_STREAM_SUBSCRIPTION", subscription);

// adding remote stream listener
streamApi.addRemoteStreamListener({
    streamRoomId,
    onRemoteStreamTrack: (event) => {
        console.log("REMOTE_STREAM_TRACK", event);
    },
    onRemoteData: (data, statusCode) => {
        console.log("REMOTE_STREAM_DATA", {
            statusCode,
            text: new TextDecoder().decode(data),
        });
    },
});

When the subscription set changes, use modifyRemoteStreamsSubscriptions(...) or unsubscribeFromRemoteStreams(...).

JavaScript
// modifying subscriptions
if (remoteStream) {
    // modifying remote streams subscriptions
    await streamApi.modifyRemoteStreamsSubscriptions(streamRoomId, [subscription], []);

    // unsubscribing from remote streams
    await streamApi.unsubscribeFromRemoteStreams(streamRoomId, [subscription]);
}

Next Step

To react to room and stream lifecycle changes, continue with Stream Events.

We use cookies on our website. We use them to ensure proper functioning of the site and, if you agree, for purposes such as analytics, marketing, and targeting ads.

On this page

Working with Streams | PrivMX Docs