为什么JavaScript .play()不能在iPhone safari上播放音频文件?

Why can't JavaScript .play() audio files on iPhone safari?

本文关键字:safari 播放 音频 文件 iPhone play JavaScript 不能 为什么      更新时间:2023-09-26

我有一个JavaScript web应用程序工作,播放一些音频周期性像这样:

var SOUND_SUCCESS = new Audio('success.mp3');
SOUND_SUCCESS.play();

这在桌面浏览器上运行良好(在Edge和Chrome上进行了测试),但在iPhone的Safari上无法运行。

我看了一下Stack Overflow,我从几年前找到了一些答案,除非你在全屏播放器中,否则不可能从Safari播放音频。现在还是这样吗?

为了补充xingliang cai的回答,这里有一个我为自己工作的代码示例(编辑如下以便在iOS14上工作,谢谢@AndrewL!):

const soundEffect = new Audio();
soundEffect.autoplay = true;
// onClick of first interaction on page before I need the sounds
// (This is a tiny MP3 file that is silent and extremely short - retrieved from https://bigsoundbank.com and then modified)
soundEffect.src = "data:audio/mpeg;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD/80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";
// later on when you actually want to play a sound at any point without user interaction
soundEffect.src = 'path/to/file.mp3';

iOS禁用自动播放,而是要求播放作为用户交互的一部分启动(例如,您可以在touchstart侦听器中开始播放)。在苹果的开发者文档中有一些关于这个的文档。在IBM的开发者网站上还有一篇文章《克服iOS HTML5音频限制》,其中有一些例子和更多细节。

IOS在手机上默认禁用自动播放声音。为了解决这个问题。您可以将启用/禁用开关按钮放在页面的某个位置,并在用户单击按钮开关时使用音频元素("audioElement")播放一些声音。

之后,同样的"audioElement"可以通过改变其"src"属性并调用其"play()"方法来播放未来的声音,而无需进一步的用户交互。

为了让@user2415116的解决方案在iOS 14中工作,我这样做了:

const soundEffect = new Audio();
soundEffect.autoplay = true;
// onClick of first interaction on page before I need the sounds
// (This is a tiny MP3 file that is silent and extremely short - retrieved from https://bigsoundbank.com and then modified)
soundEffect.src = "data:audio/mpeg;base64,SUQzBAAAAAABEVRYWFgAAAAtAAADY29tbWVudABCaWdTb3VuZEJhbmsuY29tIC8gTGFTb25vdGhlcXVlLm9yZwBURU5DAAAAHQAAA1N3aXRjaCBQbHVzIMKpIE5DSCBTb2Z0d2FyZQBUSVQyAAAABgAAAzIyMzUAVFNTRQAAAA8AAANMYXZmNTcuODMuMTAwAAAAAAAAAAAAAAD/80DEAAAAA0gAAAAATEFNRTMuMTAwVVVVVVVVVVVVVUxBTUUzLjEwMFVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQsRbAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVf/zQMSkAAADSAAAAABVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV";
// later on when you actually want to play a sound at any point without user interaction
soundEffect.src = 'path/to/file.mp3';

我用了这个:

useEffect(() => {
  window.addEventListener('touchstart', () => {
    document.getElementById('audio').muted = false
    document.getElementById('audio').play()
  })
})

只要用户滚动,声音就会播放

Safari优先考虑视频的音轨而不是音频文件!如果一个视频有配乐,即使它是无声的,并且设置为静音,它也会屏蔽音频。解决的办法是从视频中去掉原声,而不是在上面录制。我希望这能帮助到一些人!这个问题浪费了我几天的时间。

我知道这个问题已经得到了回答,但对于一些人来说,这可能有所帮助。如果你在setTimeout函数中有。play触发器,你必须将时间保持在951以下。

setTimeout(function(){$('audio').play}, 999)阻止自动播放

setTimeout(function(){$('audio').play}, 950)自动播放工作

非常古老的问题,但可能会帮助一些人,在我的情况下(当然这可能不是在所有情况下都可行),它有助于播放所有音频文件1毫秒,然后暂停它们。在那之后,如果你继续播放音频,它的工作没有问题。

   playButton.addEventListener('click', function(){
      introVid.play();
      audioPlayers[0].play(); //every array element is constructed using new Audio("yourlink");
      audioPlayers[1].play();
      audioPlayers[2].play();
      audioPlayers[3].play();
      window.setTimeout(function(){
        audioPlayers[0].pause();
        audioPlayers[1].pause();
        audioPlayers[2].pause();
        audioPlayers[3].pause();
      },1);
    })

在iOS上的Safari(适用于包括iPad在内的所有设备),预加载和自动播放是禁用的,除非用户使用蜂窝网络并按数据单位收费。在用户初始化之前,不会加载任何数据。我已经简化了我的项目,我需要播放按钮点击声音的工作代码,希望这将有助于。

 <button class="js-button-clicked">Button 1</button>
 <button class="js-button-clicked" >Button 2</button>

JS:

(function () {
  // Check if the browser supports web audio. Safari wants a prefix.
  if ("AudioContext" in window || "webkitAudioContext" in window) {
    //////////////////////////////////////////////////
    // Here's the part for just playing an audio file.
    //////////////////////////////////////////////////
    var ButtonPlay = function ButtonPlay(audioBuffer) {
      var source = context.createBufferSource();
      source.buffer = audioBuffer;
      source.connect(context.destination);
      source.start();
    };
    var soundUrl = "https://images.skidos.com/video-js/button_pressed.mp3";
    var AudioContext = window.AudioContext || window.webkitAudioContext;
    var context = new AudioContext(); // Make it crossbrowser
    var gainNode = context.createGain();
    gainNode.gain.value = 1; // set volume to 100%
    var eventButtons = document.querySelectorAll(".js-button-clicked");
    var yodelBuffer = void 0;
    // The Promise-based syntax for BaseAudioContext.decodeAudioData() is not supported in Safari(Webkit).
    window
      .fetch(soundUrl)
      .then((response) => response.arrayBuffer())
      .then((arrayBuffer) =>
        context.decodeAudioData(
          arrayBuffer,
          (audioBuffer) => {
            yodelBuffer = audioBuffer;
          },
          (error) => console.error(error)
        )
      );
    eventButtons.forEach((el) =>
      el.addEventListener("click", (event) => {
        return ButtonPlay(yodelBuffer);
      })
    );
    //////////////////////////////////////////////////
    // Here's the part for unlocking the audio context, probably for iOS only
    //////////////////////////////////////////////////
    function unlock() {
      console.log("unlocking");
      // create empty buffer and play it
      var buffer = context.createBuffer(1, 1, 22050);
      var source = context.createBufferSource();
      source.buffer = buffer;
      source.connect(context.destination);
      // play the file. noteOn is the older version of start()
      source.start ? source.start(0) : source.noteOn(0);
      // by checking the play state after some time, we know if we're really unlocked
    }
    // Try to unlock, so the unmute is hidden when not necessary (in most browsers).
    unlock();
  }
})();

的例子:https://codepen.io/himstar/pen/MWBeLvG

  • 在iphone exr, iPadAir和MacOS 12.5上测试

哈哈,我就这样智取了它。

audio标签设置为autoplay (true)

<audio id="beep" src={Assets.SOUND_BEEP} autoPlay />

一旦元素被安装,它将播放声音。(即使是safari iOS)

那么你似乎可以随时通过调用

再次播放它
document.getElementById('beep').play();

但是现在你可能会说,但是我不想让声音自动播放

是的,我聪明地把"muted"属性放在上面,然后在播放时将其设置为false。

<audio id="beep" src={Assets.SOUND_BEEP} autoPlay muted />

:

document.getElementById('beep').muted = false;
document.getElementById('beep').play();