Skip to content

Commit b7a0a37

Browse files
committed
Enable audio playback for dashboard route clips
1 parent 342d3db commit b7a0a37

3 files changed

Lines changed: 38 additions & 6 deletions

File tree

src/App.browser.test.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
2-
import { configure, render, waitFor } from '@solidjs/testing-library'
2+
import { configure, fireEvent, render, waitFor } from '@solidjs/testing-library'
33

44
import { setAccessToken, signOut } from '~/api/auth/client'
55
import * as Demo from '~/api/auth/demo'
@@ -26,10 +26,14 @@ describe('Demo mode', () => {
2626
})
2727

2828
test('View demo route', async () => {
29-
const { findByText, findByTestId } = renderApp(`/${Demo.DONGLE_ID}/${DEMO_LOG_ID}`)
29+
const { findByLabelText, findByText, findByTestId } = renderApp(`/${Demo.DONGLE_ID}/${DEMO_LOG_ID}`)
3030
expect(await findByText(DEMO_LOG_ID)).toBeTruthy()
3131
const video = (await findByTestId('route-video')) as HTMLVideoElement
3232
await waitFor(() => expect(video.src).toBeTruthy())
33+
expect(video.muted).toBe(true)
34+
await fireEvent.click(await findByLabelText('Unmute'))
35+
expect(video.muted).toBe(false)
36+
expect(await findByLabelText('Mute')).toBeTruthy()
3337
})
3438
})
3539

src/components/RouteVideoPlayer.tsx

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const RouteVideoPlayer: VoidComponent<RouteVideoPlayerProps> = (props) => {
2525
let controls!: HTMLDivElement
2626

2727
const [isPlaying, setIsPlaying] = createSignal(true)
28+
const [isMuted, setIsMuted] = createSignal(true)
2829
const [currentTime, setCurrentTime] = createSignal(0)
2930
const [duration, setDuration] = createSignal(0)
3031
const [videoLoading, setVideoLoading] = createSignal(true)
@@ -47,14 +48,28 @@ const RouteVideoPlayer: VoidComponent<RouteVideoPlayerProps> = (props) => {
4748
const startProgressTracking = () => {
4849
requestAnimationFrame(updateProgressContinuously)
4950
}
51+
const requestPlay = () => {
52+
const playResult = video.play()
53+
if (playResult) {
54+
void playResult.catch((error: unknown) => {
55+
if (error instanceof DOMException && error.name === 'AbortError') return
56+
console.debug('[RouteVideoPlayer] play interrupted', error)
57+
})
58+
}
59+
}
5060

5161
const togglePlayback = () => {
5262
if (video.paused) {
53-
void video.play()
63+
requestPlay()
5464
} else {
5565
video.pause()
5666
}
5767
}
68+
const toggleMuted = (e: Event) => {
69+
e.preventDefault()
70+
e.stopPropagation()
71+
setIsMuted((muted) => !muted)
72+
}
5873
const onClick = (e: Event) => {
5974
e.preventDefault()
6075
togglePlayback()
@@ -83,14 +98,16 @@ const RouteVideoPlayer: VoidComponent<RouteVideoPlayerProps> = (props) => {
8398
const onEnded = () => setIsPlaying(false)
8499
const onStalled = () => {
85100
if (!isPlaying()) return
86-
void video.play()
101+
requestPlay()
87102
}
88103

89104
onMount(() => {
90105
if (props.selection.startTime > 0) {
91106
video.currentTime = props.selection.startTime
92107
}
93108

109+
video.defaultMuted = true
110+
video.muted = true
94111
props.ref?.(video)
95112

96113
controls.addEventListener('click', onClick)
@@ -143,9 +160,17 @@ const RouteVideoPlayer: VoidComponent<RouteVideoPlayerProps> = (props) => {
143160
on(routeName, () => {
144161
setVideoLoading(true)
145162
setErrorMessage('')
163+
setIsMuted(true)
146164
}),
147165
)
148166

167+
createEffect(() => {
168+
if (!video) return
169+
const muted = isMuted()
170+
video.defaultMuted = muted
171+
video.muted = muted
172+
})
173+
149174
createEffect(() => {
150175
const url = streamUrl()
151176
const player = hls()
@@ -172,7 +197,7 @@ const RouteVideoPlayer: VoidComponent<RouteVideoPlayerProps> = (props) => {
172197
class="size-full object-cover"
173198
data-testid="route-video"
174199
autoplay
175-
muted
200+
muted={isMuted()}
176201
controls={false}
177202
playsinline
178203
loop
@@ -205,6 +230,9 @@ const RouteVideoPlayer: VoidComponent<RouteVideoPlayerProps> = (props) => {
205230
<div class="font-mono text-sm text-on-surface">
206231
{formatVideoTime(currentTime())} / {formatVideoTime(duration())}
207232
</div>
233+
234+
<div class="grow" />
235+
<IconButton name={isMuted() ? 'volume_off' : 'volume_up'} aria-label={isMuted() ? 'Unmute' : 'Mute'} onClick={toggleMuted} />
208236
</div>
209237
</div>
210238
</div>

src/components/material/Icon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const Icons = [
88
'add', 'arrow_back', 'camera', 'check', 'chevron_right', 'clear', 'close', 'delete', 'description', 'directions_car', 'download', 'error',
99
'file_copy', 'flag', 'info', 'keyboard_arrow_down', 'keyboard_arrow_up', 'local_fire_department', 'logout', 'menu', 'my_location',
1010
'open_in_new', 'payments', 'person', 'progress_activity', 'satellite_alt', 'search', 'settings', 'upload', 'videocam', 'refresh',
11-
'login', 'person_off', 'autorenew', 'close_small', 'pause', 'play_arrow', 'clear_all',
11+
'login', 'person_off', 'autorenew', 'close_small', 'pause', 'play_arrow', 'clear_all', 'volume_off', 'volume_up',
1212
] as const
1313

1414
export type IconName = (typeof Icons)[number]

0 commit comments

Comments
 (0)