diff options
author | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-07-05 11:43:31 +0200 |
---|---|---|
committer | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-07-30 14:21:43 +0200 |
commit | 356d7fd7a678c63477c0d53263e0fd7f05bd7bf8 (patch) | |
tree | 4cd1fd7e3c5550b5ba48e2bd86ecdcdcc9521a15 /components | |
parent | 25a74a75eaca196b1bd7a999aba42f8ac54202f4 (diff) | |
download | servo-356d7fd7a678c63477c0d53263e0fd7f05bd7bf8.tar.gz servo-356d7fd7a678c63477c0d53263e0fd7f05bd7bf8.zip |
createBufferSource and buffer setter on buffer source node
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/audiobuffer.rs | 55 | ||||
-rw-r--r-- | components/script/dom/audiobuffersourcenode.rs | 59 | ||||
-rw-r--r-- | components/script/dom/audioscheduledsourcenode.rs | 29 | ||||
-rw-r--r-- | components/script/dom/baseaudiocontext.rs | 38 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 2 | ||||
-rw-r--r-- | components/script/dom/oscillatornode.rs | 11 | ||||
-rw-r--r-- | components/script/dom/webidls/AudioBufferSourceNode.webidl | 8 | ||||
-rw-r--r-- | components/script/dom/webidls/AudioScheduledSourceNode.webidl | 4 | ||||
-rw-r--r-- | components/script/dom/webidls/BaseAudioContext.webidl | 8 |
9 files changed, 152 insertions, 62 deletions
diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index 8f0a72a440c..5d028cc3cd9 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -14,8 +14,8 @@ use dom_struct::dom_struct; use js::jsapi::{Heap, JSContext, JSObject, JS_StealArrayBufferContents}; use js::rust::CustomAutoRooterGuard; use js::typedarray::{CreateWith, Float32Array}; +use servo_media::audio::buffer_source_node::AudioBuffer as ServoMediaAudioBuffer; use std::ptr::{self, NonNull}; -use std::slice; use std::sync::{Arc, Mutex}; type JSAudioChannel = Heap<*mut JSObject>; @@ -25,7 +25,7 @@ pub struct AudioBuffer { reflector_: Reflector, js_channels: DomRefCell<Vec<JSAudioChannel>>, #[ignore_malloc_size_of = "Arc"] - shared_channels: Arc<Mutex<Vec<Vec<f32>>>>, + shared_channels: Arc<Mutex<ServoMediaAudioBuffer>>, sample_rate: f32, length: u32, duration: f64, @@ -53,11 +53,12 @@ impl AudioBuffer { AudioBuffer { reflector_: Reflector::new(), js_channels: DomRefCell::new(js_channels), - shared_channels: Arc::new(Mutex::new(vec![vec![0.; length as usize]; number_of_channels as usize])), - sample_rate: sample_rate, - length: length, - duration: length as f64 / sample_rate as f64, - number_of_channels: number_of_channels, + shared_channels: Arc::new(Mutex::new( + ServoMediaAudioBuffer::new(number_of_channels as u8, length as usize))), + sample_rate: sample_rate, + length: length, + duration: length as f64 / sample_rate as f64, + number_of_channels: number_of_channels, } } @@ -88,7 +89,7 @@ impl AudioBuffer { // Move the channel data from shared_channels to js_channels. rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>()); - let shared_channel = (*self.shared_channels.lock().unwrap()).remove(i); + let shared_channel = (*self.shared_channels.lock().unwrap()).buffers.remove(i); if unsafe { Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut()) }.is_err() { @@ -102,7 +103,7 @@ impl AudioBuffer { /// https://webaudio.github.io/web-audio-api/#acquire-the-content #[allow(unsafe_code)] - pub fn acquire_contents(&self) -> Option<Arc<Mutex<Vec<Vec<f32>>>>> { + pub fn acquire_contents(&self) -> Option<Arc<Mutex<ServoMediaAudioBuffer>>> { let cx = self.global().get_cx(); for (i, channel) in self.js_channels.borrow_mut().iter().enumerate() { // Step 1. @@ -112,17 +113,25 @@ impl AudioBuffer { // Step 2. let channel_data = unsafe { - slice::from_raw_parts( - JS_StealArrayBufferContents(cx, channel.handle()) as *mut f32, - self.length as usize - ).to_vec() + typedarray!(in(cx) let array: Float32Array = channel.get()); + if let Ok(array) = array { + // XXX TypedArrays API does not expose a way to steal the buffer's + // content. + let data = array.to_vec(); + let _ = JS_StealArrayBufferContents(cx, channel.handle()); + data + } else { + return None; + } }; channel.set(ptr::null_mut()); - // Step 3 and part of 4 (which will complete turning shared_channels - // data into js_channels ArrayBuffers in restore_js_channel_data). - (*self.shared_channels.lock().unwrap())[i] = channel_data; + // Step 3. + (*self.shared_channels.lock().unwrap()).buffers[i] = channel_data; + + // Step 4 will complete turning shared_channels + // data into js_channels ArrayBuffers in restore_js_channel_data. } self.js_channels.borrow_mut().clear(); @@ -167,16 +176,18 @@ impl AudioBufferMethods for AudioBuffer { } fn CopyFromChannel(&self, - destination: CustomAutoRooterGuard<Float32Array>, - channel_number: u32, - start_in_channel: u32) -> Fallible<()> { + _destination: CustomAutoRooterGuard<Float32Array>, + _channel_number: u32, + _start_in_channel: u32) -> Fallible<()> { + // XXX Ok(()) } fn CopyToChannel(&self, - source: CustomAutoRooterGuard<Float32Array>, - channel_number: u32, - start_in_channel: u32) -> Fallible<()> { + _source: CustomAutoRooterGuard<Float32Array>, + _channel_number: u32, + _start_in_channel: u32) -> Fallible<()> { + // XXX Ok(()) } } diff --git a/components/script/dom/audiobuffersourcenode.rs b/components/script/dom/audiobuffersourcenode.rs index 931e86ad21c..6eefe8c9ad5 100644 --- a/components/script/dom/audiobuffersourcenode.rs +++ b/components/script/dom/audiobuffersourcenode.rs @@ -12,10 +12,12 @@ use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferS use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate; use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions; use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation}; -use dom::bindings::error::Fallible; +use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods; +use dom::bindings::error::{Error, Fallible}; +use dom::bindings::inheritance::Castable; use dom::bindings::num::Finite; use dom::bindings::reflector::reflect_dom_object; -use dom::bindings::root::DomRoot; +use dom::bindings::root::{DomRoot, MutNullableDom}; use dom::window::Window; use dom_struct::dom_struct; use servo_media::audio::buffer_source_node::AudioBufferSourceNodeMessage; @@ -33,8 +35,8 @@ audio_param_impl!(Detune, AudioBufferSourceNode, AudioBufferSourceNodeMessage, S #[dom_struct] pub struct AudioBufferSourceNode { - node: AudioScheduledSourceNode, - // buffer: Option<DomRoot<AudioBuffer>>, + source_node: AudioScheduledSourceNode, + buffer: MutNullableDom<AudioBuffer>, playback_rate: DomRoot<AudioParam>, detune: DomRoot<AudioParam>, loop_enabled: Cell<bool>, @@ -54,28 +56,29 @@ impl AudioBufferSourceNode { node_options.channelCount = Some(2); node_options.channelCountMode = Some(ChannelCountMode::Max); node_options.channelInterpretation = Some(ChannelInterpretation::Speakers); - let node = AudioScheduledSourceNode::new_inherited( + let source_node = AudioScheduledSourceNode::new_inherited( AudioNodeType::AudioBufferSourceNode(options.into()), context, &node_options, 0 /* inputs */, 1 /* outputs */, ); - let playback_rate = PlaybackRate::new(context.audio_context_impl(), node.node_id()); + let node_id = source_node.node().node_id(); + let playback_rate = PlaybackRate::new(context.audio_context_impl(), node_id); let playback_rate = AudioParam::new(&window, Box::new(playback_rate), AutomationRate::K_rate, *options.playbackRate, f32::MIN, f32::MAX); - let detune = Detune::new(context.audio_context_impl(), node.node_id()); + let detune = Detune::new(context.audio_context_impl(), node_id); let detune = AudioParam::new(&window, Box::new(detune), AutomationRate::K_rate, *options.detune, f32::MIN, f32::MAX); AudioBufferSourceNode { - node, - // buffer: options.buffer, + source_node, + buffer: Default::default(), playback_rate, detune, loop_enabled: Cell::new(options.loop_), @@ -104,6 +107,31 @@ impl AudioBufferSourceNode { } impl AudioBufferSourceNodeMethods for AudioBufferSourceNode { + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer + fn GetBuffer(&self) -> Fallible<Option<DomRoot<AudioBuffer>>> { + Ok(self.buffer.get()) + } + + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer + fn SetBuffer(&self, new_buffer: Option<&AudioBuffer>) -> Fallible<()> { + if new_buffer.is_some() && self.buffer.get().is_some() { + return Err(Error::InvalidState); + } + + self.buffer.set(new_buffer); + + if self.source_node.started() { + if let Some(buffer) = self.buffer.get() { + let buffer = buffer.acquire_contents(); + self.source_node.node().message( + AudioNodeMessage::AudioBufferSourceNode( + AudioBufferSourceNodeMessage::SetBuffer(buffer))); + } + } + + Ok(()) + } + fn PlaybackRate(&self) -> DomRoot<AudioParam> { DomRoot::from_ref(&self.playback_rate) } @@ -136,8 +164,17 @@ impl AudioBufferSourceNodeMethods for AudioBufferSourceNode { self.loop_end.set(*loop_end) } - fn Start(&self, when: Finite<f64>, offset: Option<Finite<f64>>, duration: Option<Finite<f64>>) { - // XXX + fn Start(&self, + when: Finite<f64>, + _offset: Option<Finite<f64>>, + _duration: Option<Finite<f64>>) -> Fallible<()> { + if let Some(buffer) = self.buffer.get() { + let buffer = buffer.acquire_contents(); + self.source_node.node().message( + AudioNodeMessage::AudioBufferSourceNode( + AudioBufferSourceNodeMessage::SetBuffer(buffer))); + } + self.source_node.upcast::<AudioScheduledSourceNode>().Start(when) } } diff --git a/components/script/dom/audioscheduledsourcenode.rs b/components/script/dom/audioscheduledsourcenode.rs index 8c8240fdf67..da284e02910 100644 --- a/components/script/dom/audioscheduledsourcenode.rs +++ b/components/script/dom/audioscheduledsourcenode.rs @@ -5,14 +5,17 @@ use dom::audionode::AudioNode; use dom::baseaudiocontext::BaseAudioContext; use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods; use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions; +use dom::bindings::error::{Error, Fallible}; use dom::bindings::num::Finite; use dom_struct::dom_struct; -use servo_media::audio::graph::NodeId; use servo_media::audio::node::{AudioNodeMessage, AudioNodeType, AudioScheduledSourceNodeMessage}; +use std::cell::Cell; #[dom_struct] pub struct AudioScheduledSourceNode { node: AudioNode, + started: Cell<bool>, + stopped: Cell<bool>, } impl AudioScheduledSourceNode { @@ -24,11 +27,17 @@ impl AudioScheduledSourceNode { AudioScheduledSourceNode { node: AudioNode::new_inherited(node_type, None /* node_id */, context, options, number_of_inputs, number_of_outputs), + started: Cell::new(false), + stopped: Cell::new(false), } } - pub fn node_id(&self) -> NodeId { - self.node.node_id() + pub fn node(&self) -> &AudioNode { + &self.node + } + + pub fn started(&self) -> bool { + self.started.get() } } @@ -37,16 +46,26 @@ impl AudioScheduledSourceNodeMethods for AudioScheduledSourceNode { event_handler!(ended, GetOnended, SetOnended); // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-start - fn Start(&self, when: Finite<f64>) { + fn Start(&self, when: Finite<f64>) -> Fallible<()> { + if self.started.get() || self.stopped.get() { + return Err(Error::InvalidState); + } + self.started.set(true); self.node.message( AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(*when)) ); + Ok(()) } // https://webaudio.github.io/web-audio-api/#dom-audioscheduledsourcenode-stop - fn Stop(&self, when: Finite<f64>) { + fn Stop(&self, when: Finite<f64>) -> Fallible<()> { + if !self.started.get() { + return Err(Error::InvalidState); + } + self.stopped.set(true); self.node.message( AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Stop(*when)) ); + Ok(()) } } diff --git a/components/script/dom/baseaudiocontext.rs b/components/script/dom/baseaudiocontext.rs index 401da6bc4d3..59247516659 100644 --- a/components/script/dom/baseaudiocontext.rs +++ b/components/script/dom/baseaudiocontext.rs @@ -3,15 +3,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::audiobuffer::AudioBuffer; +use dom::audiobuffersourcenode::AudioBufferSourceNode; use dom::audiodestinationnode::AudioDestinationNode; +use dom::audionode::MAX_CHANNEL_COUNT; use dom::bindings::cell::DomRefCell; +use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceOptions; use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions; use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation}; use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextMethods; use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState; use dom::bindings::codegen::Bindings::GainNodeBinding::GainOptions; use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorOptions; -use dom::bindings::error::{Error, ErrorResult}; +use dom::bindings::error::{Error, ErrorResult, Fallible}; use dom::bindings::inheritance::Castable; use dom::bindings::num::Finite; use dom::bindings::refcounted::Trusted; @@ -207,23 +210,23 @@ impl BaseAudioContext { } impl BaseAudioContextMethods for BaseAudioContext { - // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-samplerate fn SampleRate(&self) -> Finite<f32> { Finite::wrap(self.sample_rate) } - // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-currenttime fn CurrentTime(&self) -> Finite<f64> { let current_time = self.audio_context_impl.current_time(); Finite::wrap(current_time) } - // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-state fn State(&self) -> AudioContextState { self.state.get() } - // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-resume #[allow(unrooted_must_root)] fn Resume(&self) -> Rc<Promise> { // Step 1. @@ -255,14 +258,15 @@ impl BaseAudioContextMethods for BaseAudioContext { promise } - // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination fn Destination(&self) -> DomRoot<AudioDestinationNode> { DomRoot::from_ref(self.destination.as_ref().unwrap()) } - // https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange event_handler!(statechange, GetOnstatechange, SetOnstatechange); + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createoscillator #[allow(unsafe_code)] fn CreateOscillator(&self) -> DomRoot<OscillatorNode> { let global = self.global(); @@ -271,6 +275,7 @@ impl BaseAudioContextMethods for BaseAudioContext { OscillatorNode::new(&window, &self, &options) } + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-creategain #[allow(unsafe_code)] fn CreateGain(&self) -> DomRoot<GainNode> { let global = self.global(); @@ -279,12 +284,27 @@ impl BaseAudioContextMethods for BaseAudioContext { GainNode::new(&window, &self, &options) } + /// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer fn CreateBuffer(&self, number_of_channels: u32, length: u32, - sample_rate: Finite<f32>) -> DomRoot<AudioBuffer> { + sample_rate: Finite<f32>) -> Fallible<DomRoot<AudioBuffer>> { + if number_of_channels <= 0 || + number_of_channels > MAX_CHANNEL_COUNT || + length <= 0 || + *sample_rate <= 0. { + return Err(Error::NotSupported); + } + let global = self.global(); + Ok(AudioBuffer::new(&global.as_window(), number_of_channels, length, *sample_rate)) + } + + #[allow(unsafe_code)] + fn CreateBufferSource(&self) -> DomRoot<AudioBufferSourceNode> { let global = self.global(); - AudioBuffer::new(&global.as_window(), number_of_channels, length, *sample_rate) + // XXX Can we do this implementing Default? + let options = unsafe { AudioBufferSourceOptions::empty(global.get_cx()) }; + AudioBufferSourceNode::new(&global.as_window(), &self, &options) } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index b84651c8c8a..7a9d4d7358f 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -80,6 +80,7 @@ use offscreen_gl_context::GLLimits; use parking_lot::RwLock; use profile_traits::mem::ProfilerChan as MemProfilerChan; use profile_traits::time::ProfilerChan as TimeProfilerChan; +use servo_media::audio::buffer_source_node::AudioBuffer; use servo_media::audio::context::AudioContext; use servo_media::audio::graph::NodeId; use script_layout_interface::OpaqueStyleAndLayoutData; @@ -432,6 +433,7 @@ unsafe_no_jsmanaged_fields!(InteractiveWindow); unsafe_no_jsmanaged_fields!(CanvasId); unsafe_no_jsmanaged_fields!(SourceSet); unsafe_no_jsmanaged_fields!(AudioGraph); +unsafe_no_jsmanaged_fields!(AudioBuffer); unsafe_no_jsmanaged_fields!(AudioContext); unsafe_no_jsmanaged_fields!(NodeId); diff --git a/components/script/dom/oscillatornode.rs b/components/script/dom/oscillatornode.rs index 7a771916834..71580e20e17 100644 --- a/components/script/dom/oscillatornode.rs +++ b/components/script/dom/oscillatornode.rs @@ -30,7 +30,7 @@ audio_param_impl!(Detune, OscillatorNode, OscillatorNodeMessage, SetDetune); #[dom_struct] pub struct OscillatorNode { - node: AudioScheduledSourceNode, + source_node: AudioScheduledSourceNode, oscillator_type: OscillatorType, frequency: DomRoot<AudioParam>, detune: DomRoot<AudioParam>, @@ -48,26 +48,27 @@ impl OscillatorNode { node_options.channelCount = Some(2); node_options.channelCountMode = Some(ChannelCountMode::Max); node_options.channelInterpretation = Some(ChannelInterpretation::Speakers); - let node = AudioScheduledSourceNode::new_inherited( + let source_node = AudioScheduledSourceNode::new_inherited( AudioNodeType::OscillatorNode(oscillator_options.into()), context, &node_options, 0, /* inputs */ 1, /* outputs */ ); - let frequency = Frequency::new(context.audio_context_impl(), node.node_id()); + let node_id = source_node.node().node_id(); + let frequency = Frequency::new(context.audio_context_impl(), node_id); let frequency = AudioParam::new(window, Box::new(frequency), AutomationRate::A_rate, 440., f32::MIN, f32::MAX); - let detune = Detune::new(context.audio_context_impl(), node.node_id()); + let detune = Detune::new(context.audio_context_impl(), node_id); let detune = AudioParam::new(window, Box::new(detune), AutomationRate::A_rate, 0., -440. / 2., 440. / 2.); OscillatorNode { - node, + source_node, oscillator_type: oscillator_options.type_, frequency, detune, diff --git a/components/script/dom/webidls/AudioBufferSourceNode.webidl b/components/script/dom/webidls/AudioBufferSourceNode.webidl index 45358fbaad8..a91a6afc393 100644 --- a/components/script/dom/webidls/AudioBufferSourceNode.webidl +++ b/components/script/dom/webidls/AudioBufferSourceNode.webidl @@ -18,13 +18,13 @@ dictionary AudioBufferSourceOptions { [Exposed=Window, Constructor (BaseAudioContext context, optional AudioBufferSourceOptions options)] interface AudioBufferSourceNode : AudioScheduledSourceNode { - // attribute AudioBuffer? buffer; + [Throws] attribute AudioBuffer? buffer; readonly attribute AudioParam playbackRate; readonly attribute AudioParam detune; attribute boolean loop; attribute double loopStart; attribute double loopEnd; - void start(optional double when = 0, - optional double offset, - optional double duration); + [Throws] void start(optional double when = 0, + optional double offset, + optional double duration); }; diff --git a/components/script/dom/webidls/AudioScheduledSourceNode.webidl b/components/script/dom/webidls/AudioScheduledSourceNode.webidl index 8e058b129cc..a1ca3fc8a8c 100644 --- a/components/script/dom/webidls/AudioScheduledSourceNode.webidl +++ b/components/script/dom/webidls/AudioScheduledSourceNode.webidl @@ -9,6 +9,6 @@ [Exposed=Window] interface AudioScheduledSourceNode : AudioNode { attribute EventHandler onended; - void start(optional double when = 0); - void stop(optional double when = 0); + [Throws] void start(optional double when = 0); + [Throws] void stop(optional double when = 0); }; diff --git a/components/script/dom/webidls/BaseAudioContext.webidl b/components/script/dom/webidls/BaseAudioContext.webidl index 92564b29a5f..9147ca5ed58 100644 --- a/components/script/dom/webidls/BaseAudioContext.webidl +++ b/components/script/dom/webidls/BaseAudioContext.webidl @@ -24,13 +24,13 @@ interface BaseAudioContext : EventTarget { readonly attribute AudioContextState state; Promise<void> resume(); attribute EventHandler onstatechange; - AudioBuffer createBuffer(unsigned long numberOfChannels, - unsigned long length, - float sampleRate); + [Throws] AudioBuffer createBuffer(unsigned long numberOfChannels, + unsigned long length, + float sampleRate); // Promise<AudioBuffer> decodeAudioData(ArrayBuffer audioData, // optional DecodeSuccessCallback successCallback, // optional DecodeErrorCallback errorCallback); - // AudioBufferSourceNode createBufferSource(); + AudioBufferSourceNode createBufferSource(); // ConstantSourceNode createConstantSource(); // ScriptProcessorNode createScriptProcessor(optional unsigned long bufferSize = 0, // optional unsigned long numberOfInputChannels = 2, |