Skip to main content

Media (Voice/Video)

Alpha

This feature is in alpha. APIs and behavior may change without notice. Not recommended for production use.

room.media is the media-state layer of Room.

It tracks who is publishing audio, video, or screen share, which tracks are present, and how mute or device state changes over time.

Client Surface​

Assume room is an authenticated room client created with client.room(...).

await room.media.audio.enable({ deviceId: 'mic-1' });
await room.media.video.enable({ deviceId: 'cam-2' });
await room.media.screen.start();

room.media.onTrack((track, member) => attachTrack(track, member));
room.media.onTrackRemoved((track, member) => detachTrack(track, member));
room.media.onStateChange((member, state) => renderMediaState(member, state));

await room.media.devices.switch({ audioInputId: 'mic-2' });

The main client APIs are:

  • room.media.list()
  • room.media.audio.enable() / disable() / setMuted()
  • room.media.video.enable() / disable() / setMuted()
  • room.media.screen.start() / stop()
  • room.media.devices.switch(...)
  • room.media.onTrack(...)
  • room.media.onTrackRemoved(...)
  • room.media.onStateChange(...)
  • room.media.onDeviceChange(...)

Access Control​

Media has split access gates because subscribe, publish, and control are different concerns:

  • access.media.subscribe(auth, roomId, payload)
  • access.media.publish(auth, roomId, kind, payload)
  • access.media.control(auth, roomId, operation, payload)

This lets you support patterns like:

  • everyone can subscribe
  • only hosts can publish screen share
  • moderators can control mute or unpublish operations

Server Hooks​

Media-specific hooks let you observe or transform the media control plane:

rooms: {
meeting: {
hooks: {
media: {
beforePublish: async (kind, sender, room, ctx) => {
// Return false to reject the publish attempt
if (kind === 'screen' && sender.role !== 'host') return false;
// Return undefined to allow
},
onPublished: async (kind, sender, room, ctx) => {
console.log(`${sender.userId} published ${kind}`);
},
onUnpublished: async (kind, sender, room, ctx) => {
console.log(`${sender.userId} stopped ${kind}`);
},
onMuteChange: async (kind, sender, muted, room, ctx) => {
console.log(`${sender.userId} ${muted ? 'muted' : 'unmuted'} ${kind}`);
},
},
},
},
},
HookParametersCan Reject
beforePublish(kind, sender, room, ctx)Yes — return false
onPublished(kind, sender, room, ctx)No
onUnpublished(kind, sender, room, ctx)No
onMuteChange(kind, sender, muted, room, ctx)No

kind: 'audio' | 'video' | 'screen'. muted: boolean.

These are useful for analytics, moderation mirrors, or injecting track metadata.

Media and Admin​

room.media describes media state.

room.admin is the moderation layer that acts on people in the room, including media-related controls such as:

  • room.admin.mute(memberId)
  • room.admin.disableVideo(memberId)
  • room.admin.stopScreenShare(memberId)

Media vs Signals​

  • Use media for room-scoped A/V publishing and mute state.
  • Use Signals for WebRTC negotiation payloads and other transient control messages.