| <!DOCTYPE html> |
| <html> |
| <head> |
| <title> |
| Test Constructor: Panner |
| </title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/webaudio/resources/audit-util.js"></script> |
| <script src="/webaudio/resources/audit.js"></script> |
| <script src="/webaudio/resources/audionodeoptions.js"></script> |
| </head> |
| <body> |
| <script id="layout-test-code"> |
| let context; |
| |
| let audit = Audit.createTaskRunner(); |
| |
| audit.define('initialize', (task, should) => { |
| context = initializeContext(should); |
| task.done(); |
| }); |
| |
| audit.define('invalid constructor', (task, should) => { |
| testInvalidConstructor(should, 'PannerNode', context); |
| task.done(); |
| }); |
| |
| audit.define('default constructor', (task, should) => { |
| let prefix = 'node0'; |
| let node = testDefaultConstructor(should, 'PannerNode', context, { |
| prefix: prefix, |
| numberOfInputs: 1, |
| numberOfOutputs: 1, |
| channelCount: 2, |
| channelCountMode: 'clamped-max', |
| channelInterpretation: 'speakers' |
| }); |
| |
| testDefaultAttributes(should, node, prefix, [ |
| {name: 'panningModel', value: 'equalpower'}, |
| {name: 'positionX', value: 0}, {name: 'positionY', value: 0}, |
| {name: 'positionZ', value: 0}, {name: 'orientationX', value: 1}, |
| {name: 'orientationY', value: 0}, {name: 'orientationZ', value: 0}, |
| {name: 'distanceModel', value: 'inverse'}, |
| {name: 'refDistance', value: 1}, {name: 'maxDistance', value: 10000}, |
| {name: 'rolloffFactor', value: 1}, |
| {name: 'coneInnerAngle', value: 360}, |
| {name: 'coneOuterAngle', value: 360}, |
| {name: 'coneOuterGain', value: 0} |
| ]); |
| |
| // Test the listener too, while we're at it. |
| let listenerAttributes = [ |
| {name: 'positionX', value: 0}, |
| {name: 'positionY', value: 0}, |
| {name: 'positionZ', value: 0}, |
| {name: 'forwardX', value: 0}, |
| {name: 'forwardY', value: 0}, |
| {name: 'forwardZ', value: -1}, |
| {name: 'upX', value: 0}, |
| {name: 'upY', value: 1}, |
| {name: 'upZ', value: 0}, |
| ]; |
| |
| listenerAttributes.forEach((item) => { |
| should( |
| context.listener[item.name].value, |
| 'context.listener.' + item.name + '.value') |
| .beEqualTo(item.value); |
| }); |
| |
| task.done(); |
| }); |
| |
| audit.define('test AudioNodeOptions', (task, should) => { |
| // Can't use testAudioNodeOptions because the constraints for this node |
| // are not supported there. |
| let node; |
| let success = true; |
| |
| // Test that we can set the channel count to 1 or 2. |
| let options = {channelCount: 1}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node1 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.channelCount, 'node1.channelCount') |
| .beEqualTo(options.channelCount); |
| |
| options = {channelCount: 2}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node2 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.channelCount, 'node2.channelCount') |
| .beEqualTo(options.channelCount); |
| |
| // Test that other channel counts throw an error |
| options = {channelCount: 0}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(DOMException, 'NotSupportedError'); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.channelCount = options.channelCount; |
| }, |
| `node.channelCount = ${options.channelCount}`) |
| .throw(DOMException, "NotSupportedError"); |
| should(node.channelCount, |
| `node.channelCount after setting to ${options.channelCount}`) |
| .beEqualTo(2); |
| |
| options = {channelCount: 3}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(DOMException, 'NotSupportedError'); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.channelCount = options.channelCount; |
| }, |
| `node.channelCount = ${options.channelCount}`) |
| .throw(DOMException, "NotSupportedError"); |
| should(node.channelCount, |
| `node.channelCount after setting to ${options.channelCount}`) |
| .beEqualTo(2); |
| |
| options = {channelCount: 99}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(DOMException, 'NotSupportedError'); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.channelCount = options.channelCount; |
| }, |
| `node.channelCount = ${options.channelCount}`) |
| .throw(DOMException, "NotSupportedError"); |
| should(node.channelCount, |
| `node.channelCount after setting to ${options.channelCount}`) |
| .beEqualTo(2); |
| |
| // Test channelCountMode. A mode of "max" is illegal, but others are |
| // ok. |
| options = {channelCountMode: 'clamped-max'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node3 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.channelCountMode, 'node3.channelCountMode') |
| .beEqualTo(options.channelCountMode); |
| |
| options = {channelCountMode: 'explicit'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node4 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.channelCountMode, 'node4.channelCountMode') |
| .beEqualTo(options.channelCountMode); |
| |
| options = {channelCountMode: 'max'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(DOMException, 'NotSupportedError'); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.channelCountMode = options.channelCountMode; |
| }, |
| `node.channelCountMode = ${options.channelCountMode}`) |
| .throw(DOMException, "NotSupportedError"); |
| should(node.channelCountMode, |
| `node.channelCountMode after setting to ${options.channelCountMode}`) |
| .beEqualTo("clamped-max"); |
| |
| options = {channelCountMode: 'foobar'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, " + JSON.stringify(options) + ")') |
| .throw(TypeError); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.channelCountMode = options.channelCountMode; |
| }, |
| `node.channelCountMode = ${options.channelCountMode}`) |
| .notThrow(); // Invalid assignment to enum-valued attrs does not throw. |
| should(node.channelCountMode, |
| `node.channelCountMode after setting to ${options.channelCountMode}`) |
| .beEqualTo("clamped-max"); |
| |
| // Test channelInterpretation. |
| options = {channelInterpretation: 'speakers'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node5 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.channelInterpretation, 'node5.channelInterpretation') |
| .beEqualTo(options.channelInterpretation); |
| |
| options = {channelInterpretation: 'discrete'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node6 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.channelInterpretation, 'node6.channelInterpretation') |
| .beEqualTo(options.channelInterpretation); |
| |
| options = {channelInterpretation: 'foobar'}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(TypeError); |
| |
| // Test maxDistance |
| options = {maxDistance: -1}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(RangeError); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.maxDistance = options.maxDistance; |
| }, |
| `node.maxDistance = ${options.maxDistance}`) |
| .throw(RangeError); |
| should(node.maxDistance, |
| `node.maxDistance after setting to ${options.maxDistance}`) |
| .beEqualTo(10000); |
| |
| options = {maxDistance: 100}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node7 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.maxDistance, 'node7.maxDistance') |
| .beEqualTo(options.maxDistance); |
| |
| // Test rolloffFactor |
| options = {rolloffFactor: -1}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(RangeError); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.rolloffFactor = options.rolloffFactor; |
| }, |
| `node.rolloffFactor = ${options.rolloffFactor}`) |
| .throw(RangeError); |
| should(node.rolloffFactor, |
| `node.rolloffFactor after setting to ${options.rolloffFactor}`) |
| .beEqualTo(1); |
| |
| options = {rolloffFactor: 0}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node8 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.rolloffFactor, 'node8.rolloffFactor') |
| .beEqualTo(options.rolloffFactor); |
| |
| options = {rolloffFactor: 0.5}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node8 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.rolloffFactor, 'node8.rolloffFactor') |
| .beEqualTo(options.rolloffFactor); |
| |
| options = {rolloffFactor: 100}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node8 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.rolloffFactor, 'node8.rolloffFactor') |
| .beEqualTo(options.rolloffFactor); |
| |
| // Test coneOuterGain |
| options = {coneOuterGain: -1}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(DOMException, 'InvalidStateError'); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.coneOuterGain = options.coneOuterGain; |
| }, |
| `node.coneOuterGain = ${options.coneOuterGain}`) |
| .throw(DOMException, 'InvalidStateError'); |
| should(node.coneOuterGain, |
| `node.coneOuterGain after setting to ${options.coneOuterGain}`) |
| .beEqualTo(0); |
| |
| options = {coneOuterGain: 1.1}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .throw(DOMException, 'InvalidStateError'); |
| should( |
| () => { |
| node = new PannerNode(context); |
| node.coneOuterGain = options.coneOuterGain; |
| }, |
| `node.coneOuterGain = ${options.coneOuterGain}`) |
| .throw(DOMException, 'InvalidStateError'); |
| should(node.coneOuterGain, |
| `node.coneOuterGain after setting to ${options.coneOuterGain}`) |
| .beEqualTo(0); |
| |
| options = {coneOuterGain: 0.0}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node9 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.coneOuterGain, 'node9.coneOuterGain') |
| .beEqualTo(options.coneOuterGain); |
| options = {coneOuterGain: 0.5}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node9 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.coneOuterGain, 'node9.coneOuterGain') |
| .beEqualTo(options.coneOuterGain); |
| |
| options = {coneOuterGain: 1.0}; |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node9 = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node.coneOuterGain, 'node9.coneOuterGain') |
| .beEqualTo(options.coneOuterGain); |
| |
| task.done(); |
| }); |
| |
| audit.define('constructor with options', (task, should) => { |
| let node; |
| let success = true; |
| let options = { |
| panningModel: 'HRTF', |
| // We use full double float values here to verify also that the actual |
| // AudioParam value is properly rounded to a float. The actual value |
| // is immaterial as long as x != Math.fround(x). |
| positionX: Math.SQRT2, |
| positionY: 2 * Math.SQRT2, |
| positionZ: 3 * Math.SQRT2, |
| orientationX: -Math.SQRT2, |
| orientationY: -2 * Math.SQRT2, |
| orientationZ: -3 * Math.SQRT2, |
| distanceModel: 'linear', |
| // We use full double float values here to verify also that the actual |
| // attribute is a double float. The actual value is immaterial as |
| // long as x != Math.fround(x). |
| refDistance: Math.PI, |
| maxDistance: 2 * Math.PI, |
| rolloffFactor: 3 * Math.PI, |
| coneInnerAngle: 4 * Math.PI, |
| coneOuterAngle: 5 * Math.PI, |
| coneOuterGain: 0.1 * Math.PI |
| }; |
| |
| should( |
| () => { |
| node = new PannerNode(context, options); |
| }, |
| 'node = new PannerNode(c, ' + JSON.stringify(options) + ')') |
| .notThrow(); |
| should(node instanceof PannerNode, 'node instanceof PannerNode') |
| .beEqualTo(true); |
| |
| should(node.panningModel, 'node.panningModel') |
| .beEqualTo(options.panningModel); |
| should(node.positionX.value, 'node.positionX.value') |
| .beEqualTo(Math.fround(options.positionX)); |
| should(node.positionY.value, 'node.positionY.value') |
| .beEqualTo(Math.fround(options.positionY)); |
| should(node.positionZ.value, 'node.positionZ.value') |
| .beEqualTo(Math.fround(options.positionZ)); |
| should(node.orientationX.value, 'node.orientationX.value') |
| .beEqualTo(Math.fround(options.orientationX)); |
| should(node.orientationY.value, 'node.orientationY.value') |
| .beEqualTo(Math.fround(options.orientationY)); |
| should(node.orientationZ.value, 'node.orientationZ.value') |
| .beEqualTo(Math.fround(options.orientationZ)); |
| should(node.distanceModel, 'node.distanceModel') |
| .beEqualTo(options.distanceModel); |
| should(node.refDistance, 'node.refDistance') |
| .beEqualTo(options.refDistance); |
| should(node.maxDistance, 'node.maxDistance') |
| .beEqualTo(options.maxDistance); |
| should(node.rolloffFactor, 'node.rolloffFactor') |
| .beEqualTo(options.rolloffFactor); |
| should(node.coneInnerAngle, 'node.coneInnerAngle') |
| .beEqualTo(options.coneInnerAngle); |
| should(node.coneOuterAngle, 'node.coneOuterAngle') |
| .beEqualTo(options.coneOuterAngle); |
| should(node.coneOuterGain, 'node.coneOuterGain') |
| .beEqualTo(options.coneOuterGain); |
| |
| should(node.channelCount, 'node.channelCount').beEqualTo(2); |
| should(node.channelCountMode, 'node.channelCountMode') |
| .beEqualTo('clamped-max'); |
| should(node.channelInterpretation, 'node.channelInterpretation') |
| .beEqualTo('speakers'); |
| |
| task.done(); |
| }); |
| |
| audit.run(); |
| </script> |
| </body> |
| </html> |