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

在Chrome中播放音频,但不在Safari中播放

  •  0
  • Gargoyle  · 技术社区  · 6 年前

    我有一个角度5的应用程序,在这里我设置了 click 下载音频文件并播放它的按钮处理程序。我正在使用此代码来执行此操作:

    onPreviewPressed(media: Media): void {
        const url = ".....";
    
        this.httpClient.get(url, {responseType: 'blob'}).subscribe(x => {
            const fileReader = new FileReader();
    
            fileReader.onloadend = () => {
                const context = new ((<any>window).AudioContext || (<any>window).webkitAudioContext)();
                const source = context.createBufferSource();
    
                context.decodeAudioData(fileReader.result, buffer => {
                    source.buffer = buffer;
                    source.connect(context.destination);
                    source.start(0);
                }, y => {
                    console.info("Error: " + y);
                });
            };
    
            fileReader.readAsArrayBuffer(x);
        });
    }
    

    音频通过一个PHP脚本从服务器发回,并发送如下标题,以防万一:

    header("Content-Type: audio/mpeg");
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . filesize($_GET['file']));
    header('Cache-Control: no-cache');
    
    1 回复  |  直到 6 年前
        1
  •  2
  •   Kaiido NickSlash    6 年前

    响应按钮点击 ".
    为了响应这个click事件,您正在启动一个异步任务。当你打电话的时候 source.start(0)

    为了避免这种情况,你可以简单地用沉默来标记你的上下文。然后,当数据可用时,您就可以无限制地启动它:

    function markContextAsAllowed(context) {
      const gain = context.createGain();
      gain.gain.value = 0; // silence
      const osc = context.createOscillator();
      osc.connect(gain);
      gain.connect(context.destination);
      osc.onended = e => gain.disconnect();
      osc.start(0);
      osc.stop(0.01);
    }
    
    
    onPreviewPressed(media: Media): void {
      const url = ".....";
      // declare in the event handler
      const context = new(window.AudioContext || window.webkitAudioContext)();
      const source = context.createBufferSource();
      // allow context synchronously
      markContextAsAllowed(context);
    
    
      this.httpClient.get(url, {
        responseType: 'blob'
      }).subscribe(x => {
        const fileReader = new FileReader();
    
        fileReader.onloadend = () => {
          context.decodeAudioData(fileReader.result, buffer => {
            source.buffer = buffer;
            source.connect(context.destination);
            source.start(0);
          }, y => {
            console.info("Error: " + y);
          });
        };
    
        fileReader.readAsArrayBuffer(x);
      });
    }
    

    As a fiddle since Safari doesn't like over-protected StackSnippets®

    httpClient.get 是否支持 {responseType: 'arraybuffer'} 选项,则可以摆脱此文件读取器,并避免用相同的数据填充两倍的内存。

    最后,如果要多次播放此音频,请考虑预取和预解码,这样就可以避免整个异步混乱。

    推荐文章