mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-16 13:40:24 +02:00
add audio device selection for mpv
This commit is contained in:
@@ -89,8 +89,16 @@ export const AudioPlayers = () => {
|
||||
useEffect(() => {
|
||||
// Not standard, just used in chromium-based browsers. See
|
||||
// https://developer.chrome.com/blog/audiocontext-setsinkid/.
|
||||
// If the isElectron() check is every removed, fix this.
|
||||
if (isElectron() && audioContext && 'setSinkId' in audioContext.context && audioDeviceId) {
|
||||
|
||||
if (!isElectron()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playbackType !== PlayerType.WEB) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (audioContext && 'setSinkId' in audioContext.context && audioDeviceId) {
|
||||
const setSink = async () => {
|
||||
try {
|
||||
if (audioContext.context.state !== 'closed') {
|
||||
@@ -103,7 +111,7 @@ export const AudioPlayers = () => {
|
||||
|
||||
setSink();
|
||||
}
|
||||
}, [audioContext, audioDeviceId]);
|
||||
}, [audioContext, audioDeviceId, playbackType]);
|
||||
|
||||
// Listen to favorite and rating events to update queue songs
|
||||
useEffect(() => {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { ListConfigTable } from '/@/renderer/features/shared/components/list-config-menu';
|
||||
import {
|
||||
usePlaybackType,
|
||||
usePlayerActions,
|
||||
usePlayerData,
|
||||
usePlayerProperties,
|
||||
@@ -35,18 +36,33 @@ import {
|
||||
} from '/@/shared/types/types';
|
||||
|
||||
const ipc = isElectron() ? window.api.ipc : null;
|
||||
const mpvPlayer = isElectron() ? window.api.mpvPlayer : null;
|
||||
|
||||
const getAudioDevice = async () => {
|
||||
const devices = await navigator.mediaDevices.enumerateDevices();
|
||||
return (devices || []).filter((dev: MediaDeviceInfo) => dev.kind === 'audiooutput');
|
||||
};
|
||||
|
||||
const getMpvAudioDevices = async () => {
|
||||
if (!mpvPlayer) {
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
return await mpvPlayer.getAudioDevices();
|
||||
} catch (error) {
|
||||
console.error('Failed to get MPV audio devices:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const PlayerConfig = () => {
|
||||
const { t } = useTranslation();
|
||||
const { currentSong } = usePlayerData();
|
||||
const speed = usePlayerSpeed();
|
||||
const queueType = usePlayerQueueType();
|
||||
const status = usePlayerStatus();
|
||||
const playbackType = usePlaybackType();
|
||||
const { crossfadeDuration, crossfadeStyle, transitionType } = usePlayerProperties();
|
||||
const { setCrossfadeDuration, setCrossfadeStyle, setQueueType, setSpeed, setTransitionType } =
|
||||
usePlayerActions();
|
||||
@@ -70,22 +86,39 @@ export const PlayerConfig = () => {
|
||||
const [audioDevices, setAudioDevices] = useState<{ label: string; value: string }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAudioDevices = () => {
|
||||
getAudioDevice()
|
||||
.then((dev) =>
|
||||
setAudioDevices(dev.map((d) => ({ label: d.label, value: d.deviceId }))),
|
||||
)
|
||||
.catch(() =>
|
||||
const fetchAudioDevices = async () => {
|
||||
if (!isElectron()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playbackType === PlayerType.WEB) {
|
||||
getAudioDevice()
|
||||
.then((dev) =>
|
||||
setAudioDevices(dev.map((d) => ({ label: d.label, value: d.deviceId }))),
|
||||
)
|
||||
.catch(() =>
|
||||
toast.error({
|
||||
message: t('error.audioDeviceFetchError', {
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
}),
|
||||
);
|
||||
} else if (playbackType === PlayerType.LOCAL && mpvPlayer) {
|
||||
try {
|
||||
const devices = await getMpvAudioDevices();
|
||||
setAudioDevices(devices);
|
||||
} catch {
|
||||
toast.error({
|
||||
message: t('error.audioDeviceFetchError', { postProcess: 'sentenceCase' }),
|
||||
}),
|
||||
);
|
||||
message: t('error.audioDeviceFetchError', {
|
||||
postProcess: 'sentenceCase',
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (playbackSettings.type === PlayerType.WEB) {
|
||||
fetchAudioDevices();
|
||||
}
|
||||
}, [playbackSettings.type, t]);
|
||||
fetchAudioDevices();
|
||||
}, [playbackType, t]);
|
||||
|
||||
const options = useMemo(() => {
|
||||
const formatPlaybackSpeedSliderLabel = (value: number) => {
|
||||
@@ -161,15 +194,15 @@ export const PlayerConfig = () => {
|
||||
comboboxProps={{ withinPortal: false }}
|
||||
data={audioDevices}
|
||||
defaultValue={playbackSettings.audioDeviceId}
|
||||
disabled={playbackSettings.type !== PlayerType.WEB}
|
||||
onChange={(e) =>
|
||||
disabled={status === PlayerStatus.PLAYING}
|
||||
onChange={(e) => {
|
||||
setSettings({
|
||||
playback: {
|
||||
...playbackSettings,
|
||||
audioDeviceId: e,
|
||||
},
|
||||
})
|
||||
}
|
||||
});
|
||||
}}
|
||||
width="100%"
|
||||
/>
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user