没有声音iOS 6的网络音频API(No sound on iOS 6 Web Audio API)

2019-06-18 06:06发布

我真的很高兴看到的iOS 6支持网络音频API,因为我们做HTML5游戏。 但是,我不能让iOS 6中使用网络音频API与在桌面版Chrome做工精细的例子在所有播放任何声音。

这是通过网络音频API一个HTML5游戏,触摸控制和播放音频(如果存在的话 - 如果不是它会回落到HTML5音频):

http://www.scirra.com/labs/sbios6b/

编辑:@Srikumar提出了一些解决方法。 我申请他们在下面的版本。 它仍然无法正常工作!

http://www.scirra.com/labs/sbios6f/

一切都在扮演着桌面版Chrome就好了,但iOS 6中发出任何声音都没有。 我无法调试它,因为我只能做的Windows开发,而iOS 6替换远程Web检查,这显然是不提供Safari浏览器的Windows调试模式。 使用几个提醒我没有找到它正确地识别网络音频API,使用它,没有检测到Vorbis格式的支持,以便回落到AAC音频,解码缓冲区,然后进行播放,并不会引发任何错误,但我什么也没有听见。 而且,当然,我试图打开音量开到最大:)

不应该有一个编解码器的问题,因为iOS 6中可以播放AAC就好了-你可以浏览到该.M4A的游戏戏剧之一 ,它起着罚款从Safari浏览器直接访问。

在网络音频API的例子看这里的iOS 6: http://chromium.googlecode.com/svn/trunk/samples/audio/samples.html -他们中的一些工作,和别人不一样。 例如, Chrome的音频可视化的工作,但使用Javascript雄蜂没有。

必须有在iOS 6和桌面版Chrome网络音频之间的一些微妙的不兼容性。 我在想什么?

Answer 1:

编辑(2015年11月):9的iOS不再允许音频在启动touchstart事件,它打破下面的解决方案。 但是它在一个touchend事件。 对于iOS 6的原始答案是原封不动的下方,但针对iOS 9支持确保您使用touchend

好吧,抱歉地回答我的奖金问题,但调试了几个小时之后,我终于找到了答案。 Safari浏览器在iOS 6上有效地与网络音频API静音启动。 它不会取消静音,直到你试图在用户输入事件来播放声音 (创建缓冲区源,它连接到目的地,并调用noteOn() 在此之后,它取消静音和音频播放无限制的,当它应该。 这是通过Web Audio API如何适用于iOS 6的无证方面( 苹果的doc是在这里 ,他们希望用这种一提的很快更新!)

用户可以触摸屏幕了很多,从事游戏。 但它仍将保持静音。 你用户输入事件中起到像touchstart [编辑: touchend为iOS 9+],一次,然后所有的音频取消静音。 之后,你可以随时播放的声音(不必是在用户输入事件)。

请注意,这是对HTML5音频的限制不同:通常你只能开始在音频中的所有用户输入事件,只有一次播放一个声音; 通过Web Audio API的第一出戏,在用户输入后完全取消静音,让您可以随时播放的声音,然后你可以将它们混合复音,工艺很酷的效果,等等。

这意味着许多游戏已经在使用网络音频API将永远不会播放音频,因为不发生问题触摸事件noteOn在网络上。 你必须调整以等待第一个用户输入事件。

有几种方法可以解决此问题:直到用户触摸屏幕不玩你的标题音乐; 有一个初步的“触摸到启用音频”屏幕和播放声音,然后开始游戏时,他们接触; 等希望这将有助于其他人有同样的问题,节省一些时间去调试它!



Answer 2:

您可以尝试在Mac上使用Web检查在Safari 6调试它。

  1. 在移动Safari浏览器设置中启用“的Webkit督察” /先进。
  2. 连接设备使用USB数据线运行的Safari 6在Mac。
  3. 加载网页/游戏
  4. 进入菜单开发 - > [设备名] - > [PAGEURL]

它不开箱的我,但试了几次,它可以帮助缩小问题。

显然还有音频只能由用户操作触发的东西。 我不知道这是真的“因为一些代码,在iOS6的工作iPhone4上不播放任何声音,在iPad上(也iOS6的)。

更新 :一些成功的iPhone4上+ iOS6的网络音频。 发现“currentTime的” 0一会,只要你创建iOS6的新的音频范围内仍然停留。 为了得到它移动,你首先需要执行一个虚拟的API调用(如createGainNode()和丢弃的结果)。 听起来发挥只有当currentTime的开始运行,但调度的声音恰好在currentTime的似乎并没有工作。 他们需要的是一点点的未来(例如:10毫秒)。 您可以使用以下createAudioContext功能要等到上下文已准备好制造噪音。 用户操作似乎并没有对iPhone进行必需的,但在iPad上没有这样的成功,只是还没有。

function createAudioContext(callback, errback) {
    var ac = new webkitAudioContext();
    ac.createGainNode(); // .. and discard it. This gets 
                         // the clock running at some point.

    var count = 0;

    function wait() {
        if (ac.currentTime === 0) {
            // Not ready yet.
            ++count;
            if (count > 600) {
                errback('timeout');
            } else {
                setTimeout(wait, 100);
            }
        } else {
            // Ready. Pass on the valid audio context.
            callback(ac); 
        }
    }

    wait();
}

随后,弹奏音符的时候,不叫.noteOn(ac.currentTime)但做.noteOn(ac.currentTime + 0.01)来代替。

请不要问我为什么 ,你所要做的一切。 这仅仅是目前的方式 - 即疯狂。



Answer 3:

我设法找出一个简单的解决方案,我相信一定是记录在其他地方 - 但有时我们不得不花费时间搞清楚这些东西占为己有?

因此,似乎很多教程(如这一项上HTML5ROCKS )指导你做以下步骤:

  • 创建的实例window.AudioContext ,如果不存在(它不会在iOS上)然后创建window.webkitAudioContext

  • 创建XMLHttpRequest加载你的声音文件

  • load运行事件context.decodeAudioData(....)然后createBufferSource()与解码后的数据填充它,最后source.start(0)来播放声音。

正如其他人所指出的,你必须创建AudioContext (顺带你必须存储和使用的页面的寿命)作为用户交互的结果(点击或touchstart)。

但是:在iOS设备上,以“解锁”它的音频能力,你必须有音频数据可以在创建AudioContext 。 如果您加载数据异步没有什么它玩。 这是不够的只是创建AudioContext一个内click事件。

这里有一个可靠的iOS播放两种解决方案:

  • 1)必须加载至少一个声音文件之前,你甚至初始化AudioContext,然后运行所有立即单个用户交互内的声音文件上面的步骤(如点击)。

  • OR 2)在内存中动态创建的声音和播放。

这是我怎么做的第二个选项:

请记住-必须内click / touch的iOS事件:

 window.AudioContext = window.AudioContext || window.webkitAudioContext;
 var context = new window.AudioContext();

 // you should null check window.AudioContext for old browsers to not blow up

 // create a dummy sound - and play it immediately in same 'thread'
 var oscillator = context.createOscillator();
 oscillator.frequency.value = 400;
 oscillator.connect(context.destination);
 oscillator.start(0);
 oscillator.stop(.5);    // you can set this to zero, but I left it here for testing.

 // audio context is now 'unlocked' and ready to load and play sounds asynchronously
 // YOU MUST STORE 'context' for future usage. DON'T recreate more AudioContexts

我想这是一个常见的错误 - 而我,似乎没有人已经指出了这3年后惊讶或发现它: - /



Answer 4:

所以,我想我已经想通了。

这是苹果公司的要求的用户动作之前的声音可以被允许玩一个问题。 事实证明,至少对我来说,你不应该在所有创建的音频范围内,当用户要求它除了。 这是不够的创建上下文时,页面加载,然后用createGainNode或类似上的用户操作。

在你的情况下,当用户点击“触摸开始”按钮,我想创建上下文。



Answer 5:

回答原来的问题,我可以证实一些麻烦与iPhone 4S / iOS 6或MacOSX的文件格式。 如果一个MP3文件是“不好”的Safari浏览器,解码变坏,并呼吁AudioContext.createBuffer(数组,布尔)让您和错误。

奇怪的是有关该错误:“SYNTAX_ERR,DOM异常12”,正如别人指出。 这让我觉得这是一个错误....

同样的行为还在MacOS上,使用Safari 6.0(7536.25)。



Answer 6:

我所遇到的与HTML5音频音频限制在iOS和解决问题的工作:

1)用无声的音频文件创建音频元素,并用触摸事件开始玩它(例如,“开始游戏”按钮),然后immidietly暂停它。

2)建立,其切换所述音频src和再短超时之后播放该音频元素的声音切换器功能。

3)调用上的任何事件声音切换功能(不需要是触摸事件)。

这工作,因为音频元素是取消静音在第一次触摸,用无声的音频文件,并保持取消静音,所以源可以即时切换。

switchSound: (id) ->
        @soundSwitch.pause()
        @soundSwitch.src = @sounds[id]._src

        clearTimeout @switchSoundDelay
        @switchSoundDelay = setTimeout =>
            # @soundSwitch.volume = 1
            @soundSwitch.play()
        ,50 


Answer 7:

更新的2015年解决办法:嘿,如果你在这里工作与iOS6的网络音频问题+我发现这些链接的帮助。

-这是用代码解决方案的好文章: http://matt-harrison.com/perfect-web-audio-on-ios-devices-with-the-web-audio-api/

尤其是圆形是一个更新到API上述^溶液文章写后https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext

-below是我更新解决了第一篇文章,使用从第二产品上的变化。 我遇到的问题是iOS的Safari浏览器7扔了怪不,足以-ARGS错误。 这个固定:

define(function() {

  try {
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    window.audioContext = new window.AudioContext();
  } catch (e) {
    console.log("No Web Audio API support");
  }
/*
 * WebAudioAPISoundManager Constructor
 */
 var WebAudioAPISoundManager = function (context) {
  this.context = context;
  this.bufferList = {};
  this.playingSounds = {};
};

/*
 * WebAudioAPISoundManager Prototype
 */
 WebAudioAPISoundManager.prototype = {
   addSound: function (url) {
      // Load buffer asynchronously
      var request = new XMLHttpRequest();
      request.open("GET", url, true);
      request.responseType = "arraybuffer";

      var self = this;

      request.onload = function () {
        // Asynchronously decode the audio file data in request.response
        self.context.decodeAudioData(
          request.response,

          function (buffer) {
            if (!buffer) {
              alert('error decoding file data: ' + url);
              return;
            }
            self.bufferList[url] = buffer;
          });
      };

      request.onerror = function () {
        alert('BufferLoader: XHR error');
      };

      request.send();
    },
    stopSoundWithUrl: function(url) {
      if(this.playingSounds.hasOwnProperty(url)){
        for(var i in this.playingSounds[url]){
          if(this.playingSounds[url].hasOwnProperty(i)) {
            this.playingSounds[url][i].stop(0);
          }
        }
      }
    }
  };

/*
 * WebAudioAPISound Constructor
 */
 var WebAudioAPISound = function (url, options) {
  this.settings = {
    loop: false
  };

  for(var i in options){
    if(options.hasOwnProperty(i)) {
      this.settings[i] = options[i];
    }
  }

  this.url = '/src/www/assets/audio/' + url + '.mp3';
  this.volume = 1;
  window.webAudioAPISoundManager = window.webAudioAPISoundManager || new WebAudioAPISoundManager(window.audioContext);
  this.manager = window.webAudioAPISoundManager;
  this.manager.addSound(this.url);
    // this.buffer = this.manager.bufferList[this.url];
  };

/*
 * WebAudioAPISound Prototype
 */
 WebAudioAPISound.prototype = {
  play: function () {
    var buffer = this.manager.bufferList[this.url];
    //Only play if it's loaded yet
    if (typeof buffer !== "undefined") {
      var source = this.makeSource(buffer);
      source.loop = this.settings.loop;
        source.start(0);

        if(!this.manager.playingSounds.hasOwnProperty(this.url)) {
          this.manager.playingSounds[this.url] = [];
        }
        this.manager.playingSounds[this.url].push(source);
      }
    },
    stop: function () {
      this.manager.stopSoundWithUrl(this.url);
    },
    getVolume: function () {
      return this.translateVolume(this.volume, true);
    },
    //Expect to receive in range 0-100
    setVolume: function (volume) {
      this.volume = this.translateVolume(volume);
    },
    translateVolume: function(volume, inverse){
      return inverse ? volume * 100 : volume / 100;
    },
    makeSource: function (buffer) {
      var source = this.manager.context.createBufferSource();
      var gainNode = this.manager.context.createGain();
      source.connect(gainNode);
      gainNode.gain.value = this.volume;
      source.buffer = buffer;
      // source.connect(gainNode);
      gainNode.connect(this.manager.context.destination);
      return source;
    }
  };

  return WebAudioAPISound;
});


Answer 8:

更新:iOS版仍然需要用户输入播放声音( 在iOS 6的网络音频API没有声音 )

我以前套牢的iOS网络上的网络音频。 而更糟糕的是,它需要在Android和其他桌面平台工作。 这篇文章是那些我看,并没有发现即时答案的帖子之一。

直到我发现howler.js 。

这是一个跨平台的网络音频解决方案,该解决方案:

<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.0.3/howler.min.js"></script>

<script>

  var sound = new Howl({
    src: ['yay3.mp3']
  });
  sound.play();


</script>


Answer 9:

这是不是一个实际的答案,只是一个方向看,如果事情还没有工作。 iOS6的有一些设备上的音频问题(特别是在特定时期生产的64GB 4S,虽然我已经看到了别人,因此实际上可能不是硬件相关的),并神秘地停止播放一些声音的类型(非铃声或语音,对于一些原因,但许多其他的声音),它的音量滑块将消失。 我发现它非常难以调试,因为它通常会(被认为并非总是如此,有时你可以捕捉它)当电源线没有连接才会发生。

看在控制台从VirtualAudio_Device断言失败的消息和各种编解码器。 这可能毫无关系,与你的具体问题,但话又说回来,在音响设备的一个区域中的错误可能与另一个。 至少,这是一个区域进行调查,如果没有别的帮助。



Answer 10:

该API将出现在iOS 6.1被打破,或至少,有一个重大更改,这意味着没有网站目前正在使用它。



Answer 11:

我有使用所有简单的解决方案的麻烦。 尤其是,当我想播放声音多次。

所以我使用这个js库: http://pupunzi.open-lab.com/2013/03/13/making-html5-audio-actually-work-on-mobile



Answer 12:

好吧,我喜欢AshleysBrain答案,它帮我解决这个问题。 但是我发现更多的通用的解决方案。

之前,你必须开始从用户事件的播放声音,现在他们强迫你通过用户输入事件做了,(听起来很奇怪)我所做的只是读取输入场之前,我播放的声音。

所以

  $('#start-lesson').click(function() {
  return startThisLesson();
});
startThisLesson = function() {
     var value;
     value = $('#key-pad-value')[0].value;
     playSoundFile(yourBuffer);
}

playSoundFile是你用什么来创建缓冲区源。



文章来源: No sound on iOS 6 Web Audio API