【问题标题】:Play audio from Blob in React在 React 中播放来自 Blob 的音频
【发布时间】:2022-01-13 06:59:27
【问题描述】:

我从后端收到一些音频(.wav 格式),并希望在 react 前端播放它。

旧实现使用公共文件夹中的文件和这样的标签:

<audio ref={audioPlayer} src={new Blob(output.data)} preload="metadata" onEnded={onEnded} onLoadedMetadata={onLoadedMetadata}/>

如何使用我的请求中的二进制数据而不是此处的源,或者是否有任何其他简单的方法可以从内存中播放音频文件?

【问题讨论】:

    标签: reactjs audio html5-audio


    【解决方案1】:

    您可以使用类似于blob 格式的二进制数据为您的音频元素源创建object URL

    这是一个注释示例,包括一个方便的钩子:

    <div id="root"></div><script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script><script src="https://unpkg.com/@babel/standalone@7.16.4/babel.min.js"></script>
    <script type="text/babel" data-type="module" data-presets="react">
    
    const {useEffect, useMemo, useState} = React;
    
    /**
     * This is just for the demo.
     * You seem to already have the binary data for the blob.
     */
    function useBlob () {
      const [blob, setBlob] = useState();
      const [error, setError] = useState();
    
      useEffect(() => {
        (async () => {
          try {
            // A random doorbell audio sample I found on GitHub
            const url = 'https://raw.githubusercontent.com/prof3ssorSt3v3/media-sample-files/65dbf140bdf0e66e8373fccff580ac0ba043f9c4/doorbell.mp3';
            const response = await fetch(url);
            if (!response.ok) throw new Error(`Response not OK (${response.status})`);
            setBlob(await response.blob());
          }
          catch (ex) {
            setError(ex instanceof Error ? ex : new Error(String(ex)));
          }
        })();
      }, []);
    
      return {blob, error};
    }
    
    /**
     * Get an object URL for the current blob. Will revoke old URL if blob changes.
     * https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
     */
    function useObjectUrl (blob) {
      const url = useMemo(() => URL.createObjectURL(blob), [blob]);
      useEffect(() => () => URL.revokeObjectURL(url), [blob]);
      return url;
    }
    
    // Use the hook and render the audio element
    function AudioPlayer ({blob}) {
      const src = useObjectUrl(blob);
      return <audio controls {...{src}} />;
    }
    
    function Example () {
      const {blob, error} = useBlob();
      return (
        <div>
          <h2>Audio player using binary data</h2>
          {
            blob ? <AudioPlayer {...{blob}} />
              : error ? <div>There was an error fetching the audio file: {String(error)}</div>
              : <div>Loading audio...</div>
          }
        </div>
      );
    }
    
    ReactDOM.render(<Example />, document.getElementById('root'));
    
    </script>

    【讨论】:

    • 这是一个很好的开始,并且完全符合我的要求!但是,我觉得我的 Blob 有问题。如何确保它的格式正确,以便可以将其解释为音频?现在我设置类型:“audi/wav”,但通过 objectURL 打开文件时文件为空。
    • @masus04 您问题中的文字表明您已经有一个 blob,因此这与您提出的问题不同。如果您想就 SO 提出不同的问题并在此处的评论中链接到它,我很乐意看一看。如果这个回答了你关于如何在 React 中使用带有音频元素的 blob 的问题,请随意将其标记为这样。
    • 我只是想弄清楚我已经拥有的 Blob 是否正确。如果您对此有任何见解,将不胜感激。无论如何,它现在对我有用,非常感谢您的回答!
    • 很高兴你成功了@masus04
    【解决方案2】:

    感谢@jsejcksn 的详尽回答!

    简短的版本如下:

    1. 确保正确检索 Blob,例如通过使用 axios 指定 {responseType: 'blob'}

    2. 将 Blob 包装到 ObjectURL 中

      url = URL.createObjectURL(blob)
      
    3. 将 url 作为 src 传递给音频标签

      <audio src={url} />
      
    4. 如果不再需要该 url,请按如下方式释放资源:

      URL.revokeObjectURL(url)
      

    编辑:添加@jsejcksn 的评论

    【讨论】:

    • 每次创建对象 URL 时,它都会在内存中创建 blob 的副本,因此请确保在使用完 url 后使用URL.revokeObjectURL(yourObjectURL),否则会导致内存泄漏。
    猜你喜欢
    • 2020-01-26
    • 2019-12-12
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多