Commit f22f8191 authored by Raymond Toy's avatar Raymond Toy Committed by Commit Bot

Throw errors for invalid rolloffFactor and coneOuterGain

The WebAudio spec says we must throw errors for a negative
rolloffFactor and for a coneOuterGain outside the interval [0,
1]. Make it so.

Also add some additional tests to ctor-panner.html to verify that a
rolloffFactor of 0 or 100 do not throw errors and that a
coneOuterGain of 0 or 1 do not throw errors.

Remove invalid tests from panner-rolloff-clamping.html because
negative rolloffFactor now throws an error.

Finally remove text expectation for ctor-panner.html test, which
passes now.

Bug: 879845
Test: the-pannernode-interface/ctor-panner.html, the-pannernode-interface/panner-rolloff-clamping.html
Change-Id: Ie90e9fe13e82fd3cc955060dc9e77266ef4ff591
Reviewed-on: https://chromium-review.googlesource.com/1205099
Commit-Queue: Raymond Toy <rtoy@chromium.org>
Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589045}
parent dab6b733
This is a testharness.js-based test.
Found 93 tests; 88 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS # AUDIT TASK RUNNER STARTED.
PASS > [initialize]
PASS context = new OfflineAudioContext(...) did not throw an exception.
PASS < [initialize] All assertions passed. (total 1 assertions)
PASS > [invalid constructor]
PASS new PannerNode() threw TypeError: "Failed to construct 'PannerNode': 1 argument required, but only 0 present.".
PASS new PannerNode(1) threw TypeError: "Failed to construct 'PannerNode': parameter 1 is not of type 'BaseAudioContext'.".
PASS new PannerNode(context, 42) threw TypeError: "Failed to construct 'PannerNode': parameter 2 ('options') is not an object.".
PASS < [invalid constructor] All assertions passed. (total 3 assertions)
PASS > [default constructor]
PASS node0 = new PannerNode(context) did not throw an exception.
PASS node0 instanceof PannerNode is equal to true.
PASS node0.numberOfInputs is equal to 1.
PASS node0.numberOfOutputs is equal to 1.
PASS node0.channelCount is equal to 2.
PASS node0.channelCountMode is equal to clamped-max.
PASS node0.channelInterpretation is equal to speakers.
PASS node0.panningModel is equal to equalpower.
PASS node0.positionX.value is equal to 0.
PASS node0.positionY.value is equal to 0.
PASS node0.positionZ.value is equal to 0.
PASS node0.orientationX.value is equal to 1.
PASS node0.orientationY.value is equal to 0.
PASS node0.orientationZ.value is equal to 0.
PASS node0.distanceModel is equal to inverse.
PASS node0.refDistance is equal to 1.
PASS node0.maxDistance is equal to 10000.
PASS node0.rolloffFactor is equal to 1.
PASS node0.coneInnerAngle is equal to 360.
PASS node0.coneOuterAngle is equal to 360.
PASS node0.coneOuterGain is equal to 0.
PASS context.listener.positionX.value is equal to 0.
PASS context.listener.positionY.value is equal to 0.
PASS context.listener.positionZ.value is equal to 0.
PASS context.listener.forwardX.value is equal to 0.
PASS context.listener.forwardY.value is equal to 0.
PASS context.listener.forwardZ.value is equal to -1.
PASS context.listener.upX.value is equal to 0.
PASS context.listener.upY.value is equal to 1.
PASS context.listener.upZ.value is equal to 0.
PASS < [default constructor] All assertions passed. (total 30 assertions)
PASS > [test AudioNodeOptions]
PASS node1 = new PannerNode(c, {"channelCount":1}) did not throw an exception.
PASS node1.channelCount is equal to 1.
PASS node2 = new PannerNode(c, {"channelCount":2}) did not throw an exception.
PASS node2.channelCount is equal to 2.
PASS new PannerNode(c, {"channelCount":0}) threw NotSupportedError: "Failed to construct 'PannerNode': The channelCount provided (0) is outside the range [1, 2].".
PASS new PannerNode(c, {"channelCount":3}) threw NotSupportedError: "Failed to construct 'PannerNode': The channelCount provided (3) is outside the range [1, 2].".
PASS new PannerNode(c, {"channelCount":99}) threw NotSupportedError: "Failed to construct 'PannerNode': The channelCount provided (99) is outside the range [1, 2].".
PASS node3 = new PannerNode(c, {"channelCountMode":"clamped-max"}) did not throw an exception.
PASS node3.channelCountMode is equal to clamped-max.
PASS node4 = new PannerNode(c, {"channelCountMode":"explicit"}) did not throw an exception.
PASS node4.channelCountMode is equal to explicit.
PASS new PannerNode(c, {"channelCountMode":"max"}) threw NotSupportedError: "Failed to construct 'PannerNode': Panner: 'max' is not allowed".
PASS new PannerNode(c, " + JSON.stringify(options) + ") threw TypeError: "Failed to construct 'PannerNode': The provided value 'foobar' is not a valid enum value of type ChannelCountMode.".
PASS node5 = new PannerNode(c, {"channelInterpretation":"speakers"}) did not throw an exception.
PASS node5.channelInterpretation is equal to speakers.
PASS node6 = new PannerNode(c, {"channelInterpretation":"discrete"}) did not throw an exception.
PASS node6.channelInterpretation is equal to discrete.
PASS new PannerNode(c, {"channelInterpretation":"foobar"}) threw TypeError: "Failed to construct 'PannerNode': The provided value 'foobar' is not a valid enum value of type ChannelInterpretation.".
PASS new PannerNode(c, {"maxDistance":-1}) threw RangeError: "Failed to construct 'PannerNode': The maxDistance provided (-1) is less than the minimum bound (0).".
PASS node7 = new PannerNode(c, {"maxDistance":100}) did not throw an exception.
PASS node7.maxDistance is equal to 100.
FAIL X new PannerNode(c, {"rolloffFactor":-1}) did not throw an exception. assert_true: expected true got false
PASS node8 = new PannerNode(c, {"rolloffFactor":0.5}) did not throw an exception.
PASS node8.rolloffFactor is equal to 0.5.
FAIL X new PannerNode(c, {"coneOuterGain":-1}) did not throw an exception. assert_true: expected true got false
FAIL X new PannerNode(c, {"coneOuterGain":1.1}) did not throw an exception. assert_true: expected true got false
PASS node9 = new PannerNode(c, {"coneOuterGain":0.5}) did not throw an exception.
PASS node9.coneOuterGain is equal to 0.5.
FAIL < [test AudioNodeOptions] 3 out of 28 assertions were failed. assert_true: expected true got false
PASS > [constructor with options]
PASS node = new PannerNode(c, {"panningModel":"HRTF","positionX":1.4142135623730951,"positionY":2.8284271247461903,"positionZ":4.242640687119286,"orientationX":-1.4142135623730951,"orientationY":-2.8284271247461903,"orientationZ":-4.242640687119286,"distanceModel":"linear","refDistance":3.141592653589793,"maxDistance":6.283185307179586,"rolloffFactor":9.42477796076938,"coneInnerAngle":12.566370614359172,"coneOuterAngle":15.707963267948966,"coneOuterGain":0.3141592653589793}) did not throw an exception.
PASS node instanceof PannerNode is equal to true.
PASS node.panningModel is equal to HRTF.
PASS node.positionX.value is equal to 1.4142135381698608.
PASS node.positionY.value is equal to 2.8284270763397217.
PASS node.positionZ.value is equal to 4.242640495300293.
PASS node.orientationX.value is equal to -1.4142135381698608.
PASS node.orientationY.value is equal to -2.8284270763397217.
PASS node.orientationZ.value is equal to -4.242640495300293.
PASS node.distanceModel is equal to linear.
PASS node.refDistance is equal to 3.141592653589793.
PASS node.maxDistance is equal to 6.283185307179586.
PASS node.rolloffFactor is equal to 9.42477796076938.
PASS node.coneInnerAngle is equal to 12.566370614359172.
PASS node.coneOuterAngle is equal to 15.707963267948966.
PASS node.coneOuterGain is equal to 0.3141592653589793.
PASS node.channelCount is equal to 2.
PASS node.channelCountMode is equal to clamped-max.
PASS node.channelInterpretation is equal to speakers.
PASS < [constructor with options] All assertions passed. (total 19 assertions)
FAIL # AUDIT TASK RUNNER FINISHED: 1 out of 5 tasks were failed. assert_true: expected true got false
Harness: the test ran to completion.
...@@ -218,6 +218,16 @@ ...@@ -218,6 +218,16 @@
}, },
'new PannerNode(c, ' + JSON.stringify(options) + ')') 'new PannerNode(c, ' + JSON.stringify(options) + ')')
.throw(RangeError); .throw(RangeError);
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}; options = {rolloffFactor: 0.5};
should( should(
() => { () => {
...@@ -228,6 +238,16 @@ ...@@ -228,6 +238,16 @@
should(node.rolloffFactor, 'node8.rolloffFactor') should(node.rolloffFactor, 'node8.rolloffFactor')
.beEqualTo(options.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 // Test coneOuterGain
options = {coneOuterGain: -1}; options = {coneOuterGain: -1};
should( should(
...@@ -235,14 +255,23 @@ ...@@ -235,14 +255,23 @@
node = new PannerNode(context, options); node = new PannerNode(context, options);
}, },
'new PannerNode(c, ' + JSON.stringify(options) + ')') 'new PannerNode(c, ' + JSON.stringify(options) + ')')
.throw('InvalidStateError'); .throw(DOMException, 'InvalidStateError');
options = {coneOuterGain: 1.1}; options = {coneOuterGain: 1.1};
should( should(
() => { () => {
node = new PannerNode(context, options); node = new PannerNode(context, options);
}, },
'new PannerNode(c, ' + JSON.stringify(options) + ')') 'new PannerNode(c, ' + JSON.stringify(options) + ')')
.throw('InvalidStateError'); .throw(DOMException, 'InvalidStateError');
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}; options = {coneOuterGain: 0.5};
should( should(
() => { () => {
...@@ -253,6 +282,16 @@ ...@@ -253,6 +282,16 @@
should(node.coneOuterGain, 'node9.coneOuterGain') should(node.coneOuterGain, 'node9.coneOuterGain')
.beEqualTo(options.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(); task.done();
}); });
......
...@@ -17,41 +17,19 @@ ...@@ -17,41 +17,19 @@
let audit = Audit.createTaskRunner(); let audit = Audit.createTaskRunner();
audit.define('linear-clamp-low', (task, should) => { audit.define(
runTest(should, { {
distanceModel: 'linear', label: 'linear-clamp-high',
// Fairly arbitrary value outside the nominal range description: 'rolloffFactor clamping for linear distance model'
rolloffFactor: -1, },
clampedRolloff: 0 (task, should) => {
}).then(() => task.done()); runTest(should, {
}); distanceModel: 'linear',
// Fairly arbitrary value outside the nominal range
audit.define('linear-clamp-high', (task, should) => { rolloffFactor: 2,
runTest(should, { clampedRolloff: 1
distanceModel: 'linear', }).then(() => task.done());
// Fairly arbitrary value outside the nominal range });
rolloffFactor: 2,
clampedRolloff: 1
}).then(() => task.done());
});
audit.define('inverse-clamp', (task, should) => {
runTest(should, {
distanceModel: 'inverse',
// Fairly arbitrary value outside the nominal range
rolloffFactor: -1,
clampedRolloff: 0
}).then(() => task.done());
});
audit.define('exponential-clamp', (task, should) => {
runTest(should, {
distanceModel: 'exponential',
// Fairly arbitrary value outside the nominal range
rolloffFactor: -2,
clampedRolloff: 0
}).then(() => task.done());
});
// Test clamping of the rolloffFactor. The test is done by comparing the // Test clamping of the rolloffFactor. The test is done by comparing the
// output of a panner with the rolloffFactor set outside the nominal range // output of a panner with the rolloffFactor set outside the nominal range
......
...@@ -740,10 +740,10 @@ PannerNode* PannerNode::Create(BaseAudioContext* context, ...@@ -740,10 +740,10 @@ PannerNode* PannerNode::Create(BaseAudioContext* context,
node->setRefDistance(options.refDistance(), exception_state); node->setRefDistance(options.refDistance(), exception_state);
node->setMaxDistance(options.maxDistance(), exception_state); node->setMaxDistance(options.maxDistance(), exception_state);
node->setRolloffFactor(options.rolloffFactor()); node->setRolloffFactor(options.rolloffFactor(), exception_state);
node->setConeInnerAngle(options.coneInnerAngle()); node->setConeInnerAngle(options.coneInnerAngle());
node->setConeOuterAngle(options.coneOuterAngle()); node->setConeOuterAngle(options.coneOuterAngle());
node->setConeOuterGain(options.coneOuterGain()); node->setConeOuterGain(options.coneOuterGain(), exception_state);
return node; return node;
} }
...@@ -818,7 +818,15 @@ double PannerNode::rolloffFactor() const { ...@@ -818,7 +818,15 @@ double PannerNode::rolloffFactor() const {
return GetPannerHandler().RolloffFactor(); return GetPannerHandler().RolloffFactor();
} }
void PannerNode::setRolloffFactor(double factor) { void PannerNode::setRolloffFactor(double factor,
ExceptionState& exception_state) {
if (factor < 0) {
exception_state.ThrowRangeError(
ExceptionMessages::IndexExceedsMinimumBound<double>("rolloffFactor",
factor, 0));
return;
}
GetPannerHandler().SetRolloffFactor(factor); GetPannerHandler().SetRolloffFactor(factor);
} }
...@@ -842,7 +850,17 @@ double PannerNode::coneOuterGain() const { ...@@ -842,7 +850,17 @@ double PannerNode::coneOuterGain() const {
return GetPannerHandler().ConeOuterGain(); return GetPannerHandler().ConeOuterGain();
} }
void PannerNode::setConeOuterGain(double gain) { void PannerNode::setConeOuterGain(double gain,
ExceptionState& exception_state) {
if (gain < 0 || gain > 1) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
ExceptionMessages::IndexOutsideRange<double>(
"coneOuterGain", gain, 0, ExceptionMessages::kInclusiveBound, 1,
ExceptionMessages::kInclusiveBound));
return;
}
GetPannerHandler().SetConeOuterGain(gain); GetPannerHandler().SetConeOuterGain(gain);
} }
......
...@@ -236,13 +236,13 @@ class PannerNode final : public AudioNode { ...@@ -236,13 +236,13 @@ class PannerNode final : public AudioNode {
double maxDistance() const; double maxDistance() const;
void setMaxDistance(double, ExceptionState&); void setMaxDistance(double, ExceptionState&);
double rolloffFactor() const; double rolloffFactor() const;
void setRolloffFactor(double); void setRolloffFactor(double, ExceptionState&);
double coneInnerAngle() const; double coneInnerAngle() const;
void setConeInnerAngle(double); void setConeInnerAngle(double);
double coneOuterAngle() const; double coneOuterAngle() const;
void setConeOuterAngle(double); void setConeOuterAngle(double);
double coneOuterGain() const; double coneOuterGain() const;
void setConeOuterGain(double); void setConeOuterGain(double, ExceptionState&);
private: private:
PannerNode(BaseAudioContext&); PannerNode(BaseAudioContext&);
......
...@@ -61,10 +61,10 @@ enum DistanceModelType { ...@@ -61,10 +61,10 @@ enum DistanceModelType {
[RaisesException=Setter] attribute double refDistance; [RaisesException=Setter] attribute double refDistance;
[RaisesException=Setter] attribute double maxDistance; [RaisesException=Setter] attribute double maxDistance;
attribute double rolloffFactor; [RaisesException=Setter] attribute double rolloffFactor;
// Directional sound cone // Directional sound cone
attribute double coneInnerAngle; attribute double coneInnerAngle;
attribute double coneOuterAngle; attribute double coneOuterAngle;
attribute double coneOuterGain; [RaisesException=Setter] attribute double coneOuterGain;
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment