Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,13 @@
"room_auth_view_ssla_caption": "By clicking \"Join call now\", you agree to our <2>Software and Services License Agreement (SSLA)</2>",
"screenshare_button_label": "Share screen",
"settings": {
"advanced_header": "Advanced",
"audio_tab": {
"auto_gain_control_label": "Automatically adjust the microphone volume",
"echo_cancellation_label": "Echo cancellation",
"effect_volume_description": "Adjust the volume at which reactions and hand raised effects play.",
"effect_volume_label": "Sound effect volume"
"effect_volume_label": "Sound effect volume",
"noise_suppression_label": "Noise suppression"
},
"background_blur_header": "Background",
"background_blur_label": "Blur the background of the video",
Expand Down
16 changes: 16 additions & 0 deletions src/livekit/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Please see LICENSE in the repository root for full details.
*/

import {
type AudioCaptureOptions,
AudioPresets,
DefaultReconnectPolicy,
type RoomOptions,
Expand All @@ -15,6 +16,12 @@ import {
VideoPresets,
} from "livekit-client";

import {
autoGainControl as autoGainControlSetting,
noiseSuppression as noiseSuppressionSetting,
echoCancellation as echoCancellationSetting,
} from "../settings/settings";

const defaultLiveKitPublishOptions: TrackPublishDefaults = {
audioPreset: AudioPresets.music,
dtx: true,
Expand Down Expand Up @@ -52,3 +59,12 @@ export const defaultLiveKitOptions: RoomOptions = {
disconnectOnPageLeave: true,
webAudioMix: false,
};

export function getLiveKitAudioCaptureOptions(): AudioCaptureOptions {
return {
autoGainControl: { ideal: autoGainControlSetting.getValue() },
noiseSuppression: { ideal: noiseSuppressionSetting.getValue() },
echoCancellation: { ideal: echoCancellationSetting.getValue() },
voiceIsolation: { ideal: noiseSuppressionSetting.getValue() },
};
}
8 changes: 7 additions & 1 deletion src/livekit/useECConnectionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
UnknownCallError,
} from "../utils/errors.ts";
import { AbortHandle } from "../utils/abortHandle.ts";
import { getLiveKitAudioCaptureOptions } from "./options";

/*
* Additional values for states that a call can be in, beyond what livekit
Expand Down Expand Up @@ -73,11 +74,16 @@ async function doConnect(
return;
}

const liveKitAudioCaptureOptions = getLiveKitAudioCaptureOptions();

logger.info("Pre-creating microphone track");
let preCreatedAudioTrack: LocalTrack | undefined;
try {
const audioTracks = await livekitRoom!.localParticipant.createTracks({
audio: { deviceId: initialDeviceId },
audio: {
deviceId: initialDeviceId,
...liveKitAudioCaptureOptions,
},
});

if (audioTracks.length < 1) {
Expand Down
5 changes: 4 additions & 1 deletion src/livekit/useLivekit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
switchMap,
} from "rxjs";

import { defaultLiveKitOptions } from "./options";
import { defaultLiveKitOptions, getLiveKitAudioCaptureOptions } from "./options";
import { type SFUConfig } from "./openIDSFU";
import { type MuteStates } from "../room/MuteStates";
import { useMediaDevices } from "../MediaDevicesContext";
Expand Down Expand Up @@ -101,6 +101,8 @@ export function useLivekit(
};
}

const liveKitAudioCaptureOptions = getLiveKitAudioCaptureOptions();

const roomOptions: RoomOptions = {
...defaultLiveKitOptions,
videoCaptureDefaults: {
Expand All @@ -111,6 +113,7 @@ export function useLivekit(
audioCaptureDefaults: {
...defaultLiveKitOptions.audioCaptureDefaults,
deviceId: initialAudioInputId,
...liveKitAudioCaptureOptions,
},
audioOutput: {
// When using controlled audio devices, we don't want to set the
Expand Down
4 changes: 4 additions & 0 deletions src/room/LobbyView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
import { usePageTitle } from "../usePageTitle";
import { useLatest } from "../useLatest";
import { getValue } from "../utils/observable";
import { getLiveKitAudioCaptureOptions } from "../livekit/options";

interface Props {
client: MatrixClient;
Expand Down Expand Up @@ -128,13 +129,16 @@ export const LobbyView: FC<Props> = ({
devices.videoInput.selected$,
)?.id;


const liveKitAudioCaptureOptions = getLiveKitAudioCaptureOptions();
// Capture the audio options as they were when we first mounted, because
// we're not doing anything with the audio anyway so we don't need to
// re-open the devices when they change (see below).
const initialAudioOptions = useInitial(
() =>
muteStates.audio.enabled && {
deviceId: getValue(devices.audioInput.selected$)?.id,
...liveKitAudioCaptureOptions,
},
);

Expand Down
50 changes: 50 additions & 0 deletions src/settings/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import {
useSetting,
soundEffectVolume as soundEffectVolumeSetting,
backgroundBlur as backgroundBlurSetting,
autoGainControl as autoGainControlSetting,
noiseSuppression as noiseSuppressionSetting,
echoCancellation as echoCancellationSetting,
developerMode,
} from "./settings";
import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
Expand Down Expand Up @@ -94,6 +97,51 @@ export const SettingsModal: FC<Props> = ({
);
};

// Generate a `Checkbox` input to turn blur on or off.
const AdvancedAudio: React.FC = (): ReactNode => {
const [autoGainControl, setAutoGainControl] = useSetting(autoGainControlSetting);
const [noiseSuppression, setNoiseSuppression] = useSetting(noiseSuppressionSetting);
const [echoCancellation, setEchoCancellation] = useSetting(echoCancellationSetting);

return (
<>
<div>
<h4>{t("settings.advanced_header")}</h4>

<FieldRow>
<InputField
id="autoGainControl"
label={t("settings.audio_tab.auto_gain_control_label")}
type="checkbox"
checked={!!autoGainControl}
onChange={(b): void => setAutoGainControl(b.target.checked)}
/>
</FieldRow>

<FieldRow>
<InputField
id="noiseSuppression"
label={t("settings.audio_tab.noise_suppression_label")}
type="checkbox"
checked={!!noiseSuppression}
onChange={(b): void => setNoiseSuppression(b.target.checked)}
/>
</FieldRow>

<FieldRow>
<InputField
id="echoCancellation"
label={t("settings.audio_tab.echo_cancellation_label")}
type="checkbox"
checked={!!echoCancellation}
onChange={(b): void => setEchoCancellation(b.target.checked)}
/>
</FieldRow>
</div>
</>
);
};

const devices = useMediaDevices();
useEffect(() => {
if (open) devices.requestDeviceNames();
Expand Down Expand Up @@ -160,6 +208,8 @@ export const SettingsModal: FC<Props> = ({
step={0.01}
/>
</div>
<Separator />
<AdvancedAudio />
</Form>
</>
),
Expand Down
4 changes: 4 additions & 0 deletions src/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ export const videoInput = new Setting<string | undefined>(
undefined,
);

export const autoGainControl = new Setting<boolean>("auto-gain-control", true);
export const noiseSuppression = new Setting<boolean>("noise-suppression", true);
export const echoCancellation = new Setting<boolean>("echo-cancellation", true);

export const backgroundBlur = new Setting<boolean>("background-blur", false);

export const showHandRaisedTimer = new Setting<boolean>(
Expand Down
Loading