代码之家  ›  专栏  ›  技术社区  ›  Megidd

Web Audio API分析器输出取决于如何定义HTML音频元素源

  •  0
  • Megidd  · 技术社区  · 4 年前

    背景

    我有这段代码来用HTML画布可视化音频。它在Safari上运行良好:

    window.MyNamespace = {} // Easy access to some vars by namespace.
    
    // Some browsers require a user gesture before creating Web Audio API context.
    MyNamespace.firstUserGesture = true
    
    MyNamespace.audio = {}
    
    MyNamespace.audio.el = document.getElementById("aud")
    
    MyNamespace.audio.canvasEl = document.getElementById("canvasEl")
    
    function setupCanvas() {
      MyNamespace.audio.canvasEl.style.width = "88%"
      MyNamespace.audio.canvasEl.style.height = "100px"
    
      // High dpi stuff.
      // Controls the chart line stroke thickness.
      MyNamespace.audio.canvasEl.width = 500 * 2
      MyNamespace.audio.canvasEl.height = 100 * 2
    
      // Get canvas context.
      MyNamespace.audio.canvasCtx = MyNamespace.audio.canvasEl.getContext("2d")
    
      // Set stroke color.
      MyNamespace.audio.canvasCtx.strokeStyle = "#4285F4"
    
      // Draw twice as thick lines due to high dpi scaling.
      MyNamespace.audio.canvasCtx.lineWidth = 2
    
      // Animation reference.
      MyNamespace.audio.canvasAnimation = {}
    
      MyNamespace.audio.el.addEventListener('play', () => drawWave())
      MyNamespace.audio.el.addEventListener('pause', () => cancelAnimationFrame(MyNamespace.audio.canvasAnimation))
      MyNamespace.audio.el.addEventListener('ended', () => cancelAnimationFrame(MyNamespace.audio.canvasAnimation))
    
      let N = 0 // Data count to show.
      N = MyNamespace.audio.analyzer.fftSize
      MyNamespace.audio.data = new Uint8Array(N)
    
      // Our drawing method
      function drawWave() {
        MyNamespace.audio.analyzer.getByteTimeDomainData(MyNamespace.audio.data)
    
        const WIDTH = MyNamespace.audio.canvasEl.width
        const HEIGHT = MyNamespace.audio.canvasEl.height
        const bufferLength = MyNamespace.audio.data.length
        const dataArray = MyNamespace.audio.data
    
        // https://github.com/mdn/voice-change-o-matic-float-data/blob/c745ba8b48d7a9b93661ac43da2886633c06f2a7/scripts/app.js#L190
        MyNamespace.audio.canvasCtx.fillStyle = 'rgb(255, 255, 255)'
        MyNamespace.audio.canvasCtx.fillRect(0, 0, WIDTH, HEIGHT)
    
        var barWidth = (WIDTH / bufferLength) * 2.5
        var barHeight
        var x = 0
    
        for (var j = 0; j < bufferLength; j++) {
          // 128 means no sound? 128 corresponds to 0? Log indicates so!
          // Multiply by 2 to make it more noticable.
          barHeight = Math.abs(dataArray[j] - 128) * 2
          //console.log('bar height', barHeight)
    
          MyNamespace.audio.canvasCtx.fillStyle = 'rgb(' + Math.floor(barHeight + 66) + ',133,244)'
          MyNamespace.audio.canvasCtx.fillRect(x, Math.abs(HEIGHT - barHeight) / 2, barWidth, barHeight)
    
          x += barWidth + 1
        }
    
        // Animate
        MyNamespace.audio.canvasAnimation = requestAnimationFrame(drawWave)
      }
    }
    
    function createAudio() {
      if (MyNamespace.firstUserGesture) {
        // Note: As a consequence of calling createMediaElementSource(),
        // audio playback from the HTMLMediaElement will be re-routed into the processing graph of the AudioContext.
        // So playing/pausing the media can still be done through the media element API and the player controls.
        if ('webkitAudioContext' in window) {
          MyNamespace.ctx = new webkitAudioContext()
          console.log('webkitAudioContext() is available.')
        } else if ('AudioContext' in window) {
          MyNamespace.ctx = new AudioContext()
          console.log('AudioContext() is available.')
        } else {
          console.log('Web Audio API is not available.')
        }
    
        MyNamespace.audio.source = MyNamespace.ctx.createMediaElementSource(MyNamespace.audio.el)
        MyNamespace.audio.analyzer = MyNamespace.ctx.createAnalyser()
        MyNamespace.audio.source.connect(MyNamespace.audio.analyzer)
        MyNamespace.audio.source.connect(MyNamespace.ctx.destination)
        console.log('Web Audio API is all set')
        // We are sure Web Audio API context is ready.
        setupCanvas()
      }
      MyNamespace.firstUserGesture = false
    }
    
    function handleClick() {
      // The AudioContext is not allowed to start before user gesture.
      // It must be resumed (or created) after a user gesture on the page.
      createAudio()
    
      // Play/pause the media
      if (MyNamespace.audio.el.paused) {
        MyNamespace.audio.el.play()
      } else {
        MyNamespace.audio.el.pause()
      }
    }
    
    MyNamespace.audio.btnEl = document.getElementById("btn")
    MyNamespace.audio.btnEl.addEventListener('click', handleClick)
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width" />
      <title>Micrufun</title>
      <link rel="shortcut icon" type="image/x-icon" href="logo.ico" />
    </head>
    
    <body>
      <div style="width: 100%;">
        <button id="btn">Play/pause</button>
      </div>
      <div style="width: 100%;">
        <audio id="aud" style="width: 50%;" preload="metadata" crossorigin="anonymous">
          <!-- This source won't show the canvas visualization: -->
          <!--source src="media/file_example_MP3_2MG.mp3" /-->
          <!-- But this one shows: -->
          <source src="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_2MG.mp3">
          Your browser does not support the vedio tag.
        </audio>
      </div>
      <div style="width: 100%;">
        <canvas id="canvasEl" style="width: 88%; height: 100px;"></canvas>
      </div>
    </body>

    问题

    Safari使用以下音频源显示画布可视化:

    <source src="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_2MG.mp3">
    

    但是,当我将完全相同的音频文件放置在公共位置并静态地提供它时,就像这样作为音频源:

    <source src="media/file_example_MP3_2MG.mp3">
    

    …播放音频,但不显示画布可视化。由于Web Audio API分析器节点输出全部 128 并且不会改变。这意味着分析器节点是 输出任何内容。

    笔记

    我通过静态方式为网页提供服务 python3 -m http.server 在我的机器上。

    问题

    只有Safari浏览器显示这两种浏览器的不同行为,为什么?

    <!-- This source works fine: -->
    <source src="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_2MG.mp3">
    
    <!-- This source doesn't show the canvas visualization but the audio sound is played: -->
    <source src="media/file_example_MP3_2MG.mp3">
    

    偶尔观察

    假使 <source src="media/file_example_MP3_2MG.mp3"> 这个 播放/暂停 按钮,偶尔从头开始播放音频。我的意思是,它不会从停止的地方拾取声音。它只是重新启动声音。

    但对于另一个来源 播放/暂停 行为如预期。

    上述偶然的观察伴随着这样一种网络交流:

    HTTP header

    0 回复  |  直到 4 年前