【web音频学习(四)】音频数据播放

151 阅读2分钟

前言

在 Web 开发中,浏览器为我们提供了三种主要的音频播放方式,各自适用于不同的场景:

  • <audio> 标签:只接受字符串形式的 src,可播放普通 URLObject URL Data URI(Base64)等音频资源。 阿
  • Audio 对象:API 与 <audio> 标签完全一致,更适合在 JS 中动态创建与复用。
  • AudioContext 对象:用于处理二进制音频数据(如 AudioBuffer),支持可视化、合成、特效等高级操作。

注意:无论使用哪种方式,浏览器的音频播放通常都需要用户交互(如点击按钮)来触发。
相关阅读:【Web 音频学习(二)】获取设备播放和麦克风权限

音频播放

<audio> 标签

<body>
    <audio id="audio" src="https://audio-1304256198.cos.ap-guangzhou.myqcloud.com/%E4%BA%B2%E5%88%87%E5%A5%B3%E5%A3%B0.mp3 "></audio>
    <button id="play">播放</button>
    <script>
        const playButton = document.getElementById('play')
        const audioElement = document.getElementById('audio')
        playButton.addEventListener('click', () => {
            audioElement.play().then(() => {
                console.log('播放成功')
            })
        })
    </script>
</body>

Audio 对象

<body>
    <button id="play">播放</button>
    <script>
        const playButton = document.getElementById('play')
        playButton.addEventListener('click', () => {
            const audioUrl = 'https://audio-1304256198.cos.ap-guangzhou.myqcloud.com/%E4%BA%B2%E5%88%87%E5%A5%B3%E5%A3%B0.mp3'
            const audioElement = new Audio(audioUrl)
            audioElement.play()
        })
    </script>
</body>

当然,<audio> 标签与 Audio 对象也能播放更复杂的类型,只需先转成 URL 即可:

  • BlobFile:通过 URL.createObjectURL 转换成 URL 后播放。
  • Base64:先转为 ArrayBuffer,再通过 URL.createObjectURL 生成 URL 播放。

相关阅读:前端也要学的“文件转换规则”知识

AudioContext 对象

AudioContext 通过连接各类 AudioNode 组成 音频路由图 来播放音频。支持的数据源几乎覆盖 Web 端所有类型:URLBlobFileArrayBufferWebRTC 媒体流、Base64等……。

更关键的是,它能在二进制层面直接处理音频:频谱分析、动态压缩、音量调节、采样率转换、3D 空间化等,都可实时完成。

相关阅读:【web音频学习(三)】 Web Audio API的使用

audioUrl

<body>
    <button id="playBtn">播放</button>
    <script>
        (async () => {
            const playButton = document.getElementById('playBtn')
            const audioUrl = 'https://audio-1304256198.cos.ap-guangzhou.myqcloud.com/%E4%BA%B2%E5%88%87%E5%A5%B3%E5%A3%B0.mp3'

            playButton.addEventListener('click', async () => {
                const response = await fetch(audioUrl)
                const arrayBuffer = await response.arrayBuffer()

                const audioContext = new AudioContext()
                const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)
                const sourceNode = audioContext.createBufferSource()
                sourceNode.buffer = audioBuffer
                sourceNode.connect(audioContext.destination)
                sourceNode.start()
            })
        })()
    </script>
</body>

File

<body>
    <button id="play">播放</button>
    <script>
        const playButton = document.getElementById('play')


        async function generateFile() {
            const audioUrl = 'https://audio-1304256198.cos.ap-guangzhou.myqcloud.com/%E4%BA%B2%E5%88%87%E5%A5%B3%E5%A3%B0.mp3'
            const response = await fetch(audioUrl)
            const arrayBuffer = await response.arrayBuffer()
            return new File([arrayBuffer], { type: 'audio/mpeg' })
        }

        playButton.addEventListener('click', async () => {
            const file = await generateFile()
           
            const audioContext = new AudioContext()   
            const audioBuffer = await audioContext.decodeAudioData(await file.arrayBuffer())
            const sourceNode = audioContext.createBufferSource()
            sourceNode.buffer = audioBuffer
            sourceNode.connect(audioContext.destination)
            sourceNode.start()
        })
    </script>
</body>

Base64

<body>
    <button id="playBtn">播放</button>
    <script>
        (async () => {
            const playButton = document.getElementById('playBtn')

            async function generateBase64String() {
                const audioUrl = 'https://audio-1304256198.cos.ap-guangzhou.myqcloud.com/%E4%BA%B2%E5%88%87%E5%A5%B3%E5%A3%B0.mp3'
                const response = await fetch(audioUrl)
                const arrayBuffer = await response.arrayBuffer()
                const uint8Array = new Uint8Array(arrayBuffer);
                let binaryString = '';
                for (let i = 0; i < uint8Array.length; i++) {
                    binaryString += String.fromCharCode(uint8Array[i]);
                }
                const base64String = `data:audio/mpeg;base64,${btoa(binaryString)}`;
                return base64String
            }

            playButton.addEventListener('click', async () => {
                let base64String = await generateBase64String()
                if(base64String.includes('data:audio/mpeg;base64,')){
                    base64String = base64String.replace('data:audio/mpeg;base64,', '')
                }
                const binaryString = atob(base64String);
                const uint8Array = new Uint8Array(binaryString.length);
                for (let i = 0; i < binaryString.length; i++) {
                    uint8Array[i] = binaryString.charCodeAt(i);
                }
                
                const audioContext  = new AudioContext()
                const audioBuffer = await audioContext.decodeAudioData(uint8Array.buffer)
                const sourceNode = audioContext.createBufferSource()
                sourceNode.buffer = audioBuffer
                sourceNode.connect(audioContext.destination)
                sourceNode.start()
            })
        })()
    </script>
</body>

在开发 TTS 流式播放功能时,后端可能会返回以下几种音频数据格式:BlobaudioUrlBase64。 这些格式用于实现音频的逐段接收与即时播放。当前阶段无需深入细节,了解其用途即可,具体实现时可作为参考。