aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorFernando Jiménez Moreno <ferjmoreno@gmail.com>2018-07-03 18:53:11 +0200
committerFernando Jiménez Moreno <ferjmoreno@gmail.com>2018-07-30 14:21:42 +0200
commitcb16c596b3ed3492ca327fa6033f1121e4e379fe (patch)
tree6c0722f69d588ffd38f54478ea722d2067bc912c /components
parent0cb053ad4c984d1b6b8dcfbf95eadaacc1ddc01e (diff)
downloadservo-cb16c596b3ed3492ca327fa6033f1121e4e379fe.tar.gz
servo-cb16c596b3ed3492ca327fa6033f1121e4e379fe.zip
AudioBuffer.GetChannelData and internal storage
Diffstat (limited to 'components')
-rw-r--r--components/script/dom/audiobuffer.rs102
-rw-r--r--components/script/dom/webidls/AudioBuffer.webidl14
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);
};