Skip to main content

Muting & Volume Control

This guide explains how to control the volume and mute state of an

AudioInput

in the ODIN Voice Web SDK, including how to properly dismiss the browser's recording indicator and optimize resource usage. It also covers how to locally mute remote peers.

Volume Basics

The

AudioInput

volume accepts values between 0 and 2 (inclusive), or the special string 'muted':

ValueEffect
1Default volume (no change)
02Scale capture volume (0 = silent, 2 = double)
'muted'Stops the underlying MediaStream entirely
Setting volume
// Full volume (default)
await audioInput.setVolume(1);

// Half volume
await audioInput.setVolume(0.5);

// Silent (stream still active, browser recording indicator still visible)
await audioInput.setVolume(0);

// Muted (stream stopped, browser recording indicator disappears)
await audioInput.setVolume("muted");
info

Setting the volume to 0 makes the audio silent but keeps the MediaStream active. The browser will continue to show its recording indicator (e.g. the red dot in the tab bar). Use 'muted' to fully stop the stream and dismiss the indicator.

Muting the Microphone

The recommended way to mute is to set the volume to 'muted'. This stops the underlying MediaStream, which causes the browser to remove its recording indicator (e.g. the red dot in the tab or address bar):

Simple mute/unmute
// Mute — stops the MediaStream, browser recording indicator disappears
await audioInput.setVolume("muted");

// Unmute — restarts the MediaStream at full volume
await audioInput.setVolume(1);

This is the preferred approach for most applications. It provides clear visual feedback to the user that their microphone is no longer active.

Full Mute (Mute + Stop Encoder)

For additional resource savings, you can also remove the

AudioInput

from the

Room

. This stops the audio encoder in addition to stopping the MediaStream, which reduces CPU usage while muted:

Full mute/unmute with encoder control
// Mute — remove from room to stop encoder, then stop MediaStream
room.removeAudioInput(audioInput);
await audioInput.setVolume("muted");

// Unmute — restore volume, then re-add to room to start encoder
await audioInput.setVolume(1);
await room.addAudioInput(audioInput);
tip

The order matters when unmuting: restore the volume before re-adding to the room. This ensures the encoder starts with the correct volume and the MediaStream is active when audio processing begins.

Comparison of Approaches

ApproachRecording IndicatorEncoder ActiveCPU Usage While Muted
setVolume(0)VisibleYesNormal
setVolume('muted')HiddenYesReduced
setVolume('muted') + removeAudioInputHiddenNoMinimal

Complete Example

Here's a complete toggle mute implementation using the full mute approach:

Complete mute toggle
let isMuted = false;

async function toggleMute(room, audioInput) {
if (isMuted) {
// Unmute: restore volume first, then re-add to room
await audioInput.setVolume(1);
await room.addAudioInput(audioInput);
} else {
// Mute: remove from room first, then stop MediaStream
room.removeAudioInput(audioInput);
await audioInput.setVolume("muted");
}

isMuted = !isMuted;
}

Framework Examples

React

const toggleMute = async () => {
if (!audioInputRef.current) return;

if (isMuted) {
await audioInputRef.current.setVolume(1);
await roomRef.current?.addAudioInput(audioInputRef.current);
} else {
roomRef.current?.removeAudioInput(audioInputRef.current);
await audioInputRef.current.setVolume("muted");
}
setIsMuted(!isMuted);
};

Vue 3

const toggleMute = async () => {
if (!audioInput.value) return;

if (isMuted.value) {
await audioInput.value.setVolume(1);
await room.value?.addAudioInput(audioInput.value);
} else {
room.value?.removeAudioInput(audioInput.value);
await audioInput.value.setVolume("muted");
}
isMuted.value = !isMuted.value;
};

Angular

async toggleMute() {
if (!this.audioInput) return;

if (this.isMuted) {
await this.audioInput.setVolume(1);
await this.room?.addAudioInput(this.audioInput);
} else {
this.room?.removeAudioInput(this.audioInput);
await this.audioInput.setVolume('muted');
}
this.isMuted = !this.isMuted;
}

Muting Remote Peers

In some scenarios you may want to locally mute a specific remote peer — for example, to let users silence someone in a crowded room. The ODIN SDK provides two complementary mechanisms for this on the

RemotePeer

.

Setting Volume to Zero (Quick Mute)

The simplest way to mute a remote peer is to set their volume to 0. This silences their audio immediately on the client side:

Quick mute/unmute a remote peer
// Mute — silence the remote peer locally
remotePeer.setVolume(0);

// Unmute — restore the remote peer's volume
remotePeer.setVolume(1);

setVolume accepts a number between 0 and 2, or a stereo tuple [left, right] for per-channel control. Setting the volume to 0 makes the peer inaudible but the audio server still sends their audio packets to your client.

Pausing Audio Outputs (Bandwidth-Saving Mute)

Each

RemotePeer

exposes an audioOutputs array containing the

AudioOutput

instances associated with that peer. Every AudioOutput has a pause() method that tells the audio server to stop sending audio packets for that stream, saving bandwidth while the peer is muted:

Pause/resume audio outputs
// Pause all audio outputs — the server stops sending packets
for (const output of remotePeer.audioOutputs) {
await output.pause();
}

// Resume all audio outputs — the server starts sending packets again
for (const output of remotePeer.audioOutputs) {
await output.resume();
}
info

Calling pause() only stops the server from delivering packets to your client. The remote peer's audio is not affected for other participants in the room.

For the best user experience, we recommend combining both methods. Set the volume to 0 for an instant local mute, and also pause the audio outputs to save bandwidth:

Full remote peer mute/unmute
// Mute a remote peer
remotePeer.setVolume(0);
for (const output of remotePeer.audioOutputs) {
await output.pause();
}

// Unmute a remote peer
remotePeer.setVolume(1);
for (const output of remotePeer.audioOutputs) {
await output.resume();
}

Muting All Remote Peers at Once

The

Room

also provides a setVolume() method that works the same way but applies to all peers and their

AudioOutput

instances in the room at once:

Mute/unmute all remote peers via the room
// Mute all remote peers in the room
room.setVolume(0);

// Unmute all remote peers in the room
room.setVolume(1);
tip

When unmuting, make sure to both call resume() on the audio outputs and set the volume back to a non-zero value. Resuming without restoring the volume will cause the server to send packets that are still silenced locally.