diff --git a/src/electron/tray.js b/src/electron/tray.js index 3ae3436..02dec6e 100644 --- a/src/electron/tray.js +++ b/src/electron/tray.js @@ -21,51 +21,50 @@ export function createTray(win) { tray.on("right-click", () => { const contextMenu = Menu.buildFromTemplate([ { - label: "播放/暂停", - icon: "src/assets/icons/play.png", - click: () => { - win.webContents.send("play"); - }, + label: "播放/暂停", + icon: "src/assets/icons/play.png", + click: () => { + win.webContents.send("play"); }, - { - label: "上一首", - icon: "src/assets/icons/left.png", - accelerator: "CmdOrCtrl+Left", - click: () => { - win.webContents.send("previous"); - }, + }, + { + label: "上一首", + icon: "src/assets/icons/left.png", + accelerator: "CmdOrCtrl+Left", + click: () => { + win.webContents.send("previous"); }, - { - label: "下一首", - icon: "src/assets/icons/right.png", - accelerator: "CmdOrCtrl+Right", - click: () => { - win.webContents.send("next"); - }, + }, + { + label: "下一首", + icon: "src/assets/icons/right.png", + accelerator: "CmdOrCtrl+Right", + click: () => { + win.webContents.send("next"); }, - { - label: "循环播放", - icon: "src/assets/icons/repeat.png", - accelerator: "Alt+R", - click: () => { - win.webContents.send("repeat"); - }, + }, + { + label: "循环播放", + icon: "src/assets/icons/repeat.png", + accelerator: "Alt+R", + click: () => { + win.webContents.send("repeat"); }, - { - label: "加入喜欢", - icon: "src/assets/icons/like.png", - accelerator: "CmdOrCtrl+L", - click: () => { - win.webContents.send("like"); - }, + }, + { + label: "加入喜欢", + icon: "src/assets/icons/like.png", + accelerator: "CmdOrCtrl+L", + click: () => { + win.webContents.send("like"); }, - { - label: "退出", - icon: "src/assets/icons/exit.png", - accelerator: "CmdOrCtrl+W", - click: () => { - app.exit(); - }, + }, + { + label: "退出", + icon: "src/assets/icons/exit.png", + accelerator: "CmdOrCtrl+W", + click: () => { + app.exit(); }, }, ]); diff --git a/src/locale/lang/en.js b/src/locale/lang/en.js index 379e693..f3052fe 100644 --- a/src/locale/lang/en.js +++ b/src/locale/lang/en.js @@ -117,6 +117,7 @@ export default { high: "High", lossless: "Lossless", }, + deviceSelector: "Output Device", appearance: { text: "Appearance", auto: "Auto", diff --git a/src/locale/lang/zh-CN.js b/src/locale/lang/zh-CN.js index 0d00f68..121e162 100644 --- a/src/locale/lang/zh-CN.js +++ b/src/locale/lang/zh-CN.js @@ -118,6 +118,7 @@ export default { high: "极高", lossless: "无损", }, + deviceSelector: "音频输出设备", appearance: { text: "外观", auto: "自动", diff --git a/src/store/initLocalStorage.js b/src/store/initLocalStorage.js index e08997e..3802ed3 100644 --- a/src/store/initLocalStorage.js +++ b/src/store/initLocalStorage.js @@ -7,6 +7,7 @@ let localStorage = { lang: null, appearance: "auto", musicQuality: 320000, + outputDevice: "default", showGithubIcon: true, showPlaylistsByAppleMusic: true, showUnavailableSongInGreyStyle: true, diff --git a/src/store/mutations.js b/src/store/mutations.js index 66a66af..c166d12 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -9,6 +9,9 @@ export default { changeMusicQuality(state, value) { state.settings.musicQuality = value; }, + changeOutputDevice(state, deviceId) { + state.settings.outputDevice = deviceId; + }, updateSettings(state, { key, value }) { state.settings[key] = value; }, diff --git a/src/utils/Player.js b/src/utils/Player.js index 9bf98df..db594cf 100644 --- a/src/utils/Player.js +++ b/src/utils/Player.js @@ -102,6 +102,8 @@ export default class { _init() { Howler.autoUnlock = false; + Howler.usingWebAudio = true; + Howler.masterGain = true; this._loadSelfFromLocalStorage(); this._replaceCurrentTrack(this._currentTrack.id, false).then(() => { this._howler.seek(localStorage.getItem("playerCurrentTrackTime") ?? 0); @@ -150,11 +152,27 @@ export default class { time, }); } + _setupAudioNode() { + Howler.masterGain.disconnect(); + const mediaStreamNode = Howler.ctx.createMediaStreamDestination(); + Howler.masterGain.connect(mediaStreamNode); + let audio = ''; + if (document.querySelector('audio') !== null) { + audio = document.querySelector('audio'); + } else { + audio = document.createElement('audio'); + document.body.append(audio); + } + audio.autoplay = true; + audio.srcObject = mediaStreamNode.stream; + audio.setSinkId(store.state.settings.outputDevice); + } _playAudioSource(source, autoplay = true) { Howler.unload(); + this._setupAudioNode(); this._howler = new Howl({ src: [source], - html5: true, + html5: false, format: ["mp3", "flac"], }); if (autoplay) { diff --git a/src/views/settings.vue b/src/views/settings.vue index 6432ea2..2084dcd 100644 --- a/src/views/settings.vue +++ b/src/views/settings.vue @@ -74,6 +74,18 @@ +