Auto merge of #21502 - Manishearth:listener, r=ferjm

Add AudioListener/AudioPanner DOM interfaces

Seems to work.

I'll need some changes to the servo-media side to support the panner
node getters as well as the older `setPosition()`/etc APIs. I'll get to
those later.

r? @ferjm

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21502)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-08-24 19:13:05 -04:00 committed by GitHub
commit d827370804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 822 additions and 340 deletions

18
Cargo.lock generated
View file

@ -3197,7 +3197,7 @@ dependencies = [
[[package]]
name = "servo-media"
version = "0.1.0"
source = "git+https://github.com/servo/media#7a5c334698aa1e8a9cf95c5bd761e4a31489b6db"
source = "git+https://github.com/servo/media#6ecac1c6259b3995e8d6a368e49777e5c2d398ae"
dependencies = [
"servo-media-audio 0.1.0 (git+https://github.com/servo/media)",
"servo-media-gstreamer 0.1.0 (git+https://github.com/servo/media)",
@ -3207,9 +3207,10 @@ dependencies = [
[[package]]
name = "servo-media-audio"
version = "0.1.0"
source = "git+https://github.com/servo/media#7a5c334698aa1e8a9cf95c5bd761e4a31489b6db"
source = "git+https://github.com/servo/media#6ecac1c6259b3995e8d6a368e49777e5c2d398ae"
dependencies = [
"byte-slice-cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"servo_media_derive 0.1.0 (git+https://github.com/servo/media)",
@ -3219,7 +3220,7 @@ dependencies = [
[[package]]
name = "servo-media-gstreamer"
version = "0.1.0"
source = "git+https://github.com/servo/media#7a5c334698aa1e8a9cf95c5bd761e4a31489b6db"
source = "git+https://github.com/servo/media#6ecac1c6259b3995e8d6a368e49777e5c2d398ae"
dependencies = [
"byte-slice-cast 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glib 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3227,7 +3228,7 @@ dependencies = [
"gstreamer-app 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-audio 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gstreamer-player 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"servo-media-audio 0.1.0 (git+https://github.com/servo/media)",
"servo-media-player 0.1.0 (git+https://github.com/servo/media)",
@ -3237,7 +3238,12 @@ dependencies = [
[[package]]
name = "servo-media-player"
version = "0.1.0"
source = "git+https://github.com/servo/media#7a5c334698aa1e8a9cf95c5bd761e4a31489b6db"
source = "git+https://github.com/servo/media#6ecac1c6259b3995e8d6a368e49777e5c2d398ae"
dependencies = [
"ipc-channel 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "servo-skia"
@ -3318,7 +3324,7 @@ dependencies = [
[[package]]
name = "servo_media_derive"
version = "0.1.0"
source = "git+https://github.com/servo/media#7a5c334698aa1e8a9cf95c5bd761e4a31489b6db"
source = "git+https://github.com/servo/media#6ecac1c6259b3995e8d6a368e49777e5c2d398ae"
dependencies = [
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",

View file

@ -10,7 +10,6 @@ use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::root::DomRoot;
use dom::globalscope::GlobalScope;
use dom_struct::dom_struct;
use servo_media::audio::node::AudioNodeInit;
#[dom_struct]
pub struct AudioDestinationNode {
@ -23,9 +22,8 @@ impl AudioDestinationNode {
options: &AudioNodeOptions,
) -> AudioDestinationNode {
AudioDestinationNode {
node: AudioNode::new_inherited(
AudioNodeInit::DestinationNode,
Some(context.destination_node()),
node: AudioNode::new_inherited_for_id(
context.destination_node(),
context,
options,
1,

View file

@ -0,0 +1,190 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::audioparam::AudioParam;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioListenerBinding::{self, AudioListenerMethods};
use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::root::{Dom, DomRoot};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::param::{ParamType, ParamDir};
use std::f32;
#[dom_struct]
pub struct AudioListener {
reflector_: Reflector,
position_x: Dom<AudioParam>,
position_y: Dom<AudioParam>,
position_z: Dom<AudioParam>,
forward_x: Dom<AudioParam>,
forward_y: Dom<AudioParam>,
forward_z: Dom<AudioParam>,
up_x: Dom<AudioParam>,
up_y: Dom<AudioParam>,
up_z: Dom<AudioParam>,
}
impl AudioListener {
fn new_inherited(
window: &Window,
context: &BaseAudioContext,
) -> AudioListener {
let node = context.listener();
let position_x = AudioParam::new(
window,
context,
node,
ParamType::Position(ParamDir::X),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let position_y = AudioParam::new(
window,
context,
node,
ParamType::Position(ParamDir::Y),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let position_z = AudioParam::new(
window,
context,
node,
ParamType::Position(ParamDir::Z),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let forward_x = AudioParam::new(
window,
context,
node,
ParamType::Forward(ParamDir::X),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let forward_y = AudioParam::new(
window,
context,
node,
ParamType::Forward(ParamDir::Y),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let forward_z = AudioParam::new(
window,
context,
node,
ParamType::Forward(ParamDir::Z),
AutomationRate::A_rate,
-1., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let up_x = AudioParam::new(
window,
context,
node,
ParamType::Up(ParamDir::X),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let up_y = AudioParam::new(
window,
context,
node,
ParamType::Up(ParamDir::Y),
AutomationRate::A_rate,
1., // default value
f32::MIN, // min value
f32::MAX, // max value
);
let up_z = AudioParam::new(
window,
context,
node,
ParamType::Up(ParamDir::Z),
AutomationRate::A_rate,
0., // default value
f32::MIN, // min value
f32::MAX, // max value
);
AudioListener {
reflector_: Reflector::new(),
position_x: Dom::from_ref(&position_x),
position_y: Dom::from_ref(&position_y),
position_z: Dom::from_ref(&position_z),
forward_x: Dom::from_ref(&forward_x),
forward_y: Dom::from_ref(&forward_y),
forward_z: Dom::from_ref(&forward_z),
up_x: Dom::from_ref(&up_x),
up_y: Dom::from_ref(&up_y),
up_z: Dom::from_ref(&up_z),
}
}
#[allow(unrooted_must_root)]
pub fn new(
window: &Window,
context: &BaseAudioContext,
) -> DomRoot<AudioListener> {
let node = AudioListener::new_inherited(window, context);
reflect_dom_object(Box::new(node), window, AudioListenerBinding::Wrap)
}
}
impl AudioListenerMethods for AudioListener {
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-positionx
fn PositionX(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.position_x)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-positiony
fn PositionY(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.position_y)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-positionz
fn PositionZ(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.position_z)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-forwardx
fn ForwardX(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.forward_x)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-forwardy
fn ForwardY(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.forward_y)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-forwardz
fn ForwardZ(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.forward_z)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-upx
fn UpX(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.up_x)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-upy
fn UpY(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.up_y)
}
// https://webaudio.github.io/web-audio-api/#dom-audiolistener-upz
fn UpZ(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.up_z)
}
}

View file

@ -36,17 +36,26 @@ pub struct AudioNode {
channel_interpretation: Cell<ChannelInterpretation>,
}
impl AudioNode {
pub fn new_inherited(
node_type: AudioNodeInit,
node_id: Option<NodeId>,
context: &BaseAudioContext,
options: &AudioNodeOptions,
number_of_inputs: u32,
number_of_outputs: u32,
) -> AudioNode {
let node_id =
node_id.unwrap_or_else(|| context.audio_context_impl().create_node(node_type));
let node_id = context.audio_context_impl().create_node(node_type);
AudioNode::new_inherited_for_id(node_id, context, options, number_of_inputs, number_of_outputs)
}
pub fn new_inherited_for_id(
node_id: NodeId,
context: &BaseAudioContext,
options: &AudioNodeOptions,
number_of_inputs: u32,
number_of_outputs: u32,
) -> AudioNode {
AudioNode {
eventtarget: EventTarget::new_inherited(),
node_id,
@ -204,6 +213,11 @@ impl AudioNodeMethods for AudioNode {
return Err(Error::IndexSize);
}
},
EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => {
if value > 2 {
return Err(Error::NotSupported)
}
}
// XXX We do not support any of the other AudioNodes with
// constraints yet. Add more cases here as we add support
// for new AudioNodes.
@ -237,6 +251,11 @@ impl AudioNodeMethods for AudioNode {
return Err(Error::InvalidState);
}
},
EventTargetTypeId::AudioNode(AudioNodeTypeId::PannerNode) => {
if value == ChannelCountMode::Max {
return Err(Error::NotSupported)
}
}
// XXX We do not support any of the other AudioNodes with
// constraints yet. Add more cases here as we add support
// for new AudioNodes.

View file

@ -34,7 +34,6 @@ impl AudioScheduledSourceNode {
AudioScheduledSourceNode {
node: AudioNode::new_inherited(
node_type,
None, /* node_id */
context,
options,
number_of_inputs,

View file

@ -5,6 +5,7 @@
use dom::audiobuffer::AudioBuffer;
use dom::audiobuffersourcenode::AudioBufferSourceNode;
use dom::audiodestinationnode::AudioDestinationNode;
use dom::audiolistener::AudioListener;
use dom::audionode::MAX_CHANNEL_COUNT;
use dom::bindings::callback::ExceptionHandling;
use dom::bindings::cell::DomRefCell;
@ -17,6 +18,7 @@ use dom::bindings::codegen::Bindings::BaseAudioContextBinding::DecodeErrorCallba
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::DecodeSuccessCallback;
use dom::bindings::codegen::Bindings::GainNodeBinding::GainOptions;
use dom::bindings::codegen::Bindings::OscillatorNodeBinding::OscillatorOptions;
use dom::bindings::codegen::Bindings::PannerNodeBinding::PannerOptions;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
@ -27,6 +29,7 @@ use dom::domexception::{DOMErrorName, DOMException};
use dom::eventtarget::EventTarget;
use dom::gainnode::GainNode;
use dom::oscillatornode::OscillatorNode;
use dom::pannernode::PannerNode;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
@ -63,9 +66,10 @@ struct DecodeResolver {
pub struct BaseAudioContext {
eventtarget: EventTarget,
#[ignore_malloc_size_of = "servo_media"]
audio_context_impl: Rc<AudioContext<Backend>>,
audio_context_impl: AudioContext<Backend>,
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-destination
destination: MutNullableDom<AudioDestinationNode>,
listener: MutNullableDom<AudioListener>,
/// Resume promises which are soon to be fulfilled by a queued task.
#[ignore_malloc_size_of = "promises are hard"]
in_flight_resume_promises_queue: DomRefCell<VecDeque<(Box<[Rc<Promise>]>, ErrorResult)>>,
@ -95,12 +99,11 @@ impl BaseAudioContext {
let context = BaseAudioContext {
eventtarget: EventTarget::new_inherited(),
audio_context_impl: Rc::new(
ServoMedia::get()
.unwrap()
.create_audio_context(options.into()),
),
audio_context_impl: ServoMedia::get()
.unwrap()
.create_audio_context(options.into()),
destination: Default::default(),
listener: Default::default(),
in_flight_resume_promises_queue: Default::default(),
pending_resume_promises: Default::default(),
decode_resolvers: Default::default(),
@ -117,14 +120,18 @@ impl BaseAudioContext {
false
}
pub fn audio_context_impl(&self) -> Rc<AudioContext<Backend>> {
self.audio_context_impl.clone()
pub fn audio_context_impl(&self) -> &AudioContext<Backend> {
&self.audio_context_impl
}
pub fn destination_node(&self) -> NodeId {
self.audio_context_impl.dest_node()
}
pub fn listener(&self) -> NodeId {
self.audio_context_impl.listener()
}
// https://webaudio.github.io/web-audio-api/#allowed-to-start
pub fn is_allowed_to_start(&self) -> bool {
self.state.get() == AudioContextState::Suspended
@ -297,6 +304,15 @@ impl BaseAudioContextMethods for BaseAudioContext {
})
}
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-listener
fn Listener(&self) -> DomRoot<AudioListener> {
let global = self.global();
let window = global.as_window();
self.listener.or_init(|| {
AudioListener::new(&window, self)
})
}
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-onstatechange
event_handler!(statechange, GetOnstatechange, SetOnstatechange);
@ -314,6 +330,12 @@ impl BaseAudioContextMethods for BaseAudioContext {
GainNode::new(&self.global().as_window(), &self, &GainOptions::empty())
}
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createpanner
fn CreatePanner(&self) -> Fallible<DomRoot<PannerNode>> {
PannerNode::new(&self.global().as_window(), &self, &PannerOptions::empty())
}
/// https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createbuffer
fn CreateBuffer(
&self,

View file

@ -92,6 +92,7 @@ use servo_media::Backend;
use servo_media::audio::buffer_source_node::AudioBuffer;
use servo_media::audio::context::AudioContext;
use servo_media::audio::graph::NodeId;
use servo_media::audio::panner_node::{DistanceModel, PanningModel};
use servo_media::audio::param::ParamType;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use smallvec::SmallVec;
@ -434,7 +435,7 @@ unsafe_no_jsmanaged_fields!(SourceSet);
unsafe_no_jsmanaged_fields!(AudioBuffer);
unsafe_no_jsmanaged_fields!(AudioContext<Backend>);
unsafe_no_jsmanaged_fields!(NodeId);
unsafe_no_jsmanaged_fields!(ParamType);
unsafe_no_jsmanaged_fields!(DistanceModel, PanningModel, ParamType);
unsafe impl<'a> JSTraceable for &'a str {
#[inline]

View file

@ -38,7 +38,6 @@ impl GainNode {
node_options.channelInterpretation = Some(ChannelInterpretation::Speakers);
let node = AudioNode::new_inherited(
AudioNodeInit::GainNode(gain_options.into()),
None,
context,
&node_options,
1, // inputs

View file

@ -220,6 +220,7 @@ pub mod audiobuffer;
pub mod audiobuffersourcenode;
pub mod audiocontext;
pub mod audiodestinationnode;
pub mod audiolistener;
pub mod audionode;
pub mod audioparam;
pub mod audioscheduledsourcenode;
@ -408,6 +409,7 @@ pub mod pagetransitionevent;
pub mod paintrenderingcontext2d;
pub mod paintsize;
pub mod paintworkletglobalscope;
pub mod pannernode;
pub mod performance;
pub mod performanceentry;
pub mod performancemark;

View file

@ -0,0 +1,354 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use dom::audionode::AudioNode;
use dom::audioparam::AudioParam;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioNodeBinding::{ChannelCountMode, ChannelInterpretation};
use dom::bindings::codegen::Bindings::AudioNodeBinding::AudioNodeOptions;
use dom::bindings::codegen::Bindings::AudioParamBinding::{AudioParamMethods, AutomationRate};
use dom::bindings::codegen::Bindings::PannerNodeBinding::{self, PannerNodeMethods, PannerOptions};
use dom::bindings::codegen::Bindings::PannerNodeBinding::{DistanceModelType, PanningModelType};
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::{Dom, DomRoot};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage};
use servo_media::audio::panner_node::{DistanceModel, PannerNodeOptions, PanningModel};
use servo_media::audio::panner_node::PannerNodeMessage;
use servo_media::audio::param::{ParamDir, ParamType};
use std::cell::Cell;
use std::f32;
#[dom_struct]
pub struct PannerNode {
node: AudioNode,
position_x: Dom<AudioParam>,
position_y: Dom<AudioParam>,
position_z: Dom<AudioParam>,
orientation_x: Dom<AudioParam>,
orientation_y: Dom<AudioParam>,
orientation_z: Dom<AudioParam>,
#[ignore_malloc_size_of = "servo_media"]
panning_model: Cell<PanningModel>,
#[ignore_malloc_size_of = "servo_media"]
distance_model: Cell<DistanceModel>,
ref_distance: Cell<f64>,
max_distance: Cell<f64>,
rolloff_factor: Cell<f64>,
cone_inner_angle: Cell<f64>,
cone_outer_angle: Cell<f64>,
cone_outer_gain: Cell<f64>,
}
impl PannerNode {
#[allow(unrooted_must_root)]
pub fn new_inherited(
window: &Window,
context: &BaseAudioContext,
options: &PannerOptions,
) -> Fallible<PannerNode> {
let count = options.parent.channelCount.unwrap_or(2);
let mode = options.parent.channelCountMode.unwrap_or(ChannelCountMode::Clamped_max);
if mode == ChannelCountMode::Max {
return Err(Error::NotSupported)
}
if count > 2 {
return Err(Error::NotSupported)
}
let mut node_options = AudioNodeOptions::empty();
node_options.channelCount = Some(count);
node_options.channelCountMode = Some(mode);
node_options.channelInterpretation = Some(ChannelInterpretation::Speakers);
let options = options.into();
let node = AudioNode::new_inherited(
AudioNodeInit::PannerNode(options),
context,
&node_options,
1, // inputs
1, // outputs
);
let id = node.node_id();
let position_x = AudioParam::new(
window,
context,
id,
ParamType::Position(ParamDir::X),
AutomationRate::A_rate,
options.position_x, // default value
f32::MIN, // min value
f32::MAX, // max value
);
let position_y = AudioParam::new(
window,
context,
id,
ParamType::Position(ParamDir::Y),
AutomationRate::A_rate,
options.position_y, // default value
f32::MIN, // min value
f32::MAX, // max value
);
let position_z = AudioParam::new(
window,
context,
id,
ParamType::Position(ParamDir::Z),
AutomationRate::A_rate,
options.position_z, // default value
f32::MIN, // min value
f32::MAX, // max value
);
let orientation_x = AudioParam::new(
window,
context,
id,
ParamType::Orientation(ParamDir::X),
AutomationRate::A_rate,
options.orientation_x, // default value
f32::MIN, // min value
f32::MAX, // max value
);
let orientation_y = AudioParam::new(
window,
context,
id,
ParamType::Orientation(ParamDir::Y),
AutomationRate::A_rate,
options.orientation_y, // default value
f32::MIN, // min value
f32::MAX, // max value
);
let orientation_z = AudioParam::new(
window,
context,
id,
ParamType::Orientation(ParamDir::Z),
AutomationRate::A_rate,
options.orientation_z, // default value
f32::MIN, // min value
f32::MAX, // max value
);
Ok(PannerNode {
node,
position_x: Dom::from_ref(&position_x),
position_y: Dom::from_ref(&position_y),
position_z: Dom::from_ref(&position_z),
orientation_x: Dom::from_ref(&orientation_x),
orientation_y: Dom::from_ref(&orientation_y),
orientation_z: Dom::from_ref(&orientation_z),
panning_model: Cell::new(options.panning_model),
distance_model: Cell::new(options.distance_model),
ref_distance: Cell::new(options.ref_distance),
max_distance: Cell::new(options.max_distance),
rolloff_factor: Cell::new(options.rolloff_factor),
cone_inner_angle: Cell::new(options.cone_inner_angle),
cone_outer_angle: Cell::new(options.cone_outer_angle),
cone_outer_gain: Cell::new(options.cone_outer_gain),
})
}
#[allow(unrooted_must_root)]
pub fn new(
window: &Window,
context: &BaseAudioContext,
options: &PannerOptions,
) -> Fallible<DomRoot<PannerNode>> {
let node = PannerNode::new_inherited(window, context, options)?;
Ok(reflect_dom_object(Box::new(node), window, PannerNodeBinding::Wrap))
}
pub fn Constructor(
window: &Window,
context: &BaseAudioContext,
options: &PannerOptions,
) -> Fallible<DomRoot<PannerNode>> {
PannerNode::new(window, context, options)
}
}
impl PannerNodeMethods for PannerNode {
// https://webaudio.github.io/web-audio-api/#dom-pannernode-positionx
fn PositionX(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.position_x)
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-positiony
fn PositionY(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.position_y)
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-positionz
fn PositionZ(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.position_z)
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-orientationx
fn OrientationX(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.orientation_x)
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-orientationy
fn OrientationY(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.orientation_y)
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-orientationz
fn OrientationZ(&self) -> DomRoot<AudioParam> {
DomRoot::from_ref(&self.orientation_z)
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-distancemodel
fn DistanceModel(&self) -> DistanceModelType {
match self.distance_model.get() {
DistanceModel::Linear => DistanceModelType::Linear,
DistanceModel::Inverse => DistanceModelType::Inverse,
DistanceModel::Exponential => DistanceModelType::Exponential,
}
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-distancemodel
fn SetDistanceModel(&self, model: DistanceModelType) {
self.distance_model.set(model.into());
let msg = PannerNodeMessage::SetDistanceModel(self.distance_model.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-panningmodel
fn PanningModel(&self) -> PanningModelType {
match self.panning_model.get() {
PanningModel::EqualPower => PanningModelType::Equalpower,
PanningModel::HRTF => PanningModelType::HRTF,
}
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-panningmodel
fn SetPanningModel(&self, model: PanningModelType) {
self.panning_model.set(model.into());
let msg = PannerNodeMessage::SetPanningModel(self.panning_model.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-refdistance
fn RefDistance(&self) -> Finite<f64> {
Finite::wrap(self.ref_distance.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-refdistance
fn SetRefDistance(&self, val: Finite<f64>) {
self.ref_distance.set(*val);
let msg = PannerNodeMessage::SetRefDistance(self.ref_distance.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-maxdistance
fn MaxDistance(&self) -> Finite<f64> {
Finite::wrap(self.max_distance.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-maxdistance
fn SetMaxDistance(&self, val: Finite<f64>) -> Fallible<()> {
if *val < 0. {
return Err(Error::NotSupported)
}
self.max_distance.set(*val);
let msg = PannerNodeMessage::SetMaxDistance(self.max_distance.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
Ok(())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-rollofffactor
fn RolloffFactor(&self) -> Finite<f64> {
Finite::wrap(self.rolloff_factor.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-rollofffactor
fn SetRolloffFactor(&self, val: Finite<f64>) -> Fallible<()> {
if *val < 0. {
return Err(Error::Range("value should be positive".into()))
}
self.rolloff_factor.set(*val);
let msg = PannerNodeMessage::SetRolloff(self.rolloff_factor.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
Ok(())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneinnerangle
fn ConeInnerAngle(&self) -> Finite<f64> {
Finite::wrap(self.cone_inner_angle.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneinnerangle
fn SetConeInnerAngle(&self, val: Finite<f64>) {
self.cone_inner_angle.set(*val);
let msg = PannerNodeMessage::SetConeInner(self.cone_inner_angle.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneouterangle
fn ConeOuterAngle(&self) -> Finite<f64> {
Finite::wrap(self.cone_outer_angle.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneouterangle
fn SetConeOuterAngle(&self, val: Finite<f64>) {
self.cone_outer_angle.set(*val);
let msg = PannerNodeMessage::SetConeOuter(self.cone_outer_angle.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneoutergain
fn ConeOuterGain(&self) -> Finite<f64> {
Finite::wrap(self.cone_outer_gain.get())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-coneoutergain
fn SetConeOuterGain(&self, val: Finite<f64>) -> Fallible<()> {
if *val < 0. || *val > 360. {
return Err(Error::InvalidState)
}
self.cone_outer_gain.set(*val);
let msg = PannerNodeMessage::SetConeGain(self.cone_outer_gain.get());
self.upcast::<AudioNode>().message(AudioNodeMessage::PannerNode(msg));
Ok(())
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-setposition
fn SetPosition(&self, x: Finite<f32>, y: Finite<f32>, z: Finite<f32>) {
self.position_x.SetValue(x);
self.position_y.SetValue(y);
self.position_z.SetValue(z);
}
// https://webaudio.github.io/web-audio-api/#dom-pannernode-setorientation
fn SetOrientation(&self, x: Finite<f32>, y: Finite<f32>, z: Finite<f32>) {
self.orientation_x.SetValue(x);
self.orientation_y.SetValue(y);
self.orientation_z.SetValue(z);
}
}
impl<'a> From<&'a PannerOptions> for PannerNodeOptions {
fn from(options: &'a PannerOptions) -> Self {
Self {
panning_model: options.panningModel.into(),
distance_model: options.distanceModel.into(),
position_x: *options.positionX,
position_y: *options.positionY,
position_z: *options.positionZ,
orientation_x: *options.orientationX,
orientation_y: *options.orientationY,
orientation_z: *options.orientationZ,
ref_distance: *options.refDistance,
max_distance: *options.maxDistance,
rolloff_factor: *options.rolloffFactor,
cone_inner_angle: *options.coneInnerAngle,
cone_outer_angle: *options.coneOuterAngle,
cone_outer_gain: *options.coneOuterGain,
}
}
}
impl From<DistanceModelType> for DistanceModel {
fn from(model: DistanceModelType) -> Self {
match model {
DistanceModelType::Linear => DistanceModel::Linear,
DistanceModelType::Inverse => DistanceModel::Inverse,
DistanceModelType::Exponential => DistanceModel::Exponential,
}
}
}
impl From<PanningModelType> for PanningModel {
fn from(model: PanningModelType) -> Self {
match model {
PanningModelType::Equalpower => PanningModel::EqualPower,
PanningModelType::HRTF => PanningModel::HRTF,
}
}
}

View file

@ -0,0 +1,22 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The origin of this IDL file is
* https://webaudio.github.io/web-audio-api/#audiolistener
*/
[Exposed=Window]
interface AudioListener {
readonly attribute AudioParam positionX;
readonly attribute AudioParam positionY;
readonly attribute AudioParam positionZ;
readonly attribute AudioParam forwardX;
readonly attribute AudioParam forwardY;
readonly attribute AudioParam forwardZ;
readonly attribute AudioParam upX;
readonly attribute AudioParam upY;
readonly attribute AudioParam upZ;
// void setPosition (float x, float y, float z);
// void setOrientation (float x, float y, float z, float xUp, float yUp, float zUp);
};

View file

@ -20,7 +20,7 @@ interface BaseAudioContext : EventTarget {
readonly attribute AudioDestinationNode destination;
readonly attribute float sampleRate;
readonly attribute double currentTime;
// readonly attribute AudioListener listener;
readonly attribute AudioListener listener;
readonly attribute AudioContextState state;
Promise<void> resume();
attribute EventHandler onstatechange;
@ -42,7 +42,7 @@ interface BaseAudioContext : EventTarget {
// IIRFilterNode createIIRFilter(sequence<double> feedforward,
// sequence<double> feedback);
// WaveShaperNode createWaveShaper();
// PannerNode createPanner();
[Throws] PannerNode createPanner();
// StereoPannerNode createStereoPanner();
// ConvolverNode createConvolver();
// ChannelSplitterNode createChannelSplitter(optional unsigned long numberOfOutputs = 6);

View file

@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The origin of this IDL file is
* https://webaudio.github.io/web-audio-api/#pannernode
*/
dictionary PannerOptions : AudioNodeOptions {
PanningModelType panningModel = "equalpower";
DistanceModelType distanceModel = "inverse";
float positionX = 0;
float positionY = 0;
float positionZ = 0;
float orientationX = 1;
float orientationY = 0;
float orientationZ = 0;
double refDistance = 1;
double maxDistance = 10000;
double rolloffFactor = 1;
double coneInnerAngle = 360;
double coneOuterAngle = 360;
double coneOuterGain = 0;
};
enum DistanceModelType {
"linear",
"inverse",
"exponential"
};
enum PanningModelType {
"equalpower",
"HRTF"
};
[Exposed=Window,
Constructor (BaseAudioContext context, optional PannerOptions options)]
interface PannerNode : AudioNode {
attribute PanningModelType panningModel;
readonly attribute AudioParam positionX;
readonly attribute AudioParam positionY;
readonly attribute AudioParam positionZ;
readonly attribute AudioParam orientationX;
readonly attribute AudioParam orientationY;
readonly attribute AudioParam orientationZ;
attribute DistanceModelType distanceModel;
attribute double refDistance;
[SetterThrows] attribute double maxDistance;
[SetterThrows] attribute double rolloffFactor;
attribute double coneInnerAngle;
attribute double coneOuterAngle;
[SetterThrows] attribute double coneOuterGain;
void setPosition (float x, float y, float z);
void setOrientation (float x, float y, float z);
};

View file

@ -0,0 +1,32 @@
<script type="text/javascript">
let ctx = new AudioContext();
let osc = ctx.createOscillator();
let options = {
"coneOuterAngle": 0,
"positionX": 100, "positionY": 0, "positionZ": 100,
"refDistance": 100, "rolloffFactor": 0.01
};
let panner = new PannerNode(ctx, options);
osc.connect(panner);
panner.connect(ctx.destination);
osc.start();
panner.positionX.linearRampToValueAtTime(-100, 0.2);
panner.positionZ.linearRampToValueAtTime(100, 0.2);
panner.positionX.linearRampToValueAtTime(-100, 0.4);
panner.positionZ.linearRampToValueAtTime(-100, 0.4);
panner.positionX.linearRampToValueAtTime(100, 0.6);
panner.positionZ.linearRampToValueAtTime(-100, 0.6);
panner.positionX.linearRampToValueAtTime(100, 0.8);
panner.positionZ.linearRampToValueAtTime(100, 0.8);
panner.positionX.linearRampToValueAtTime(-100, 1.0);
panner.positionZ.linearRampToValueAtTime(100, 1.0);
panner.positionX.linearRampToValueAtTime(-100, 1.2);
panner.positionZ.linearRampToValueAtTime(-100, 1.2);
panner.positionX.linearRampToValueAtTime(100, 1.4);
panner.positionZ.linearRampToValueAtTime(-100, 1.4);
panner.positionX.linearRampToValueAtTime(100, 1.6);
panner.positionZ.linearRampToValueAtTime(100, 1.6);
panner.positionZ.linearRampToValueAtTime(10000, 3);
ctx.listener.positionZ.setValueAtTime(0, 3);
ctx.listener.positionZ.linearRampToValueAtTime(10000, 4);
</script>

View file

@ -1,13 +0,0 @@
[historical.html]
[dopplerFactor member should not exist on the AudioListener.]
expected: FAIL
[speedOfSound member should not exist on the AudioListener.]
expected: FAIL
[setVelocity member should not exist on the AudioListener.]
expected: FAIL
[setVelocity should not exist on PannerNodes.]
expected: FAIL

View file

@ -5,9 +5,6 @@
[Test driver]
expected: FAIL
[BaseAudioContext interface: attribute listener]
expected: FAIL
[BaseAudioContext interface: attribute audioWorklet]
expected: FAIL
@ -38,9 +35,6 @@
[BaseAudioContext interface: operation createIIRFilter([object Object\], [object Object\])]
expected: FAIL
[BaseAudioContext interface: operation createPanner()]
expected: FAIL
[BaseAudioContext interface: operation createPeriodicWave([object Object\], [object Object\], PeriodicWaveConstraints)]
expected: FAIL
@ -98,9 +92,6 @@
[AudioContext interface: context must inherit property "createMediaStreamDestination()" with the proper type]
expected: FAIL
[BaseAudioContext interface: context must inherit property "listener" with the proper type]
expected: FAIL
[BaseAudioContext interface: context must inherit property "audioWorklet" with the proper type]
expected: FAIL
@ -143,9 +134,6 @@
[BaseAudioContext interface: calling createIIRFilter([object Object\], [object Object\]) on context with too few arguments must throw TypeError]
expected: FAIL
[BaseAudioContext interface: context must inherit property "createPanner()" with the proper type]
expected: FAIL
[BaseAudioContext interface: context must inherit property "createPeriodicWave([object Object\], [object Object\], PeriodicWaveConstraints)" with the proper type]
expected: FAIL
@ -179,9 +167,6 @@
[OfflineAudioContext interface: calling suspend(double) on new OfflineAudioContext(1, 1, sample_rate) with too few arguments must throw TypeError]
expected: FAIL
[BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "listener" with the proper type]
expected: FAIL
[BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "audioWorklet" with the proper type]
expected: FAIL
@ -224,9 +209,6 @@
[BaseAudioContext interface: calling createIIRFilter([object Object\], [object Object\]) on new OfflineAudioContext(1, 1, sample_rate) with too few arguments must throw TypeError]
expected: FAIL
[BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "createPanner()" with the proper type]
expected: FAIL
[BaseAudioContext interface: new OfflineAudioContext(1, 1, sample_rate) must inherit property "createPeriodicWave([object Object\], [object Object\], PeriodicWaveConstraints)" with the proper type]
expected: FAIL
@ -416,90 +398,12 @@
[AudioNode interface: new AnalyserNode(context) must inherit property "channelInterpretation" with the proper type]
expected: FAIL
[AudioListener interface: existence and properties of interface object]
expected: FAIL
[AudioListener interface object length]
expected: FAIL
[AudioListener interface object name]
expected: FAIL
[AudioListener interface: existence and properties of interface prototype object]
expected: FAIL
[AudioListener interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[AudioListener interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[AudioListener interface: attribute positionX]
expected: FAIL
[AudioListener interface: attribute positionY]
expected: FAIL
[AudioListener interface: attribute positionZ]
expected: FAIL
[AudioListener interface: attribute forwardX]
expected: FAIL
[AudioListener interface: attribute forwardY]
expected: FAIL
[AudioListener interface: attribute forwardZ]
expected: FAIL
[AudioListener interface: attribute upX]
expected: FAIL
[AudioListener interface: attribute upY]
expected: FAIL
[AudioListener interface: attribute upZ]
expected: FAIL
[AudioListener interface: operation setPosition(float, float, float)]
expected: FAIL
[AudioListener interface: operation setOrientation(float, float, float, float, float, float)]
expected: FAIL
[AudioListener must be primary interface of context.listener]
expected: FAIL
[Stringification of context.listener]
expected: FAIL
[AudioListener interface: context.listener must inherit property "positionX" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "positionY" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "positionZ" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "forwardX" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "forwardY" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "forwardZ" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "upX" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "upY" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "upZ" with the proper type]
expected: FAIL
[AudioListener interface: context.listener must inherit property "setPosition(float, float, float)" with the proper type]
expected: FAIL
@ -1673,201 +1577,6 @@
[OscillatorNode interface: calling setPeriodicWave(PeriodicWave) on new OscillatorNode(context) with too few arguments must throw TypeError]
expected: FAIL
[PannerNode interface: existence and properties of interface object]
expected: FAIL
[PannerNode interface object length]
expected: FAIL
[PannerNode interface object name]
expected: FAIL
[PannerNode interface: existence and properties of interface prototype object]
expected: FAIL
[PannerNode interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[PannerNode interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[PannerNode interface: attribute panningModel]
expected: FAIL
[PannerNode interface: attribute positionX]
expected: FAIL
[PannerNode interface: attribute positionY]
expected: FAIL
[PannerNode interface: attribute positionZ]
expected: FAIL
[PannerNode interface: attribute orientationX]
expected: FAIL
[PannerNode interface: attribute orientationY]
expected: FAIL
[PannerNode interface: attribute orientationZ]
expected: FAIL
[PannerNode interface: attribute distanceModel]
expected: FAIL
[PannerNode interface: attribute refDistance]
expected: FAIL
[PannerNode interface: attribute maxDistance]
expected: FAIL
[PannerNode interface: attribute rolloffFactor]
expected: FAIL
[PannerNode interface: attribute coneInnerAngle]
expected: FAIL
[PannerNode interface: attribute coneOuterAngle]
expected: FAIL
[PannerNode interface: attribute coneOuterGain]
expected: FAIL
[PannerNode interface: operation setPosition(float, float, float)]
expected: FAIL
[PannerNode interface: operation setOrientation(float, float, float)]
expected: FAIL
[PannerNode must be primary interface of new PannerNode(context)]
expected: FAIL
[Stringification of new PannerNode(context)]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "panningModel" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "positionX" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "positionY" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "positionZ" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "orientationX" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "orientationY" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "orientationZ" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "distanceModel" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "refDistance" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "maxDistance" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "rolloffFactor" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "coneInnerAngle" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "coneOuterAngle" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "coneOuterGain" with the proper type]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "setPosition(float, float, float)" with the proper type]
expected: FAIL
[PannerNode interface: calling setPosition(float, float, float) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[PannerNode interface: new PannerNode(context) must inherit property "setOrientation(float, float, float)" with the proper type]
expected: FAIL
[PannerNode interface: calling setOrientation(float, float, float) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "connect(AudioNode, unsigned long, unsigned long)" with the proper type]
expected: FAIL
[AudioNode interface: calling connect(AudioNode, unsigned long, unsigned long) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "connect(AudioParam, unsigned long)" with the proper type]
expected: FAIL
[AudioNode interface: calling connect(AudioParam, unsigned long) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect()" with the proper type]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect(unsigned long)" with the proper type]
expected: FAIL
[AudioNode interface: calling disconnect(unsigned long) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect(AudioNode)" with the proper type]
expected: FAIL
[AudioNode interface: calling disconnect(AudioNode) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect(AudioNode, unsigned long)" with the proper type]
expected: FAIL
[AudioNode interface: calling disconnect(AudioNode, unsigned long) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect(AudioNode, unsigned long, unsigned long)" with the proper type]
expected: FAIL
[AudioNode interface: calling disconnect(AudioNode, unsigned long, unsigned long) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect(AudioParam)" with the proper type]
expected: FAIL
[AudioNode interface: calling disconnect(AudioParam) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "disconnect(AudioParam, unsigned long)" with the proper type]
expected: FAIL
[AudioNode interface: calling disconnect(AudioParam, unsigned long) on new PannerNode(context) with too few arguments must throw TypeError]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "context" with the proper type]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "numberOfInputs" with the proper type]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "numberOfOutputs" with the proper type]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "channelCount" with the proper type]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "channelCountMode" with the proper type]
expected: FAIL
[AudioNode interface: new PannerNode(context) must inherit property "channelInterpretation" with the proper type]
expected: FAIL
[PeriodicWave interface: existence and properties of interface object]
expected: FAIL

View file

@ -1,2 +1,5 @@
[audiobuffersource-multi-channels.html]
expected: CRASH
expected: TIMEOUT
[X Rendered audio for channel 0 does not equal [0,0.19242584705352783,0.3714718818664551,0.5250332355499268,0.6435103416442871,0.7207010388374329,0.7542802691459656,0.7458723187446594,0.7007185816764832,0.6269197463989258,0.5344454050064087,0.4339446425437927,0.33560463786125183,0.24808235466480255,0.17771567404270172,0.12810270488262177...\] with an element-wise tolerance of {"absoluteThreshold":0.000030517578125,"relativeThreshold":0}.\n\tIndex\tActual\t\t\tExpected\t\tAbsError\t\tRelError\t\tTest threshold\n\t[1\]\t6.2648326158523560e-2\t1.9242584705352783e-1\t1.2977752089500427e-1\t6.7442873648311685e-1\t3.0517578125000000e-5\n\t[2\]\t1.2505052983760834e-1\t3.7147188186645508e-1\t2.4642135202884674e-1\t6.6336474995282613e-1\t3.0517578125000000e-5\n\t[3\]\t1.8696144223213196e-1\t5.2503323554992676e-1\t3.3807179331779480e-1\t6.4390551002679652e-1\t3.0517578125000000e-5\n\t[4\]\t2.4813784658908844e-1\t6.4351034164428711e-1\t3.9537249505519867e-1\t6.1439959775152853e-1\t3.0517578125000000e-5\n\t[5\]\t3.0833941698074341e-1\t7.2070103883743286e-1\t4.1236162185668945e-1\t5.7216737542361873e-1\t3.0517578125000000e-5\n\t...and 44074 more errors.\n\tMax AbsError of 8.6889546364545822e-1 at index of 129.\n\t[129\]\t9.7299009561538696e-1\t1.0409463196992874e-1\t8.6889546364545822e-1\t8.3471687944145678e+0\t3.0517578125000000e-5\n\tMax RelError of 1.2424206265621037e+5 at index of 1363.\n\t[1363\]\t-5.8316510915756226e-1\t4.6938193918322213e-6\t5.8316980297695409e-1\t1.2424206265621037e+5\t3.0517578125000000e-5\n]
expected: FAIL

View file

@ -1,5 +1,4 @@
[ctor-panner.html]
expected: ERROR
[X context = new OfflineAudioContext(...) incorrectly threw ReferenceError: "OfflineAudioContext is not defined".]
expected: FAIL
@ -9,3 +8,15 @@
[X node0 = new PannerNode(context) incorrectly threw TypeError: "window[name\] is not a constructor".]
expected: FAIL
[< [test AudioNodeOptions\] 2 out of 18 assertions were failed.]
expected: FAIL
[X new PannerNode(c, {"channelCount":0}) did not throw an exception.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 5 tasks were failed.]
expected: FAIL
[X node6.channelInterpretation is not equal to discrete. Got speakers.]
expected: FAIL

View file

@ -1,2 +1,10 @@
[distance-exponential.html]
expected: ERROR
[X Number of impulses is not equal to 100. Got 0.]
expected: FAIL
[< [test\] 1 out of 2 assertions were failed.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL

View file

@ -1,2 +1,10 @@
[distance-inverse.html]
expected: ERROR
[X Number of impulses is not equal to 100. Got 0.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL
[< [test\] 1 out of 2 assertions were failed.]
expected: FAIL

View file

@ -1,2 +1,10 @@
[distance-linear.html]
expected: ERROR
[X Number of impulses is not equal to 100. Got 0.]
expected: FAIL
[< [test\] 1 out of 2 assertions were failed.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL

View file

@ -1,2 +1,10 @@
[panner-automation-equalpower-stereo.html]
expected: ERROR
[X Number of impulses found is not equal to 100. Got 0.]
expected: FAIL
[< [test\] 1 out of 4 assertions were failed.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL

View file

@ -11,3 +11,28 @@
[X new PannerNode(c, {refDistance: -1}) threw "ReferenceError" instead of EcmaScript error RangeError.]
expected: FAIL
[X panner.maxDistance = 0 did not throw an exception.]
expected: FAIL
[X panner.maxDistance = -1 threw "NotSupportedError" instead of EcmaScript error RangeError.]
expected: FAIL
[< [max-distance-error\] 4 out of 6 assertions were failed.]
expected: FAIL
[X new PannerNode(c, {maxDistance: 0}) did not throw an exception.]
expected: FAIL
[X panner.refDistance = -1 did not throw an exception.]
expected: FAIL
[X new PannerNode(c, {refDistance: -1}) did not throw an exception.]
expected: FAIL
[< [ref-distance-error\] 2 out of 6 assertions were failed.]
expected: FAIL
[X new PannerNode(c, {maxDistance: -1}) did not throw an exception.]
expected: FAIL

View file

@ -1,2 +1,10 @@
[panner-equalpower-stereo.html]
expected: ERROR
[X Number of impulses found is not equal to 100. Got 0.]
expected: FAIL
[< [test\] 1 out of 4 assertions were failed.]
expected: FAIL
[# AUDIT TASK RUNNER FINISHED: 1 out of 1 tasks were failed.]
expected: FAIL

View file

@ -1,2 +1,8 @@
[panner-equalpower.html]
expected: ERROR
expected: TIMEOUT
[X Number of impulses found is not equal to 100. Got 0.]
expected: FAIL
[< [test\] 1 out of 4 assertions were failed.]
expected: FAIL

View file

@ -1,5 +1,4 @@
[pannernode-basic.html]
expected: ERROR
[X Initialize context and panner incorrectly threw TypeError: "context.createPanner is not a function".]
expected: FAIL

View file

@ -65286,7 +65286,7 @@
"testharness"
],
"mozilla/interfaces.html": [
"ad419477302c2f55fd0b0f7b90d4b36ee9700988",
"179f9c6c6928b3a4194c82f85cd1cce81123a5bc",
"testharness"
],
"mozilla/interfaces.js": [

View file

@ -16,6 +16,7 @@ test_interfaces([
"AudioBufferSourceNode",
"AudioContext",
"AudioDestinationNode",
"AudioListener",
"AudioNode",
"AudioParam",
"AudioScheduledSourceNode",
@ -173,6 +174,7 @@ test_interfaces([
"OfflineAudioContext",
"OscillatorNode",
"PageTransitionEvent",
"PannerNode",
"Performance",
"PerformanceEntry",
"PerformanceMark",