Daily’s input settings API lets you apply real-time processing to audio and video tracks — noise cancellation, background blur, background replacement, and face detection — as well as supply custom MediaStreamTrack objects in place of the default camera and microphone. Send settings control encoding quality and simulcast behavior; receive settings control which simulcast layer remote streams are decoded at.
// Apply settings
const { inputSettings } = await call.updateInputSettings({
audio: { processor: { type: 'noise-cancellation' } },
video: { processor: { type: 'background-blur', config: { strength: 0.5 } } },
});
// Read current settings
const current = await call.getInputSettings();
Both operate on a DailyInputSettings object:
interface DailyInputSettings {
audio?: DailyInputAudioSettings;
video?: DailyInputVideoSettings;
}
You can also pass inputSettings to join() or startCamera() to apply settings before the first frame is captured.
interface DailyInputAudioSettings {
processor?: DailyInputAudioProcessorSettings;
settings?: MediaTrackConstraints | DailyCustomTrackSettings;
}
interface DailyInputAudioProcessorSettings {
type: 'none' | 'noise-cancellation';
}
'none' — no audio processing
'noise-cancellation' — applies Daily’s built-in noise cancellation model
settings
MediaTrackConstraints | DailyCustomTrackSettings
Pass standard MediaTrackConstraints to configure the microphone (e.g. echoCancellation, sampleRate), or a DailyCustomTrackSettings to supply your own track:interface DailyCustomTrackSettings {
customTrack: MediaStreamTrack;
}
interface DailyInputVideoSettings {
processor?: DailyInputVideoProcessorSettings;
settings?: MediaTrackConstraints | DailyCustomTrackSettings;
}
DailyInputVideoProcessorSettings is a union of four processor types:
None
Background blur
Background image
Face detection
Disables any active video processor:await call.updateInputSettings({
video: { processor: { type: 'none' } },
});
Blurs the background behind the participant. strength ranges from 0 (no blur) to 1 (maximum blur):await call.updateInputSettings({
video: {
processor: {
type: 'background-blur',
config: { strength: 0.75 },
},
},
});
Replaces the background with an image. Provide either a URL or a raw source:// Using a URL
await call.updateInputSettings({
video: {
processor: {
type: 'background-image',
config: { source: 'https://example.com/office.jpg' },
},
},
});
// Using a raw source (string, number, or ArrayBuffer)
await call.updateInputSettings({
video: {
processor: {
type: 'background-image',
config: { source: imageArrayBuffer },
},
},
});
Enables face detection processing. Detected face counts are reported via the face-counts-updated event:await call.updateInputSettings({
video: { processor: { type: 'face-detection' } },
});
Fires whenever input settings change (locally or remotely triggered):
call.on('input-settings-updated', ({ inputSettings }) => {
console.log('New input settings:', inputSettings);
});
Example: noise cancellation and background blur
// Enable both noise cancellation and background blur at join time
await call.join({
url: roomUrl,
inputSettings: {
audio: {
processor: { type: 'noise-cancellation' },
},
video: {
processor: {
type: 'background-blur',
config: { strength: 0.5 },
},
},
},
});
// Toggle noise cancellation later
async function toggleNoiseCancellation(enabled: boolean) {
await call.updateInputSettings({
audio: {
processor: { type: enabled ? 'noise-cancellation' : 'none' },
},
});
}
Video processors require browser support for OffscreenCanvas and WebGL. Check Daily.supportedBrowser().supportsVideoProcessing before enabling them.
Send settings
Send settings control how the local participant’s video is encoded and transmitted.
updateSendSettings() and getSendSettings()
const updated = await call.updateSendSettings({
video: 'bandwidth-optimized',
});
const current = call.getSendSettings(); // DailySendSettings | null
interface DailySendSettings {
video?: DailyCamVideoSendSettings | DailyVideoSendSettingsPreset;
screenVideo?: DailyVideoSendSettings | DailyScreenVideoSendSettingsPreset;
customVideoDefaults?: DailyVideoSendSettings | DailyVideoSendSettingsPreset;
[customKey: string]: DailyVideoSendSettings | DailyCamVideoSendSettings
| DailyVideoSendSettingsPreset | DailyScreenVideoSendSettingsPreset | undefined;
}
Video send settings presets
For camera video (video key):
| Preset | Description |
|---|
'default-video' | Default encoding for camera video |
'bandwidth-optimized' | Lower bitrate, smaller resolution |
'bandwidth-and-quality-balanced' | Balanced tradeoff |
'quality-optimized' | Higher bitrate and resolution |
'adaptive-2-layers' | Simulcast with 2 quality layers |
'adaptive-3-layers' | Simulcast with 3 quality layers |
For screen video (screenVideo key):
| Preset | Description |
|---|
'default-screen-video' | Default screen share encoding |
'detail-optimized' | Prioritizes clarity (good for slides) |
'motion-optimized' | Prioritizes framerate (good for video) |
'motion-and-detail-balanced' | Balanced tradeoff |
Custom encoding parameters
For fine-grained control, use DailyVideoSendSettings directly:
interface DailyVideoSendSettings {
maxQuality?: 'low' | 'medium' | 'high';
encodings?: {
low: RTCRtpEncodingParameters;
medium?: RTCRtpEncodingParameters;
high?: RTCRtpEncodingParameters;
};
}
// Camera video additionally supports adaptive layers
interface DailyCamVideoSendSettings extends DailyVideoSendSettings {
allowAdaptiveLayers?: boolean;
}
await call.updateSendSettings({
video: {
allowAdaptiveLayers: true,
maxQuality: 'high',
encodings: {
low: { maxBitrate: 80_000, scaleResolutionDownBy: 4 },
medium: { maxBitrate: 300_000, scaleResolutionDownBy: 2 },
high: { maxBitrate: 1_200_000, scaleResolutionDownBy: 1 },
},
},
});
send-settings-updated event
call.on('send-settings-updated', ({ sendSettings }) => {
console.log('Send settings changed:', sendSettings);
});
Receive settings
Receive settings let you select which simulcast layer to decode for each remote participant’s video tracks. This is useful for saving bandwidth when you know certain participants’ video will be displayed at a smaller size.
updateReceiveSettings() and getReceiveSettings()
// Get settings for all participants
const allSettings = await call.getReceiveSettings();
// Get settings for a specific participant (with inherited values filled in)
const participantSettings = await call.getReceiveSettings(sessionId, {
showInheritedValues: true,
});
// Update receive settings
const updated = await call.updateReceiveSettings({
// Use the special '*' key to set a default for all participants
'*': { video: { layer: 1 } },
// Override for a specific participant (renders at full quality)
[speakerSessionId]: { video: { layer: 2 } },
});
interface DailyReceiveSettings {
[participantIdOrBase: string]: DailySingleParticipantReceiveSettings;
}
interface DailySingleParticipantReceiveSettings {
video?: DailyVideoReceiveSettings;
screenVideo?: DailyVideoReceiveSettings;
[customKey: string]: DailyVideoReceiveSettings | undefined;
}
interface DailyVideoReceiveSettings {
layer?: number; // 0 = lowest quality, higher = better quality
}
When updating, you can use 'inherit' to reset a participant back to the default:
await call.updateReceiveSettings({
[sessionId]: 'inherit', // reset this participant to the '*' default
});
receive-settings-updated event
call.on('receive-settings-updated', ({ receiveSettings }) => {
console.log('Receive settings updated:', receiveSettings);
});
Example: active speaker optimization
Set a low-quality default for all participants and bump up the active speaker:
// Set low layer as default
await call.updateReceiveSettings({ '*': { video: { layer: 0 } } });
let currentSpeakerId: string | null = null;
call.on('active-speaker-change', async ({ activeSpeaker }) => {
const updates: Record<string, any> = {};
// Reset the previous speaker
if (currentSpeakerId) {
updates[currentSpeakerId] = 'inherit';
}
// Promote the new speaker to high quality
if (activeSpeaker.peerId) {
updates[activeSpeaker.peerId] = { video: { layer: 2 } };
currentSpeakerId = activeSpeaker.peerId;
}
await call.updateReceiveSettings(updates);
});