Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Fix audio waveform seeking behaviors #633

Merged
merged 4 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions src/components/VAudioTrack/VAudioTrack.vue
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,41 @@ export default defineComponent({
const duration = computed(() => (props.audio.duration ?? 0) / 1e3) // seconds

const updateTime = () => {
if (window?.audioEl) {
if (
window?.audioEl &&
/**
* When the user switches from playing one audio track to another,
* say on the related audio section, if we don't check that the src
* of the audio element matches the source of the audio for this
* current instance of the audio track component, then we'll end up
* updating this instances `currentTime` ref to the value of the
* current time of the audio playing for the other element.
*
* The effect of this is that when you're switching audio tracks that
* are playing, the previous track that was playing will end up having
* it's current time set to the current time of the next audio track.
*/
window.audioEl.src === props.audio.url
) {
currentTime.value = window.audioEl.currentTime
if (currentTime.value >= duration.value) {
store.commit(`${ACTIVE}/${PAUSE_ACTIVE_MEDIA_ITEM}`)
status.value = 'played'
}
}
}

const updateTimeLoop = () => {
updateTime()
if (status.value === 'playing') {
// Audio is playing, keep looping
window.requestAnimationFrame(updateTimeLoop)
} else {
// Update time one last time on the next frame to try to fix
// some weird, difficult to reproduce, seemingly machine
// dependent bugs, described in the PR discussion below:
// https://github.com/WordPress/openverse-frontend/pull/633
window.requestAnimationFrame(updateTime)
}
}

Expand All @@ -158,7 +180,13 @@ export default defineComponent({
const elPlay = () => {
if (window?.audioEl) {
if (window.audioEl.src !== props.audio.url) {
window.audioEl.src = props.audio.url // resets position to zero
window.audioEl.src = props.audio.url
// Set the current time of the audio back to the seeked time
// of the waveform/timeline. In the future we might change
// this to reset the audio back to 0 anytime another audio
// is played but for now this is simpler and requires less
// cross-instance communication.
window.audioEl.currentTime = currentTime.value
Comment on lines +183 to +189
Copy link
Member

@zackkrida zackkrida Jan 19, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
window.audioEl.src = props.audio.url
// Set the current time of the audio back to the seeked time
// of the waveform/timeline. In the future we might change
// this to reset the audio back to 0 anytime another audio
// is played but for now this is simpler and requires less
// cross-instance communication.
window.audioEl.currentTime = currentTime.value
// Set the current time of the audio back to the seeked time
// of the waveform/timeline. In the future we might change
// this to reset the audio back to 0 anytime another audio
// is played but for now this is simpler and requires less
// cross-instance communication.
window.audioEl.currentTime = currentTime.value
window.audioEl.src = props.audio.url

@sarayourfriend this one weird trick fixes all of the problems for me! I haven't tested this + removing your other attempts to fix browser bugs but I will do so now.

Edit: Actually, this prevents the current track from being seeked prior to start.

}
window.audioEl.play()
}
Expand Down Expand Up @@ -239,9 +267,22 @@ export default defineComponent({

/* Interface with VWaveform */

/**
* Always update the current time ref when seeking happens
* for this audio track so that seeking can happen on one
* track even if it's not being played, and then that new
* time will get used if this instance's track gets played.
*
* Otherwise seeking will appear to not work on paused
* audio tracks.
*
* @param {number} frac
*/
const elSetTime = (frac) => {
const seekedTime = frac * (props.audio.duration / 1e3)
currentTime.value = seekedTime
if (window?.audioEl && isActiveTrack.value) {
window.audioEl.currentTime = frac * (props.audio.duration / 1e3)
window.audioEl.currentTime = seekedTime
}
}
const handleSeeked = (frac) => {
Expand Down
17 changes: 17 additions & 0 deletions src/components/VAudioTrack/VWaveform.vue
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,17 @@ export default defineComponent({
default: () => ['timestamps', 'seek'],
},
},
emits: [
/**
* Emitted when the waveform receives mouse events for seeking,
* either single clicks on a specific part of the waveform,
* or a click and drag.
*
* Also emitted when the waveform receives arrow key or home/end
* keyboard events that also correspond to seeking.
*/
'seeked',
],
setup(props, { emit }) {
/* Utils */

Expand Down Expand Up @@ -437,7 +448,13 @@ export default defineComponent({
emit('seeked', currentFrac.value + delta)
}
}

const willBeHandled = (event) =>
['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)

const handleKeys = (event) => {
if (!willBeHandled(event)) return

event.preventDefault()
if (['ArrowLeft', 'ArrowRight'].includes(event.key))
return handleArrowKeys(event)
Expand Down