Use ScriptProcessorNode in iPhone Safari

隐身守侯 提交于 2020-01-05 04:50:30

问题


I'm new in html5 and I want to use a ScriptProcessorNode to generate a sounds. My problem is that this code don't work in iPhone safari. But it works in safari on desktop.

var context; var isPlaying; var generatorNode; var isNeedShowAlert;

            function myButtonClick(button) 
        {
            isNeedShowAlert = true;
            if (isPlaying)
            {
                isPlaying = false;
                console.log("Stop!");
                generatorNode.disconnect();
            }
            else
            {
                alert("Play!");
                isPlaying = true;
                console.log("Play!");

                context = new webkitAudioContext();

                generatorNode = context.createJavaScriptNode(2048, 1, 2);
                generatorNode.onaudioprocess = function (e) 
                {
                    console.log("onaudioprocess!");
                    $("body").append("buffering<br/>");
                    var output = e.outputBuffer.getChannelData(0);

                    if (isNeedShowAlert)
                    {
                        isNeedShowAlert = false;
                        console.log("Length "+ output.length);
                        alert("Length "+ output.length);
                    }

                    for (var i = 0; i < output.length; i++)
                    {
                        output[i] = Math.random();
                    }
                }                   
                generatorNode.connect(context.destination);
                alert("Node Connected");
            }
            }

Looks like onaudioprocess never called. here people write that ScriptProcessorNode can be destroyed be garbage collector, but in my case it is global variable. I'm try a lot and start to think, that trere is no way to use ScriptProcessorNode in iPhone Safari. Can someone do id?

UPD. But if i use AudioBufferSourceNode, it works.

bufferNode = context.createBufferSource()
var buffer = context.createBuffer(1, 1024, context.sampleRate)
var  data = buffer.getChannelData(0);

for (var i = 0; i < 1024; i++) 
{
  data[i] = Math.random();
}
bufferNode.buffer = buffer;
bufferNode.loop = true;
bufferNode.connect(context.destination);
bufferNode.noteOn(0);

Looks like problem is specifically in ScriptProcessorNode and its onaudioprocess method.


回答1:


I found an answer by myself. It's need to add a source node to ScriptProcessorNode. Something like this.

bufferNode = context.createBufferSource()
var buffer = context.createBuffer(1, 1024, context.sampleRate)
var  data = buffer.getChannelData(0);
for (var i = 0; i < 2048; i++) 
{
  data[i] = 0;
}
bufferNode.buffer = buffer;
bufferNode.loop = true;

generatorNode = context.createJavaScriptNode(2048, 1, 1);
generatorNode.channelCount = 2;
generatorNode.channelCountMode = "max";
generatorNode.channelInterpretation = "speakers";
generatorNode.onaudioprocess = function generateWhiteNoise(e) 
{
   var output = e.outputBuffer.getChannelData(0);
   console.log("onaudioprocess!");
   for (var i = 0; i < output.length; i++)
   {
     output[i] = ( Math.random() * 2 ) - 1;
   }
}
bufferNode.connect(generatorNode);
generatorNode.connect(context.destination);
bufferNode.noteOn(0);

This code will be work in iOS safari browser.

UPD. Update white noise generation code. I's not my target, just use it for test, but it will be bad, if somebody use my wrong code to generate real white noise.




回答2:


After having the same issue I tried the accepted answer here but it didn't work for me. It seems the issue is that when the generatorNode is conntected to the context.destination context.state remains suspended! and adding the context.resume() in the same block has no effect. Adding context.resume() triggered by a button click event works and also triggers the earlier resume! this is still too much of a workaround for my liking but is a workaround that works.

If anyone has any suggestions/ideas for a better workaround to trigger context.resume() or eliminate the need for it at all (like all other browsers) it would be much appreciated.

jsfiddle example is here!

var suspendBtn = document.getElementById("suspendBtn");
var resumeBtn = document.getElementById("resumeBtn");

suspendBtn.onclick = function() {
    context.suspend();
}

resumeBtn.onclick = function() {
    context.resume();
}

var context = new webkitAudioContext();
var generatorNode = context.createJavaScriptNode(2048, 1, 2);

generatorNode.onaudioprocess = function generateWhiteNoise(e) {
    var output = e.outputBuffer.getChannelData(0);

    for (var i = 0; i < output.length; i++) {
        output[i] = ( Math.random() * 2 ) - 1;
    }
}

// This connects the generatorNode but in a suspended state!
generatorNode.connect(context.destination);

// This has no effect! 
// seems that it needs to be called from another context/closure
context.resume();


来源:https://stackoverflow.com/questions/17087119/use-scriptprocessornode-in-iphone-safari

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!