Safari 6.0.2 not calling onaudioprocess

2019-05-15 12:11发布

问题:

I've earlier successfully used the JavaScriptAudioNode in the Web Audio API to synthesize and mix audio both in Chrome and Safari 6.0. However, the latest version of Safari no longer appears to work, because it does not call onaudioprocess to fill the source buffers.

This is a simplified example which plays only silence and appends text to the document body on each call to onaudioprocess:

<html>
<head>  
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script type="text/javascript">    
$(document).ready(function() {
  $("a").click(function() {    
    var context = new webkitAudioContext(); 
    var mixerNode=context.createJavaScriptNode(2048, 0, 2);                

    mixerNode.onaudioprocess=function(ape) {                     
      var buffer=ape.outputBuffer;
      for(var s=0;s<buffer.length;s++)
      {  
        buffer.getChannelData(0)[s]=0;      
        buffer.getChannelData(1)[s]=0;       
      }
      $("body").append("buffering<br/>");
    };               

    $("body").html("");               
    mixerNode.connect(context.destination);               
    return false;
  });                                                          
});                         
</script>    
</head>  
<body>  
<a href="#">start</a>        
</body>  
</html>

The above example works in Chrome as expected, but not in desktop Safari. The iOS version of Safari does not work either, but it never did work for me in the first place.

Calling context.createJavaScriptNode does return a proper object of type JavaScriptAudioNode and connecting it to the destination node does not throw any exceptions. context.activeSourceCount remains at zero, but this is also the case in Chrome as it apparently only counts active nodes of type AudioBufferSourceNode. context.currentTime also increments as expected.

Am I doing something wrong here or is this an actual bug or a missing feature in Safari? The Apple documentation has no mention of JavaScriptAudioNode (nor the new name, ScriptProcessorNode) but it did work before on the first release of Safari 6. The iOS Safari requirement for user input doesn't seem to help, as the example above should take care of that.

The simple example can be found here and a more complex one is my Protracker module player which exhibits the same behaviour.

回答1:

There are a couple bugs in Safari's implementation of the Web Audio API that you'll need to look out for. The first is in the createJavaScriptNode constructor... it seems to have problems with the "input channels" param being set to 0. Try changing it to this:

createJavaScriptNode(2048, 1, 2)

The second issue has to do with garbage collection (I think); once your mixerNode variable is out of scope, Safari seems to stop firing the onaudioprocess callback. One solution is to introduce mixerNode at the top-level scope (i.e. declaring var mixerNode; at the top of your script) and then store your JavaScriptNode in that top-level variable. If you plan on dynamically creating multiple mixerNodes, you can achieve the same effect by storing references to them in a top-level array variable.

If you make these two changes (input channel param set to 1, maintaining a reference to the mixerNode) then your script should work in Safari as expected.