【问题标题】:HTML 5 audio .play() delay on mobile移动设备上的 HTML 5 音频 .play() 延迟
【发布时间】:2015-05-12 16:41:12
【问题描述】:

我刚刚使用 socket.io 构建了一个实时应用程序,其中“主”用户可以在接收设备(桌面浏览器、移动浏览器)上触发声音。该主用户会看到声音文件列表,并且可以在声音文件上单击“播放”。

音频播放在浏览器上是即时的。然而,在手机上,有 0.5-2 秒的延迟(我的 Nexus 4 和 iPhone 5 大约 1 秒,iPhone 3GS 1-2 秒)。

我已经尝试了几种方法来优化音频播放,以使其在手机上更快。现在(我想说的是其优化的最佳“阶段”),我将所有 mp3 合并到一个音频文件中(它创建 .mp3、.ogg 和 .mp4 文件)。我需要有关如何进一步解决/改进此问题的想法。瓶颈似乎确实在hmtl 5音频方法中,例如.play()

在我这样使用的接收器上:

<audio id="audioFile" preload="auto">
  <source src="/output.m4a" type="audio/mp4"/>
  <source src="/output.mp3" type="audio/mpeg"/>
  <source src="/output.ogg" type="audio/ogg"/>
  <p>Your browser does not support HTML5 audio.</p>
</audio>

在我的 JS 中:

var audioFile = document.getElementById('audioFile');

  // Little hack for mobile, as only a user generated click will enable us to play the sounds
  $('#prepareAudioBtn').on('click', function () {
    $(this).hide();
    audioFile.play();
    audioFile.pause();
    audioFile.currentTime = 0;
  });

// Master user triggered a sound sprite to play
socket.on('playAudio', function (audioClip) {
  if (audioFile.paused)
    audioFile.play();

  audioFile.currentTime = audioClip.startTime;

  // checks every 750ms to pause the clip if the endTime has been reached. 
  // There is a second of "silence" between each sound sprite so the pause is sure to happen at a correct time.
  timeListener(audioClip.endTime);
});

function timeListener(clipEndTime) {
  this.clear = function () {
    clearInterval(interval);
    interval = null;
  };

  if (interval !== null) {
    this.clear();
  }

  interval = setInterval(function () {
    if (audioFile.currentTime >= clipEndTime) {
      audioFile.pause();
      this.clear();
    }
  }, 750);
}

也考虑了每个声音的 blob,但有些声音可以持续几分钟,所以这就是为什么我将所有声音组合在一起形成一个大音频文件(比每个剪辑页面上的多个 audio 标签更好)

【问题讨论】:

    标签: javascript jquery html audio


    【解决方案1】:

    我没有暂停/播放,而是在不应该播放时将音量设置为 0,在应该播放时设置回 1。 Audio 方法 currentTimevolume 即使在 iPhone 3GS 上也不会减慢音频播放速度。

    我还在音频元素中添加了“循环”属性,这样就不必再次.play()'ed。

    将所有 mp3 声音组合在一起是卓有成效的,因为此解决方案可以正常工作。

    编辑:audioElement.muted = true 或 audioElement.muted = false 更有意义。

    Edit2:无法在 iOS 上代表用户控制音量,因此我必须暂停()和播放()音频元素,而不是仅仅静音和取消静音。

    【讨论】:

      【解决方案2】:

      由于preload 属性,您的设置在桌面上运行良好。

      很遗憾,这里是Apple on the subject of preload

      iOS 上的 Safari 从不预加载。

      这里是MDN

      注意:这个值在移动平台上经常被忽略。

      移动平台正在权衡以节省电池和数据使用量,以便仅在用户实际与之交互或以编程方式播放媒体时才加载媒体(autoplay 通常由于类似原因不起作用)。

      我认为你要做的最好的事情就是将你的曲目组合在一起,正如你所说的那样,你不必支付那么多的初始加载“成本”。

      【讨论】:

      • 第一次播放文件后,延迟仍然存在。暂停后文件的加载能否恢复到初始状态?为什么即使文件播放了一次或已经播放了几次,延迟仍然存在?
      • 对于单个组合音频,您不应该为每次搜索产生初始负载...是否在您 play() 之前设置 currentTime playAudio 事件中的音频会使任何区别?无论您要跳转到的剪辑是在文件中您当前位置之前还是之后,延迟都会发生吗?
      • 会尝试的。我还将测试将音量设置为 0,然后再调回 100,而不是再次暂停/播放。
      • 天哪,这就是最大的不同。我只是不停地播放音频文件,并在需要时将它的 currentTime 和音量从 0 更改为 1。是的
      【解决方案3】:

      我在移动设备上进行测试时遇到了同样的延迟问题。我发现了一些 HTML 5 游戏用于音频的内容,因为游戏需要非常低的延迟。有些人使用SoundJS。我建议你试试那个库。

      您可以在此处找到使用 HTML Audio 标签与使用 SoundJS 之间的速度比较:

      http://www.nickfrazier.com/javascript/audio/ui/2016/08/14/js-sound-libraries.html

      (在手机中测试以了解差异)

      根据我的测试 SoundJS 要快得多。

      事实上,它可以用在游戏中,或者用于用户界面中的声音反馈。

      【讨论】:

      • 欣赏插件。 SoundJS 默认使用 WebAudio,并使用 HTML Audio 标签作为后备。 WebAudio 方法更加一致、强大,并且受到所有浏览器的更好支持。
      • 感谢您的建议。我制作了一个依赖于按下按钮的迷你网络应用程序。所以我在按下按钮时添加了反馈声音。 SoundJS 运行良好。老式的 HTML 音频方法在按下按钮和播放声音时造成了几乎一秒的延迟。
      【解决方案4】:

      老问题,但这是我使用上述答案之一的解决方案:

      const el = document.createElement("audio");
      el.muted = true;
      el.loop = true;
      
      const source = document.createElement("source");
      source.src = lineSe;
      source.type = "audio/mpeg";
      
      el.appendChild(source);
      
      // need to call this function after user first interaction, or safari won't do it.
      function firstPlay() {
          el.play();
      }
      
      let timeout = null;
      
      function play() {
          // In case user press the button too fast, cancel last timeout
          if (lineSeTimeout) {
              clearTimeout(timeout);
          }
      
          // Back to beginning
          el.currentTime = 0;
      
          // unmute
          el.muted = false;
      
          // set to mute after the audio finish. In my case 500ms later
          // onended event won't work because loop=tue
          timeout = setTimeout(() => {
              // mute audio again
              el.muted = true;
          }, 500);
      }
      

      【讨论】:

        猜你喜欢
        • 2017-01-23
        • 1970-01-01
        • 2011-04-06
        • 2013-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-14
        相关资源
        最近更新 更多