繁体   English   中英

适用于 iOS 13+ 设备的网络音频音量衰减

[英]Web audio volume fade for iOS 13+ devices

我希望 Stack Overflow 社区中的某个人能够为此提供解决方法。 很长一段时间以来,这一直是我心中的刺。

我的要求非常简单:淡入页面上音频播放的音量。

使用 javascript 有几种方法可以做到这一点:

  1. 更新HTMLAudioElement上的“volume”属性。 这对 iOS 设备根本不起作用,因为该属性对于操作系统是只读的。
  2. 使用 Web 音频 API AudioContext.createMediaElementSource()GainNode 这目前有效,但是声音输出通常会失真 - 裂缝和爆破声会破坏任何流式音频的体验。 这不是由 AudioContext 使用不同的采样率引起的。
  3. 对通过XMLHttpRequest下载的文件使用 Web Audio API AudioBufferarraybuffer响应类型。 这似乎根本没有音量。 它适用于模拟器,但不适用于物理设备。

这三种方法几乎适用于除现代 iOS 设备之外的任何设备上的任何浏览器。 13 之前的 iOS 版本适用于方法 2 或 3。我并不是说所有的阴谋论者都是如此,但苹果是否会故意破坏 PWA 支持以将更多收入转移到他们的应用商店?

TL;DR 所有你需要的都在这个片段中(希望如此)

我有这个片段,你可以尝试一下,然后告诉我它是否适合你:

// input
const FADE_IN_DURATION = 10
const url = '/path/to/audio.mp3'

// setup
const context = /** @type {AudioContext} */(new (window.AudioContext || window.webkitAudioContext)())
const gainNode = context.createGain()
gainNode.connect(context.destination)
gainNode.gain.value = 0

// fetch
const response = await fetch(url)
const audioData = await response.arrayBuffer()
const buffer = await new Promise((resolve, reject) => {
    context.decodeAudioData(audioData, resolve, reject)
})

// connect
const source = context.createBufferSource()
source.buffer = buffer
source.connect(gainNode)

// play
const startTime = context.currentTime
gainNode.gain.linearRampToValueAtTime(1, startTime + FADE_IN_DURATION)
source.start(startTime)

关键点

  • context.createGain()返回的GainNode使您可以访问“增益” AudioParam 而且AudioParam有一个名为linearRampToValueAtTime的方法,它完全符合您的要求
  • 高于1的增益值会产生一些“失真”,因为“音量峰值”开始超过可能的最大值。 因此,如果您只想平滑淡入,请保持在01之间。
  • 我正在做的“布线”是非常基本的AudioBufferSourceNode --> GainNode --> AudioContext

实际工作脚本

上面的代码片断并没有真正的工作盒的,因为你需要

  • 一个处理异步/等待的函数,
  • 以及开始播放音频上下文的用户输入)。 所以这里有所有正确的包装:

 // input const FADE_IN_DURATION = 10 const url = 'https://upload.wikimedia.org/wikipedia/commons/d/de/Lorem_ipsum.ogg' // setup const context = /** @type {AudioContext} */ (new(window.AudioContext || window.webkitAudioContext)()) const gainNode = context.createGain() gainNode.connect(context.destination) gainNode.gain.value = 0 // fetch ;(async function() { const response = await fetch(url) const audioData = await response.arrayBuffer() const buffer = await new Promise((resolve, reject) => { context.decodeAudioData(audioData, resolve, reject) }) // user input necessary document.getElementById('text').textContent = "Ready. Click anywhere to start audio." document.addEventListener('click', () => { document.getElementById('text').textContent = "Now playing..." // connect const source = context.createBufferSource() source.buffer = buffer source.connect(gainNode) // play const startTime = context.currentTime gainNode.gain.linearRampToValueAtTime(1, startTime + FADE_IN_DURATION) source.start(startTime) }, { once: true }) })()
 <div id="text">Loading file...</div>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM