【问题标题】:Web audio volume fade for iOS 13+ devicesiOS 13+ 设备的网络音频音量衰减
【发布时间】:2021-09-04 08:12:03
【问题描述】:

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

我的要求很简单:淡入音量以在页面上播放音频。

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

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

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

【问题讨论】:

  • 你能公布你对第三种方法的尝试吗?
  • 事实证明这种方法现在有效。在某一时刻,它不起作用。不知道为什么,我没有用于测试的 iOS 设备来找出原因。
  • @BruceHamilton 你有没有找到任何解决方案来支持在流式传输音频时褪色?

标签: javascript ios progressive-web-apps web-audio-api


【解决方案1】:

TL;DR 你需要的只是这个 sn-p(希望如此)

我有这个sn-p,你可以试试,告诉我它是否适合你:

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

实际工作脚本

上面的 sn-p 并不是真的开箱即用,因为你需要

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

// 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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多