@@ -72,6 +72,38 @@ const getOptimisedPosterImage = (mainImage: string): string => {
72
72
} ) ;
73
73
} ;
74
74
75
+ /**
76
+ * Runs a series of browser-specific checks to determine if the video has audio.
77
+ */
78
+ const doesVideoHaveAudio = ( video : HTMLVideoElement ) : boolean => {
79
+ // If there exists a browser that does not support any of these properties, we are
80
+ // unable to detect whether the video has audio. Therefore, we assume it has audio,
81
+ // so that the unmute/mute icon is displayed.
82
+ if (
83
+ ! ( 'mozHasAudio' in video ) &&
84
+ ! ( 'webkitAudioDecodedByteCount' in video ) &&
85
+ ! ( 'audioTracks' in video )
86
+ ) {
87
+ // Gather data on what browsers do not support these properties.
88
+ window . guardian . modules . sentry . reportError (
89
+ new Error (
90
+ 'Could not determine if video has audio. This is likely due to the browser not supporting the necessary properties.' ,
91
+ ) ,
92
+ 'loop-video' ,
93
+ ) ;
94
+
95
+ return true ;
96
+ }
97
+
98
+ return (
99
+ ( 'mozHasAudio' in video && Boolean ( video . mozHasAudio ) ) ||
100
+ ( 'webkitAudioDecodedByteCount' in video &&
101
+ Boolean ( video . webkitAudioDecodedByteCount ) ) ||
102
+ ( 'audioTracks' in video &&
103
+ Boolean ( ( video . audioTracks as { length : number } ) . length ) )
104
+ ) ;
105
+ } ;
106
+
75
107
type Props = {
76
108
src : string ;
77
109
atomId : string ;
@@ -104,6 +136,7 @@ export const LoopVideo = ({
104
136
const vidRef = useRef < HTMLVideoElement > ( null ) ;
105
137
const [ isPlayable , setIsPlayable ] = useState ( false ) ;
106
138
const [ isMuted , setIsMuted ] = useState ( true ) ;
139
+ const [ hasAudio , setHasAudio ] = useState ( true ) ;
107
140
const [ showPlayIcon , setShowPlayIcon ] = useState ( false ) ;
108
141
const [ preloadPartialData , setPreloadPartialData ] = useState ( false ) ;
109
142
const [ showPosterImage , setShowPosterImage ] = useState < boolean > ( false ) ;
@@ -277,7 +310,7 @@ export const LoopVideo = ({
277
310
true ,
278
311
) ;
279
312
} catch ( error ) {
280
- console . error ( 'Failed to track video attention:' , error ) ;
313
+ log ( 'dotcom' , 'Failed to track video attention:' , error ) ;
281
314
}
282
315
} ;
283
316
@@ -410,6 +443,12 @@ export const LoopVideo = ({
410
443
return FallbackImageComponent ;
411
444
}
412
445
446
+ const handleLoadedData = ( ) => {
447
+ if ( vidRef . current ) {
448
+ setHasAudio ( doesVideoHaveAudio ( vidRef . current ) ) ;
449
+ }
450
+ } ;
451
+
413
452
const handleCanPlay = ( ) => {
414
453
if ( ! isPlayable ) {
415
454
setIsPlayable ( true ) ;
@@ -541,13 +580,14 @@ export const LoopVideo = ({
541
580
isPlayable = { isPlayable }
542
581
playerState = { playerState }
543
582
isMuted = { isMuted }
583
+ handleLoadedData = { handleLoadedData }
544
584
handleCanPlay = { handleCanPlay }
545
585
handlePlayPauseClick = { handlePlayPauseClick }
546
586
handleAudioClick = { handleAudioClick }
547
587
handleKeyDown = { handleKeyDown }
548
588
handlePause = { handlePause }
549
589
onError = { onError }
550
- AudioIcon = { AudioIcon }
590
+ AudioIcon = { hasAudio ? AudioIcon : null }
551
591
preloadPartialData = { preloadPartialData }
552
592
showPlayIcon = { showPlayIcon }
553
593
/>
0 commit comments