diff options
author | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-07-03 18:53:11 +0200 |
---|---|---|
committer | Fernando Jiménez Moreno <ferjmoreno@gmail.com> | 2018-07-30 14:21:42 +0200 |
commit | cb16c596b3ed3492ca327fa6033f1121e4e379fe (patch) | |
tree | 6c0722f69d588ffd38f54478ea722d2067bc912c /components | |
parent | 0cb053ad4c984d1b6b8dcfbf95eadaacc1ddc01e (diff) | |
download | servo-cb16c596b3ed3492ca327fa6033f1121e4e379fe.tar.gz servo-cb16c596b3ed3492ca327fa6033f1121e4e379fe.zip |
AudioBuffer.GetChannelData and internal storage
Diffstat (limited to 'components')
-rw-r--r-- | components/script/dom/audiobuffer.rs | 102 | ||||
-rw-r--r-- | components/script/dom/webidls/AudioBuffer.webidl | 14 |
2 files changed, 95 insertions, 21 deletions
diff --git a/components/script/dom/audiobuffer.rs b/components/script/dom/audiobuffer.rs index b5a8f43ca9a..5e6855ae689 100644 --- a/components/script/dom/audiobuffer.rs +++ b/components/script/dom/audiobuffer.rs @@ -3,28 +3,27 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use dom::audionode::MAX_CHANNEL_COUNT; +use dom::bindings::cell::DomRefCell; use dom::bindings::codegen::Bindings::AudioBufferBinding::{self, AudioBufferMethods, AudioBufferOptions}; use dom::bindings::error::{Error, Fallible}; use dom::bindings::num::Finite; -use dom::bindings::reflector::{Reflector, reflect_dom_object}; +use dom::bindings::reflector::{DomObject, Reflector, reflect_dom_object}; use dom::bindings::root::DomRoot; use dom::window::Window; use dom_struct::dom_struct; -use smallvec::SmallVec; +use js::conversions::ToJSValConvertible; +use js::jsapi::{Heap, JSContext, JSObject, JS_StealArrayBufferContents}; +use js::typedarray::{CreateWith, Float32Array}; +use std::ptr::{self, NonNull}; +use std::slice; -#[derive(JSTraceable, MallocSizeOf)] -struct AudioChannel(pub Vec<f32>); - -impl AudioChannel { - pub fn new(capacity: usize) -> AudioChannel { - AudioChannel(Vec::with_capacity(capacity)) - } -} +type JSAudioChannel = Heap<*mut JSObject>; #[dom_struct] pub struct AudioBuffer { reflector_: Reflector, - internal_data: SmallVec<[AudioChannel; MAX_CHANNEL_COUNT as usize]>, + js_channels: Vec<JSAudioChannel>, + shared_channels: DomRefCell<Option<Vec<Vec<f32>>>>, sample_rate: f32, length: u32, duration: f64, @@ -35,11 +34,10 @@ impl AudioBuffer { #[allow(unrooted_must_root)] #[allow(unsafe_code)] pub fn new_inherited(options: &AudioBufferOptions) -> AudioBuffer { - let mut internal_data = SmallVec::new(); - unsafe { internal_data.set_len(options.numberOfChannels as usize); } AudioBuffer { reflector_: Reflector::new(), - internal_data, + js_channels: Vec::with_capacity(options.numberOfChannels as usize), + shared_channels: DomRefCell::new(None), sample_rate: *options.sampleRate, length: options.length, duration: options.length as f64 / *options.sampleRate as f64, @@ -61,22 +59,98 @@ impl AudioBuffer { } Ok(AudioBuffer::new(window, options)) } + + #[allow(unsafe_code)] + fn restore_js_channel_data(&self, cx: *mut JSContext) -> bool { + for (i, channel) in self.js_channels.iter().enumerate() { + if !channel.get().is_null() { + // Already have data in JS array. + continue; + } + + match *self.shared_channels.borrow_mut() { + Some(ref mut shared_channels) => { + // Step 4 of https://webaudio.github.io/web-audio-api/#acquire-the-content + // "Attach ArrayBuffers containing copies of the data of the AudioBuffer, to + // be returned by the next call to getChannelData()". + rooted!(in (cx) let mut array = ptr::null_mut::<JSObject>()); + let shared_channel = shared_channels.remove(i); + if unsafe { + Float32Array::create(cx, CreateWith::Slice(&shared_channel), array.handle_mut()) + }.is_err() { + return false; + } + channel.set(array.get()); + }, + None => return false, + } + } + + *self.shared_channels.borrow_mut() = None; + + true + } + + /// https://webaudio.github.io/web-audio-api/#acquire-the-content + #[allow(unsafe_code)] + pub fn acquire_contents(&self) { + let cx = self.global().get_cx(); + for (i, channel) in self.js_channels.iter().enumerate() { + // Step 1. + if channel.get().is_null() { + return; + } + + // Step 2. + let channel_data = unsafe { + slice::from_raw_parts( + JS_StealArrayBufferContents(cx, channel.handle()) as *mut f32, + self.length as usize + ).to_vec() + }; + + // Step 3. + let mut shared_channels = self.shared_channels.borrow_mut(); + if shared_channels.is_none() { + *shared_channels = Some(Vec::with_capacity(self.number_of_channels as usize)); + } + (*shared_channels).as_mut().unwrap()[i] = channel_data; + } + } } impl AudioBufferMethods for AudioBuffer { + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-samplerate fn SampleRate(&self) -> Finite<f32> { Finite::wrap(self.sample_rate) } + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-length fn Length(&self) -> u32 { self.length } + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-duration fn Duration(&self) -> Finite<f64> { Finite::wrap(self.duration) } + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-numberofchannels fn NumberOfChannels(&self) -> u32 { self.number_of_channels } + + /// https://webaudio.github.io/web-audio-api/#dom-audiobuffer-getchanneldata + #[allow(unsafe_code)] + unsafe fn GetChannelData(&self, cx: *mut JSContext, channel: u32) -> Fallible<NonNull<JSObject>> { + if channel >= self.number_of_channels { + return Err(Error::IndexSize); + } + + if !self.restore_js_channel_data(cx) { + return Err(Error::JSFailed); + } + + Ok(NonNull::new_unchecked(self.js_channels[channel as usize].get())) + } } diff --git a/components/script/dom/webidls/AudioBuffer.webidl b/components/script/dom/webidls/AudioBuffer.webidl index 7ec015ecb2f..f5290a36aea 100644 --- a/components/script/dom/webidls/AudioBuffer.webidl +++ b/components/script/dom/webidls/AudioBuffer.webidl @@ -19,11 +19,11 @@ interface AudioBuffer { readonly attribute unsigned long length; readonly attribute double duration; readonly attribute unsigned long numberOfChannels; -// Float32Array getChannelData(unsigned long channel); -// void copyFromChannel(Float32Array destination, -// unsigned long channelNumber, -// optional unsigned long startInChannel = 0); -// void copyToChannel (Float32Array source, -// unsigned long channelNumber, -// optional unsigned long startInChannel = 0); + [Throws] Float32Array getChannelData(unsigned long channel); +//[Throws] void copyFromChannel(Float32Array destination, +// unsigned long channelNumber, +// optional unsigned long startInChannel = 0); +//[Throws] void copyToChannel(Float32Array source, +// unsigned long channelNumber, +// optional unsigned long startInChannel = 0); }; |