Playing Audio and Video

<audio> and <video> (Multimedia) share HTMLMediaElement; new Audio(url) needs no markup. play() returns a promise that rejects with NotAllowedError when the autoplay policy blocks sound before any user interaction, or NotSupportedError when no source is playable.

The HTMLMediaElement API at a glance
Kind Most-used members
Methods play(), pause(), load(), canPlayType(type)
Position currentTime, duration, paused, ended, loop
Sound and speed volume (0-1), muted, playbackRate
Loading src, currentSrc, readyState, buffered (Timing Media Clips)
Events loadedmetadata, playing, pause, timeupdate, ended, error
Checking formats and a promise-aware play buttonHTMLLive
<button id="toggle">Play</button><pre id="log"></pre>
<script type="module">
  const audio = new Audio('alarm.mp3');
  const button = document.querySelector('#toggle');
  button.addEventListener('click', () => (audio.paused
    ? audio.play().catch((err) => { button.textContent = err.name; }) : audio.pause()));
  audio.addEventListener('play', () => { button.textContent = 'Pause'; });
  audio.addEventListener('pause', () => { button.textContent = 'Play'; });
  document.querySelector('#log').textContent = ['audio/mpeg', 'audio/flac', 'video/x-flv']
    .map((type) => `canPlayType('${type}'): "${audio.canPlayType(type)}"`).join('\n');
</script>
Browser output of Listing 8.35
Browser output of 35

canPlayType() answers "probably", "maybe" or "". Update the UI from play and pause events, since media keys change state too. Autoplaying video must be muted. For per-frame work use requestVideoFrameCallback() (Baseline since October 2024); timeupdate fires only about 4 to 66 times a second.