Skip to content
Snippets Groups Projects
Commit 7900c2d0 authored by Tony Wasserka's avatar Tony Wasserka
Browse files

Properly handle redundant MediaSession play/pause requests

MediaSession pause requests may happen even when Funkwhale is already in a
paused state. Previously FW would flip between play/pause without
consideration for the current state instead of doing nothing when
the playback state matches the requested one.

Notably, this made Funkwhale resume audio playback when entering sleep mode
on my system.
parent 38f0fd3b
No related branches found
No related tags found
No related merge requests found
...@@ -96,7 +96,7 @@ ...@@ -96,7 +96,7 @@
v-if="!playing" v-if="!playing"
:title="labels.play" :title="labels.play"
:aria-label="labels.play" :aria-label="labels.play"
@click.prevent.stop="togglePlay" @click.prevent.stop="resumePlayback"
class="control"> class="control">
<i :class="['ui', 'play', {'disabled': !currentTrack}, 'icon']"></i> <i :class="['ui', 'play', {'disabled': !currentTrack}, 'icon']"></i>
</span> </span>
...@@ -105,7 +105,7 @@ ...@@ -105,7 +105,7 @@
v-else v-else
:title="labels.pause" :title="labels.pause"
:aria-label="labels.pause" :aria-label="labels.pause"
@click.prevent.stop="togglePlay" @click.prevent.stop="pausePlayback"
class="control"> class="control">
<i :class="['ui', 'pause', {'disabled': !currentTrack}, 'icon']"></i> <i :class="['ui', 'pause', {'disabled': !currentTrack}, 'icon']"></i>
</span> </span>
...@@ -308,7 +308,8 @@ export default { ...@@ -308,7 +308,8 @@ export default {
unmute: "player/unmute", unmute: "player/unmute",
clean: "queue/clean", clean: "queue/clean",
toggleMute: "player/toggleMute", toggleMute: "player/toggleMute",
togglePlay: "player/togglePlay", resumePlayback: "player/resumePlayback",
pausePlayback: "player/pausePlayback",
}), }),
reorder: function(event) { reorder: function(event) {
this.$store.commit("queue/reorder", { this.$store.commit("queue/reorder", {
......
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
v-if="!playing" v-if="!playing"
:title="labels.play" :title="labels.play"
:aria-label="labels.play" :aria-label="labels.play"
@click.prevent.stop="togglePlay" @click.prevent.stop="resumePlayback"
class="circular button control"> class="circular button control">
<i :class="['ui', 'big', 'play', {'disabled': !currentTrack}, 'icon']"></i> <i :class="['ui', 'big', 'play', {'disabled': !currentTrack}, 'icon']"></i>
</button> </button>
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
v-else v-else
:title="labels.pause" :title="labels.pause"
:aria-label="labels.pause" :aria-label="labels.pause"
@click.prevent.stop="togglePlay" @click.prevent.stop="pausePlayback"
class="circular button control"> class="circular button control">
<i :class="['ui', 'big', 'pause', {'disabled': !currentTrack}, 'icon']"></i> <i :class="['ui', 'big', 'pause', {'disabled': !currentTrack}, 'icon']"></i>
</button> </button>
...@@ -203,7 +203,7 @@ ...@@ -203,7 +203,7 @@
</div> </div>
</div> </div>
<GlobalEvents <GlobalEvents
@keydown.p.prevent.exact="togglePlay" @keydown.p.prevent.exact="togglePlayback"
@keydown.esc.prevent.exact="$store.commit('ui/queueFocused', null)" @keydown.esc.prevent.exact="$store.commit('ui/queueFocused', null)"
@keydown.ctrl.shift.left.prevent.exact="previous" @keydown.ctrl.shift.left.prevent.exact="previous"
@keydown.ctrl.shift.right.prevent.exact="next" @keydown.ctrl.shift.right.prevent.exact="next"
...@@ -281,8 +281,8 @@ export default { ...@@ -281,8 +281,8 @@ export default {
} }
// Add controls for notification drawer // Add controls for notification drawer
if ('mediaSession' in navigator) { if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('play', this.togglePlay); navigator.mediaSession.setActionHandler('play', this.resumePlayback);
navigator.mediaSession.setActionHandler('pause', this.togglePlay); navigator.mediaSession.setActionHandler('pause', this.pausePlayback);
navigator.mediaSession.setActionHandler('seekforward', this.seekForward); navigator.mediaSession.setActionHandler('seekforward', this.seekForward);
navigator.mediaSession.setActionHandler('seekbackward', this.seekBackward); navigator.mediaSession.setActionHandler('seekbackward', this.seekBackward);
navigator.mediaSession.setActionHandler('nexttrack', this.next); navigator.mediaSession.setActionHandler('nexttrack', this.next);
...@@ -297,7 +297,9 @@ export default { ...@@ -297,7 +297,9 @@ export default {
}, },
methods: { methods: {
...mapActions({ ...mapActions({
togglePlay: "player/togglePlay", resumePlayback: "player/resumePlayback",
pausePlayback: "player/pausePlayback",
togglePlayback: "player/togglePlayback",
mute: "player/mute", mute: "player/mute",
unmute: "player/unmute", unmute: "player/unmute",
clean: "queue/clean", clean: "queue/clean",
......
...@@ -99,7 +99,7 @@ export default { ...@@ -99,7 +99,7 @@ export default {
commit('errored', false) commit('errored', false)
commit('resetErrorCount') commit('resetErrorCount')
}, },
togglePlay ({commit, state, dispatch}) { togglePlayback ({commit, state, dispatch}) {
commit('playing', !state.playing) commit('playing', !state.playing)
if (state.errored && state.errorCount < state.maxConsecutiveErrors) { if (state.errored && state.errorCount < state.maxConsecutiveErrors) {
setTimeout(() => { setTimeout(() => {
...@@ -109,6 +109,19 @@ export default { ...@@ -109,6 +109,19 @@ export default {
}, 3000) }, 3000)
} }
}, },
resumePlayback ({commit, state, dispatch}) {
commit('playing', true)
if (state.errored && state.errorCount < state.maxConsecutiveErrors) {
setTimeout(() => {
if (state.playing) {
dispatch('queue/next', null, {root: true})
}
}, 3000)
}
},
pausePlayback ({commit}) {
commit('playing', false)
},
toggleMute({commit, state}) { toggleMute({commit, state}) {
if (state.volume > 0) { if (state.volume > 0) {
commit('tempVolume', state.volume) commit('tempVolume', state.volume)
......
...@@ -112,24 +112,41 @@ describe('store/player', () => { ...@@ -112,24 +112,41 @@ describe('store/player', () => {
] ]
}) })
}) })
it('toggle play false', () => { it('toggle playback false', () => {
testAction({ testAction({
action: store.actions.togglePlay, action: store.actions.togglePlayback,
params: {state: {playing: false}}, params: {state: {playing: false}},
expectedMutations: [ expectedMutations: [
{ type: 'playing', payload: true } { type: 'playing', payload: true }
] ]
}) })
}) })
it('toggle play true', () => { it('toggle playback true', () => {
testAction({ testAction({
action: store.actions.togglePlay, action: store.actions.togglePlayback,
params: {state: {playing: true}}, params: {state: {playing: true}},
expectedMutations: [ expectedMutations: [
{ type: 'playing', payload: false } { type: 'playing', payload: false }
] ]
}) })
}) })
it('resume playback', () => {
testAction({
action: store.actions.resumePlayback,
params: {state: {}},
expectedMutations: [
{ type: 'playing', payload: true }
]
})
})
it('pause playback', () => {
testAction({
action: store.actions.pausePlayback,
expectedMutations: [
{ type: 'playing', payload: false }
]
})
})
it('trackEnded', () => { it('trackEnded', () => {
testAction({ testAction({
action: store.actions.trackEnded, action: store.actions.trackEnded,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment