mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-19 05:55:34 +09:00
fix(voice): make stereo microphones work in studio and custom (#2852)
This commit is contained in:
1 parent
a3454e8245
commit
487febac8e
52 files changed
+105
-138
No files matched your search
@@ -5,7 +5,7 @@ import type {TrackPublishOptions} from 'livekit-client';
|
||||
|
||||
export const OPUS_MAX_AUDIO_BITRATE_BPS = 510000;
|
||||
export const VOICE_CHANNEL_MIN_AUDIO_BITRATE_BPS = 8000;
|
||||
export const STEREO_VOICE_MIN_AUDIO_BITRATE_BPS = 64000;
|
||||
export const STEREO_VOICE_MIN_AUDIO_BITRATE_BPS = 128000;
|
||||
|
||||
export function normaliseAudioBitrateBps(value: number | null | undefined): number | undefined {
|
||||
if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0) return undefined;
|
||||
@@ -27,7 +27,7 @@ export function buildMicrophonePublishOptions(
|
||||
},
|
||||
dtx: false,
|
||||
red: true,
|
||||
forceStereo: stereoCapture && maxBitrate >= STEREO_VOICE_MIN_AUDIO_BITRATE_BPS,
|
||||
forceStereo: stereoCapture && maxBitrate >= STEREO_VOICE_MIN_AUDIO_BITRATE_BPS ? undefined : false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,17 @@ import * as VoiceSettingsCommands from '@app/features/voice/commands/VoiceSettin
|
||||
import VoiceNoiseSuppressionRollout from '@app/features/voice/state/VoiceNoiseSuppressionRollout';
|
||||
import VoiceSettings from '@app/features/voice/state/VoiceSettings';
|
||||
import {
|
||||
getNoiseSuppressionBackendDescriptor,
|
||||
isNoiseSuppressionBackendSupported,
|
||||
isVoiceNoiseSuppressionBackend,
|
||||
VOICE_NOISE_SUPPRESSION_BACKENDS,
|
||||
type VoiceNoiseSuppressionBackend,
|
||||
} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionBackends';
|
||||
import {readEffectiveNoiseSuppression} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionRuntime';
|
||||
import {readNoiseSuppressionRuntimeCapabilities} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionSelection';
|
||||
import {
|
||||
applyNoiseSuppressionOverride,
|
||||
readNoiseSuppressionRuntimeCapabilities,
|
||||
supportsStereoCapture,
|
||||
} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionSelection';
|
||||
import {
|
||||
legacyNoiseSuppressionBackend,
|
||||
resolveVoiceProcessingFromState,
|
||||
@@ -67,13 +70,11 @@ export function setNoiseSuppressionChoice(backend: VoiceNoiseSuppressionBackend)
|
||||
}
|
||||
|
||||
export function isStereoMicrophoneChoiceAvailable(): boolean {
|
||||
const assignment = VoiceNoiseSuppressionRollout.assignment;
|
||||
if (!assignment.enabled || !assignment.stereo_enabled) return false;
|
||||
const effective = readEffectiveNoiseSuppression(NOISE_SUPPRESSION_UI_SAMPLE_RATE);
|
||||
const backend = effective.backend ?? resolveVoiceProcessingFromState(VoiceSettings).noiseSuppressionBackend;
|
||||
return getNoiseSuppressionBackendDescriptor(backend).preservesInputChannels;
|
||||
const profile = applyNoiseSuppressionOverride(resolveVoiceProcessingFromState(VoiceSettings), effective);
|
||||
return supportsStereoCapture(profile);
|
||||
}
|
||||
|
||||
export function isStereoMicrophoneEnabled(): boolean {
|
||||
return VoiceSettings.getStereoMicrophone() !== false;
|
||||
return VoiceSettings.getStereoMicrophone() === true;
|
||||
}
|
||||
@@ -47,7 +47,7 @@ const STEREO_MICROPHONE_DESCRIPTOR = msg({
|
||||
comment: 'Switch label in the voice settings that sends both channels of a stereo microphone. Keep it concise.',
|
||||
});
|
||||
const STEREO_MICROPHONE_DESCRIPTION_DESCRIPTOR = msg({
|
||||
message: 'Sends both channels of a stereo microphone. Works only with no suppression or standard suppression.',
|
||||
message: 'Sends both channels of a stereo microphone. Needs all processing off and a channel at 128 kbps or higher.',
|
||||
comment: 'Description for the stereo microphone switch in the voice settings.',
|
||||
});
|
||||
|
||||
|
||||
+20
-14
@@ -21,7 +21,7 @@ export interface EffectiveNoiseSuppression {
|
||||
requestedBackend: VoiceNoiseSuppressionBackend | null;
|
||||
source: VoiceNoiseSuppressionResolutionSource | null;
|
||||
suppressionStrength: number;
|
||||
stereoEnabled: boolean;
|
||||
stereoPreferred: boolean;
|
||||
configVersion: number;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export const INERT_EFFECTIVE_NOISE_SUPPRESSION: EffectiveNoiseSuppression = {
|
||||
requestedBackend: null,
|
||||
source: null,
|
||||
suppressionStrength: 80,
|
||||
stereoEnabled: false,
|
||||
stereoPreferred: false,
|
||||
configVersion: 0,
|
||||
};
|
||||
|
||||
@@ -44,8 +44,8 @@ export function resolveEffectiveNoiseSuppression(
|
||||
): EffectiveNoiseSuppression {
|
||||
const preference = isVoiceNoiseSuppressionBackend(userPreference) ? userPreference : null;
|
||||
const resolution = resolveVoiceNoiseSuppressionForCall(assignment, guildId, preference);
|
||||
const stereoAllowed = assignment.enabled && assignment.stereo_enabled && stereoPreference !== false;
|
||||
if (resolution == null) return {...INERT_EFFECTIVE_NOISE_SUPPRESSION, stereoEnabled: stereoAllowed};
|
||||
const stereoAllowed = stereoPreference === true;
|
||||
if (resolution == null) return {...INERT_EFFECTIVE_NOISE_SUPPRESSION, stereoPreferred: stereoAllowed};
|
||||
const backend = selectUsableNoiseSuppressionBackend(resolution.backend, capabilities);
|
||||
return {
|
||||
rolloutApplied: true,
|
||||
@@ -53,8 +53,7 @@ export function resolveEffectiveNoiseSuppression(
|
||||
requestedBackend: resolution.backend,
|
||||
source: resolution.source,
|
||||
suppressionStrength: resolution.suppressionStrength,
|
||||
stereoEnabled:
|
||||
stereoAllowed && resolution.stereoEnabled && getNoiseSuppressionBackendDescriptor(backend).preservesInputChannels,
|
||||
stereoPreferred: stereoAllowed,
|
||||
configVersion: resolution.configVersion,
|
||||
};
|
||||
}
|
||||
@@ -77,11 +76,17 @@ export function getNoiseSuppressionScopeGuildId(): string | null {
|
||||
return activeScopeGuildId;
|
||||
}
|
||||
|
||||
export function resolveStereoCapture(
|
||||
effective: EffectiveNoiseSuppression,
|
||||
backend: VoiceNoiseSuppressionBackend,
|
||||
): boolean {
|
||||
return effective.stereoEnabled && getNoiseSuppressionBackendDescriptor(backend).preservesInputChannels;
|
||||
export function supportsStereoCapture(profile: ResolvedVoiceProcessing): boolean {
|
||||
if (profile.echoCancellation || profile.autoGainControl) return false;
|
||||
if (profile.browserNoiseSuppression || profile.deepFilter) return false;
|
||||
return getNoiseSuppressionBackendDescriptor(profile.noiseSuppressionBackend).preservesInputChannels;
|
||||
}
|
||||
|
||||
export function resolveStereoCapture(effective: EffectiveNoiseSuppression, profile: ResolvedVoiceProcessing): boolean {
|
||||
if (!supportsStereoCapture(profile)) return false;
|
||||
if (profile.mode === 'studio') return true;
|
||||
if (profile.mode === 'custom') return effective.stereoPreferred;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function applyNoiseSuppressionOverride(
|
||||
@@ -89,16 +94,17 @@ export function applyNoiseSuppressionOverride(
|
||||
effective: EffectiveNoiseSuppression,
|
||||
): ResolvedVoiceProcessing {
|
||||
if (!effective.rolloutApplied || effective.backend == null || profile.mode === 'studio') {
|
||||
return {...profile, stereoCapture: resolveStereoCapture(effective, profile.noiseSuppressionBackend)};
|
||||
return {...profile, stereoCapture: resolveStereoCapture(effective, profile)};
|
||||
}
|
||||
const backend = effective.backend;
|
||||
const descriptor = getNoiseSuppressionBackendDescriptor(backend);
|
||||
return {
|
||||
const next: ResolvedVoiceProcessing = {
|
||||
...profile,
|
||||
browserNoiseSuppression: descriptor.browserNoiseSuppression,
|
||||
deepFilter: backend === 'deep_filter',
|
||||
deepFilterNoiseReductionLevel: backend === 'deep_filter' ? effective.suppressionStrength : 0,
|
||||
noiseSuppressionBackend: backend,
|
||||
stereoCapture: resolveStereoCapture(effective, backend),
|
||||
stereoCapture: false,
|
||||
};
|
||||
return {...next, stereoCapture: resolveStereoCapture(effective, next)};
|
||||
}
|
||||
Reference in new issue
Block a user