Publish and unpublish on the local member

One way to put media on the session: publish(request) resolves with the local track once LiveKit has it, and unpublish(id) removes it. A request names a source with its device, processor and capture settings, so CaptureSettings on the client options goes, as do setMicrophoneEnabled and setCameraEnabled on the client and the four screen share fields on the local member; sharing is tracks$ having a screenShare track, and a capture failure rejects the promise. LocalMediaInputs becomes the list of initial requests, which also become the room defaults so that one permission prompt covers microphone and camera. The publisher keeps the requests across a reconnection and republishes what is not muted. The harness gains a Share screen button.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Timo K.
2026-10-08 13:53:57 +02:00
co-authored by Claude Fable 5.1
parent 5a43eaf5a6
commit b9f79be106
12 changed files with 441 additions and 326 deletions
+32 -4
View File
@@ -36,6 +36,7 @@ const messages = document.getElementById("messages")!;
const buttons = {
microphone: document.getElementById("microphone") as HTMLButtonElement,
camera: document.getElementById("camera") as HTMLButtonElement,
screenShare: document.getElementById("screenShare") as HTMLButtonElement,
leave: document.getElementById("leave") as HTMLButtonElement,
};
@@ -74,8 +75,7 @@ async function start(
client,
room,
{
microphoneEnabled: true,
cameraEnabled: true,
publish: [{ source: "microphone" }, { source: "camera" }],
audioOutputDeviceId$: constant(undefined),
},
{
@@ -94,10 +94,13 @@ async function start(
rtcClient.join();
toggle(buttons.microphone, async (enabled) =>
rtcClient.setMicrophoneEnabled(enabled),
setPublished(rtcClient, "microphone", enabled),
);
toggle(buttons.camera, async (enabled) =>
rtcClient.setCameraEnabled(enabled),
setPublished(rtcClient, "camera", enabled),
);
toggle(buttons.screenShare, async (enabled) =>
setPublished(rtcClient, "screenShare", enabled),
);
buttons.leave.hidden = false;
buttons.leave.onclick = (): void => {
@@ -115,6 +118,31 @@ async function start(
}
}
/**
* Turns one of our sources on or off: a microphone or camera is muted and
* unmuted while it exists and published when it does not; a screen share is
* published and unpublished.
*/
async function setPublished(
rtcClient: MatrixRTCClient,
source: "microphone" | "camera" | "screenShare",
enabled: boolean,
): Promise<boolean> {
const member = rtcClient.localMember$.value;
if (member === null) return !enabled;
const track = member.media$.value?.tracks$.value.find(
(t) => t.source === source,
);
if (track && source === "screenShare") {
if (!enabled) await member.unpublish(track.id);
return enabled;
}
if (track) return track.setEnabled(enabled);
if (!enabled) return false;
await member.publish({ source });
return true;
}
/** A pressed button means the source is on; the SDK says what it could do. */
function toggle(
button: HTMLButtonElement,