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.
This commit is contained in:
Tony Wasserka 2021-03-24 15:46:53 +01:00
parent 38f0fd3b60
commit 7900c2d065
4 changed files with 47 additions and 14 deletions

View File

@ -96,7 +96,7 @@
v-if="!playing"
:title="labels.play"
:aria-label="labels.play"
@click.prevent.stop="togglePlay"
@click.prevent.stop="resumePlayback"
class="control">
<i :class="['ui', 'play', {'disabled': !currentTrack}, 'icon']"></i>
</span>
@ -105,7 +105,7 @@
v-else
:title="labels.pause"
:aria-label="labels.pause"
@click.prevent.stop="togglePlay"
@click.prevent.stop="pausePlayback"
class="control">
<i :class="['ui', 'pause', {'disabled': !currentTrack}, 'icon']"></i>
</span>
@ -308,7 +308,8 @@ export default {
unmute: "player/unmute",
clean: "queue/clean",
toggleMute: "player/toggleMute",
togglePlay: "player/togglePlay",
resumePlayback: "player/resumePlayback",
pausePlayback: "player/pausePlayback",
}),
reorder: function(event) {
this.$store.commit("queue/reorder", {

View File

@ -74,7 +74,7 @@
v-if="!playing"
:title="labels.play"
:aria-label="labels.play"
@click.prevent.stop="togglePlay"
@click.prevent.stop="resumePlayback"
class="circular button control">
<i :class="['ui', 'big', 'play', {'disabled': !currentTrack}, 'icon']"></i>
</button>
@ -82,7 +82,7 @@
v-else
:title="labels.pause"
:aria-label="labels.pause"
@click.prevent.stop="togglePlay"
@click.prevent.stop="pausePlayback"
class="circular button control">
<i :class="['ui', 'big', 'pause', {'disabled': !currentTrack}, 'icon']"></i>
</button>
@ -203,7 +203,7 @@
</div>
</div>
<GlobalEvents
@keydown.p.prevent.exact="togglePlay"
@keydown.p.prevent.exact="togglePlayback"
@keydown.esc.prevent.exact="$store.commit('ui/queueFocused', null)"
@keydown.ctrl.shift.left.prevent.exact="previous"
@keydown.ctrl.shift.right.prevent.exact="next"
@ -281,8 +281,8 @@ export default {
}
// Add controls for notification drawer
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('play', this.togglePlay);
navigator.mediaSession.setActionHandler('pause', this.togglePlay);
navigator.mediaSession.setActionHandler('play', this.resumePlayback);
navigator.mediaSession.setActionHandler('pause', this.pausePlayback);
navigator.mediaSession.setActionHandler('seekforward', this.seekForward);
navigator.mediaSession.setActionHandler('seekbackward', this.seekBackward);
navigator.mediaSession.setActionHandler('nexttrack', this.next);
@ -297,7 +297,9 @@ export default {
},
methods: {
...mapActions({
togglePlay: "player/togglePlay",
resumePlayback: "player/resumePlayback",
pausePlayback: "player/pausePlayback",
togglePlayback: "player/togglePlayback",
mute: "player/mute",
unmute: "player/unmute",
clean: "queue/clean",

View File

@ -99,7 +99,7 @@ export default {
commit('errored', false)
commit('resetErrorCount')
},
togglePlay ({commit, state, dispatch}) {
togglePlayback ({commit, state, dispatch}) {
commit('playing', !state.playing)
if (state.errored && state.errorCount < state.maxConsecutiveErrors) {
setTimeout(() => {
@ -109,6 +109,19 @@ export default {
}, 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}) {
if (state.volume > 0) {
commit('tempVolume', state.volume)

View File

@ -112,24 +112,41 @@ describe('store/player', () => {
]
})
})
it('toggle play false', () => {
it('toggle playback false', () => {
testAction({
action: store.actions.togglePlay,
action: store.actions.togglePlayback,
params: {state: {playing: false}},
expectedMutations: [
{ type: 'playing', payload: true }
]
})
})
it('toggle play true', () => {
it('toggle playback true', () => {
testAction({
action: store.actions.togglePlay,
action: store.actions.togglePlayback,
params: {state: {playing: true}},
expectedMutations: [
{ 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', () => {
testAction({
action: store.actions.trackEnded,