[bugfix]: Validate audio sample range, catch AudioContext error (#470)
This commit is contained in:
parent
3bca85b3a8
commit
5f1d0a3b5e
4 changed files with 32 additions and 8 deletions
|
@ -510,7 +510,7 @@
|
||||||
"replayGainPreamp": "{{ReplayGain}} preamp (dB)",
|
"replayGainPreamp": "{{ReplayGain}} preamp (dB)",
|
||||||
"replayGainPreamp_description": "adjust the preamp gain applied to the {{ReplayGain}} values",
|
"replayGainPreamp_description": "adjust the preamp gain applied to the {{ReplayGain}} values",
|
||||||
"sampleRate": "sample rate",
|
"sampleRate": "sample rate",
|
||||||
"sampleRate_description": "select the output sample rate to be used if the sample frequency selected is different from that of the current media",
|
"sampleRate_description": "select the output sample rate to be used if the sample frequency selected is different from that of the current media. a value less than 8000 will use the default frequency",
|
||||||
"savePlayQueue": "save play queue",
|
"savePlayQueue": "save play queue",
|
||||||
"savePlayQueue_description": "save the play queue when the application is closed and restore it when the application is opened",
|
"savePlayQueue_description": "save the play queue when the application is closed and restore it when the application is opened",
|
||||||
"scrobble": "scrobble",
|
"scrobble": "scrobble",
|
||||||
|
|
|
@ -7,10 +7,11 @@ import {
|
||||||
crossfadeHandler,
|
crossfadeHandler,
|
||||||
gaplessHandler,
|
gaplessHandler,
|
||||||
} from '/@/renderer/components/audio-player/utils/list-handlers';
|
} from '/@/renderer/components/audio-player/utils/list-handlers';
|
||||||
import { useSettingsStore } from '/@/renderer/store/settings.store';
|
import { useSettingsStore, useSettingsStoreActions } from '/@/renderer/store/settings.store';
|
||||||
import type { CrossfadeStyle } from '/@/renderer/types';
|
import type { CrossfadeStyle } from '/@/renderer/types';
|
||||||
import { PlaybackStyle, PlayerStatus } from '/@/renderer/types';
|
import { PlaybackStyle, PlayerStatus } from '/@/renderer/types';
|
||||||
import { useSpeed } from '/@/renderer/store';
|
import { useSpeed } from '/@/renderer/store';
|
||||||
|
import { toast } from '/@/renderer/components/toast';
|
||||||
|
|
||||||
interface AudioPlayerProps extends ReactPlayerProps {
|
interface AudioPlayerProps extends ReactPlayerProps {
|
||||||
crossfadeDuration: number;
|
crossfadeDuration: number;
|
||||||
|
@ -60,6 +61,7 @@ export const AudioPlayer = forwardRef(
|
||||||
const [isTransitioning, setIsTransitioning] = useState(false);
|
const [isTransitioning, setIsTransitioning] = useState(false);
|
||||||
const audioDeviceId = useSettingsStore((state) => state.playback.audioDeviceId);
|
const audioDeviceId = useSettingsStore((state) => state.playback.audioDeviceId);
|
||||||
const playback = useSettingsStore((state) => state.playback.mpvProperties);
|
const playback = useSettingsStore((state) => state.playback.mpvProperties);
|
||||||
|
const { resetSampleRate } = useSettingsStoreActions();
|
||||||
const playbackSpeed = useSpeed();
|
const playbackSpeed = useSpeed();
|
||||||
|
|
||||||
const [webAudio, setWebAudio] = useState<WebAudio | null>(null);
|
const [webAudio, setWebAudio] = useState<WebAudio | null>(null);
|
||||||
|
@ -119,10 +121,21 @@ export const AudioPlayer = forwardRef(
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ('AudioContext' in window) {
|
if ('AudioContext' in window) {
|
||||||
const context = new AudioContext({
|
let context: AudioContext;
|
||||||
latencyHint: 'playback',
|
|
||||||
sampleRate: playback.audioSampleRateHz || undefined,
|
try {
|
||||||
});
|
context = new AudioContext({
|
||||||
|
latencyHint: 'playback',
|
||||||
|
sampleRate: playback.audioSampleRateHz || undefined,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// In practice, this should never be hit because the UI should validate
|
||||||
|
// the range. However, the actual supported range is not guaranteed
|
||||||
|
toast.error({ message: (error as Error).message });
|
||||||
|
context = new AudioContext({ latencyHint: 'playback' });
|
||||||
|
resetSampleRate();
|
||||||
|
}
|
||||||
|
|
||||||
const gain = context.createGain();
|
const gain = context.createGain();
|
||||||
gain.connect(context.destination);
|
gain.connect(context.destination);
|
||||||
|
|
||||||
|
|
|
@ -206,11 +206,16 @@ export const MpvSettings = () => {
|
||||||
{
|
{
|
||||||
control: (
|
control: (
|
||||||
<NumberInput
|
<NumberInput
|
||||||
defaultValue={settings.mpvProperties.audioSampleRateHz}
|
defaultValue={settings.mpvProperties.audioSampleRateHz || undefined}
|
||||||
|
max={192000}
|
||||||
|
min={0}
|
||||||
|
placeholder="48000"
|
||||||
|
rightSection="Hz"
|
||||||
width={100}
|
width={100}
|
||||||
onBlur={(e) => {
|
onBlur={(e) => {
|
||||||
const value = Number(e.currentTarget.value);
|
const value = Number(e.currentTarget.value);
|
||||||
handleSetMpvProperty('audioSampleRateHz', value > 0 ? value : undefined);
|
// Setting a value of `undefined` causes an error for MPV. Use 0 instead
|
||||||
|
handleSetMpvProperty('audioSampleRateHz', value >= 8000 ? value : value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
|
@ -251,6 +251,7 @@ export interface SettingsState {
|
||||||
export interface SettingsSlice extends SettingsState {
|
export interface SettingsSlice extends SettingsState {
|
||||||
actions: {
|
actions: {
|
||||||
reset: () => void;
|
reset: () => void;
|
||||||
|
resetSampleRate: () => void;
|
||||||
setSettings: (data: Partial<SettingsState>) => void;
|
setSettings: (data: Partial<SettingsState>) => void;
|
||||||
setSidebarItems: (items: SidebarItemType[]) => void;
|
setSidebarItems: (items: SidebarItemType[]) => void;
|
||||||
setTable: (type: TableType, data: DataTableProps) => void;
|
setTable: (type: TableType, data: DataTableProps) => void;
|
||||||
|
@ -567,6 +568,11 @@ export const useSettingsStore = create<SettingsSlice>()(
|
||||||
set(initialState);
|
set(initialState);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
resetSampleRate: () => {
|
||||||
|
set((state) => {
|
||||||
|
state.playback.mpvProperties.audioSampleRateHz = 0;
|
||||||
|
});
|
||||||
|
},
|
||||||
setSettings: (data) => {
|
setSettings: (data) => {
|
||||||
set({ ...get(), ...data });
|
set({ ...get(), ...data });
|
||||||
},
|
},
|
||||||
|
|
Reference in a new issue