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

Add handling for media errors in audio track #163

Merged
merged 4 commits into from
Aug 27, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
29 changes: 26 additions & 3 deletions src/components/AudioTrack/AudioTrack.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@
@toggle="setPlayerState"
/>
<div
class="flex-grow"
@keypress.enter="setPlayerState(!isPlaying)"
@keypress.space="setPlayerState(!isPlaying)"
>
<Waveform
:class="isCompact ? 'h-20' : 'h-30'"
:is-ready="isReady"
:message="message ? $t(`audio-track.messages.${message}`) : null"
:current-time="currentTime"
:duration="duration"
:peaks="audio.peaks"
Expand Down Expand Up @@ -83,6 +84,7 @@
"
@play="setIsPlaying(true)"
@pause="setIsPlaying(false)"
@error="handleError"
/>
<!-- eslint-enable vuejs-accessibility/media-has-caption -->
</div>
Expand Down Expand Up @@ -120,7 +122,7 @@ export default {
player: null, // HTMLAudioElement
currentTime: 0,
duration: 0,
isReady: false,
message: 'loading',
isPlaying: false,
}),
computed: {
Expand All @@ -135,6 +137,10 @@ export default {
date.setSeconds(seconds)
return date.toISOString().substr(11, 8).replace(/^00:/, '')
},

isReady() {
return this.message === null
},
},
mounted() {
this.player = this.$refs.audio
Expand Down Expand Up @@ -172,11 +178,28 @@ export default {

// HTMLAudioElement events
setIsReady() {
this.isReady = true
this.message = null
},
setIsPlaying(isPlaying) {
this.isPlaying = isPlaying
},
handleError(event) {
const error = event.target.error
switch (error.code) {
case error.MEDIA_ERR_ABORTED:
this.message = 'err_aborted'
break
case error.MEDIA_ERR_NETWORK:
this.message = 'err_network'
break
case error.MEDIA_ERR_DECODE:
this.message = 'err_decode'
break
case error.MEDIA_ERR_SRC_NOT_SUPPORTED:
this.message = 'err_unsupported'
break
}
},
},
}
</script>
24 changes: 15 additions & 9 deletions src/components/AudioTrack/Waveform.vue
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@
</div>
</template>

<!-- Loading overlay -->
<!-- Message overlay -->
<div
v-else
class="absolute inset-x-0 inset-y-0 flex items-center justify-center loading font-bold text-sm"
>
{{ $t('waveform.loading') }}
{{ message }}
</div>
</div>
</template>
Expand Down Expand Up @@ -108,11 +108,11 @@ export default {
validator: (val) => val.every((item) => item >= 0 && item <= 1),
},
/**
* whether the audio metadata has been loaded and is ready to display
* the message to display instead of the waveform; This is useful when
* displaying a loading or error state.
*/
isReady: {
type: Boolean,
default: false,
message: {
type: String,
},
/**
* the current play time of the audio track
Expand Down Expand Up @@ -185,6 +185,10 @@ export default {
observer.disconnect()
})

/* State */

const isReady = computed(() => !props.message)

/* Resampling */

const barWidth = 2
Expand Down Expand Up @@ -221,7 +225,7 @@ export default {
/* Progress bar */

const currentFrac = computed(() =>
props.isReady ? props.currentTime / props.duration : 0
isReady.value ? props.currentTime / props.duration : 0
)
const progressBarWidth = computed(() => {
const frac = isDragging.value ? seekFrac.value : currentFrac.value
Expand All @@ -248,10 +252,10 @@ export default {
* the seek jump length as a % of the track
*/
const seekDeltaFrac = computed(() => {
return props.isReady ? seekDelta / props.duration : 0
return isReady.value ? seekDelta / props.duration : 0
})
const modSeekDeltaFrac = computed(() =>
props.isReady ? modSeekDelta / props.duration : 0
isReady.value ? modSeekDelta / props.duration : 0
)
const setSeekProgress = (event) => {
seekFrac.value = getPositionFrac(event)
Expand Down Expand Up @@ -307,6 +311,8 @@ export default {

el, // template ref

isReady,

barWidth,
normalizedPeaks,

Expand Down
12 changes: 5 additions & 7 deletions src/components/AudioTrack/meta/Waveform.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ Here 9 points are upsampled to as many as required to fill the viewport.
name="Upsampling"
args={{
peaks: [0.5, 1, 0.5, 0, 0.5, 1, 0.5, 0, 0.5], // triangular wave with 9 points
isReady: true,
currentTime: 2,
duration: 10,
showDuration: true,
Expand All @@ -67,7 +66,6 @@ Here 1000 points are downsampled to as many as required to fill the viewport.
{ length: 1000 },
(_, k) => 0.5 * Math.sin((k * 2 * Math.PI) / 500) + 0.5
), // sine wave with 1000 points
isReady: true,
currentTime: 2,
duration: 10,
showDuration: true,
Expand All @@ -87,16 +85,16 @@ The waveform always takes the height and width of its container.
Thus the `barWidth` and `barGap` will be maintained even in the case of
horizontal scaling.

## Loading state
## Message state

The waveform bars are set to zero height when loading. They will animate up to
their actual height when the `isReady` prop is set to `true`.
The waveform bars are set to zero height when the `message` prop is passed. They
will animate up to their actual height when the prop is unset.

<Canvas>
<Story
name="Loading"
name="Message"
args={{
isReady: false,
message: 'Hello, World!',
}}
>
{Template.bind({})}
Expand Down
10 changes: 8 additions & 2 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -571,12 +571,18 @@
},
"waveform": {
"label": "Audio seek bar",
"loading": "Loading...",
"current-time": "{time} seconds"
},
"audio-track": {
"title": "{title} by {creator}",
"aria-label": "Audio Player"
"aria-label": "Audio Player",
"messages": {
"err_aborted": "You aborted playback.",
"err_network": "A network error occurred.",
"err_decode": "Could not decode audio.",
"err_unsupported": "The media provider is unsuitable.",
dhruvkb marked this conversation as resolved.
Show resolved Hide resolved
"loading": "Loading..."
}
},
"play-pause": {
"play": "Play",
Expand Down