Skip to content

Commit ee6ae0b

Browse files
Ensured that audio nodes threw typed exceptions.
1 parent dc43542 commit ee6ae0b

16 files changed

+117
-38
lines changed

src/KristofferStrube.Blazor.WebAudio/AudioNodes/ChannelMergerNode.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public class ChannelMergerNode : AudioNode, IJSCreatable<ChannelMergerNode>
4444
/// <returns>A new instance of a <see cref="ChannelMergerNode"/>.</returns>
4545
public static async Task<ChannelMergerNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, ChannelMergerOptions? options = null)
4646
{
47-
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
48-
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructChannelMergerNode", context, options);
47+
await using ErrorHandlingJSObjectReference errorHandlingHelper = await jSRuntime.GetErrorHandlingHelperAsync();
48+
IJSObjectReference jSInstance = await errorHandlingHelper.InvokeAsync<IJSObjectReference>("constructChannelMergerNode", context, options);
4949
return new ChannelMergerNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
5050
}
5151

src/KristofferStrube.Blazor.WebAudio/AudioNodes/ChannelSplitterNode.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ public class ChannelSplitterNode : AudioNode, IJSCreatable<ChannelSplitterNode>
4343
/// <returns>A new instance of a <see cref="ChannelSplitterNode"/>.</returns>
4444
public static async Task<ChannelSplitterNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, ChannelSplitterOptions? options = null)
4545
{
46-
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
47-
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructChannelSplitterNode", context, options);
46+
await using ErrorHandlingJSObjectReference errorHandlingHelper = await jSRuntime.GetErrorHandlingHelperAsync();
47+
IJSObjectReference jSInstance = await errorHandlingHelper.InvokeAsync<IJSObjectReference>("constructChannelSplitterNode", context, options);
4848
return new ChannelSplitterNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
4949
}
5050

src/KristofferStrube.Blazor.WebAudio/AudioNodes/ConvolverNode.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public class ConvolverNode : AudioNode, IJSCreatable<ConvolverNode>
3737
/// <returns>A new instance of a <see cref="ConvolverNode"/>.</returns>
3838
public static async Task<ConvolverNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, ConvolverOptions? options = null)
3939
{
40-
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
41-
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructConvolverNode", context, options);
40+
await using ErrorHandlingJSObjectReference errorHandlingHelper = await jSRuntime.GetErrorHandlingHelperAsync();
41+
IJSObjectReference jSInstance = await errorHandlingHelper.InvokeAsync<IJSObjectReference>("constructConvolverNode", context, options);
4242
return new ConvolverNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
4343
}
4444

src/KristofferStrube.Blazor.WebAudio/AudioNodes/DynamicsCompressorNode.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public class DynamicsCompressorNode : AudioNode, IJSCreatable<DynamicsCompressor
3636
/// <returns>A new instance of an <see cref="DynamicsCompressorNode"/>.</returns>
3737
public static async Task<DynamicsCompressorNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, DynamicsCompressorOptions? options = null)
3838
{
39-
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
40-
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructDynamicsCompressorNode", context, options);
39+
await using ErrorHandlingJSObjectReference errorHandlingHelper = await jSRuntime.GetErrorHandlingHelperAsync();
40+
IJSObjectReference jSInstance = await errorHandlingHelper.InvokeAsync<IJSObjectReference>("constructDynamicsCompressorNode", context, options);
4141
return new DynamicsCompressorNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
4242
}
4343

src/KristofferStrube.Blazor.WebAudio/AudioNodes/PannerNode.cs

+14-14
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,6 @@ namespace KristofferStrube.Blazor.WebAudio;
1313
[IJSWrapperConverter]
1414
public class PannerNode : AudioNode, IJSCreatable<PannerNode>
1515
{
16-
/// <summary>
17-
/// Creates an <see cref="PannerNode"/> using the standard constructor.
18-
/// </summary>
19-
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
20-
/// <param name="context">The <see cref="BaseAudioContext"/> this new <see cref="PannerNode"/> will be associated with.</param>
21-
/// <param name="options">Optional initial parameter value for this <see cref="PannerNode"/>.</param>
22-
/// <returns>A new instance of an <see cref="PannerNode"/>.</returns>
23-
public static async Task<PannerNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, PannerOptions? options = null)
24-
{
25-
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
26-
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructPannerNode", context, options);
27-
return new PannerNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
28-
}
29-
3016
/// <inheritdoc/>
3117
public static new async Task<PannerNode> CreateAsync(IJSRuntime jSRuntime, IJSObjectReference jSReference)
3218
{
@@ -39,6 +25,20 @@ public static async Task<PannerNode> CreateAsync(IJSRuntime jSRuntime, BaseAudio
3925
return Task.FromResult(new PannerNode(jSRuntime, jSReference, options));
4026
}
4127

28+
/// <summary>
29+
/// Creates an <see cref="PannerNode"/> using the standard constructor.
30+
/// </summary>
31+
/// <param name="jSRuntime">An <see cref="IJSRuntime"/> instance.</param>
32+
/// <param name="context">The <see cref="BaseAudioContext"/> this new <see cref="PannerNode"/> will be associated with.</param>
33+
/// <param name="options">Optional initial parameter value for this <see cref="PannerNode"/>.</param>
34+
/// <returns>A new instance of an <see cref="PannerNode"/>.</returns>
35+
public static async Task<PannerNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, PannerOptions? options = null)
36+
{
37+
await using ErrorHandlingJSObjectReference errorHandlingHelper = await jSRuntime.GetErrorHandlingHelperAsync();
38+
IJSObjectReference jSInstance = await errorHandlingHelper.InvokeAsync<IJSObjectReference>("constructPannerNode", context, options);
39+
return new PannerNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
40+
}
41+
4242
/// <inheritdoc cref="CreateAsync(IJSRuntime, IJSObjectReference, CreationOptions)"/>
4343
protected PannerNode(IJSRuntime jSRuntime, IJSObjectReference jSReference, CreationOptions options) : base(jSRuntime, jSReference, options)
4444
{

src/KristofferStrube.Blazor.WebAudio/AudioNodes/StereoPannerNode.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ public class StereoPannerNode : AudioNode, IJSCreatable<StereoPannerNode>
3636
/// <returns>A new instance of a <see cref="StereoPannerNode"/>.</returns>
3737
public static async Task<StereoPannerNode> CreateAsync(IJSRuntime jSRuntime, BaseAudioContext context, StereoPannerOptions? options = null)
3838
{
39-
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
40-
IJSObjectReference jSInstance = await helper.InvokeAsync<IJSObjectReference>("constructStereoPannerNode", context, options);
39+
await using ErrorHandlingJSObjectReference errorHandlingHelper = await jSRuntime.GetErrorHandlingHelperAsync();
40+
IJSObjectReference jSInstance = await errorHandlingHelper.InvokeAsync<IJSObjectReference>("constructStereoPannerNode", context, options);
4141
return new StereoPannerNode(jSRuntime, jSInstance, new() { DisposesJSReference = true });
4242
}
4343

src/KristofferStrube.Blazor.WebAudio/Extensions/IJSRuntimeExtensions.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL;
2+
using Microsoft.JSInterop;
23

34
namespace KristofferStrube.Blazor.WebAudio.Extensions;
45

@@ -14,4 +15,9 @@ internal static async Task<IJSInProcessObjectReference> GetInProcessHelperAsync(
1415
return await jSRuntime.InvokeAsync<IJSInProcessObjectReference>(
1516
"import", "./_content/KristofferStrube.Blazor.WebAudio/KristofferStrube.Blazor.WebAudio.js");
1617
}
18+
internal static async Task<ErrorHandlingJSObjectReference> GetErrorHandlingHelperAsync(this IJSRuntime jSRuntime)
19+
{
20+
IJSObjectReference helper = await jSRuntime.GetHelperAsync();
21+
return new ErrorHandlingJSObjectReference(jSRuntime, helper);
22+
}
1723
}

src/KristofferStrube.Blazor.WebAudio/Options/ConstantSourceOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace KristofferStrube.Blazor.WebAudio;
66
/// This specifies options for constructing a <see cref="ConstantSourceNode"/>.
77
/// </summary>
88
/// <remarks><see href="https://www.w3.org/TR/webaudio/#ConstantSourceOptions">See the API definition here</see>.</remarks>
9-
public class ConstantSourceOptions : AudioNodeOptions
9+
public class ConstantSourceOptions
1010
{
1111
/// <summary>
1212
/// The initial value for the <see cref="ConstantSourceNode.GetOffsetAsync"/> <see cref="AudioParam"/> of this node.

tests/IntegrationTests/AudioNodeTests/AudioNodeWithAudioNodeOptions.cs

+35
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public override async Task<TAudioNode> GetDefaultInstanceAsync()
1212
return await CreateAsync(EvaluationContext.JSRuntime, await EvaluationContext.GetAudioContext(), null);
1313
}
1414

15+
public virtual Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => [];
16+
1517
[Test]
1618
public async Task CreateAsync_WithEmptyOptions_Succeeds()
1719
{
@@ -76,4 +78,37 @@ public async Task CreateAsync_WithEmptyOptions_HasSameChannelInterpretationAsWhe
7678
(ChannelInterpretation emptyOptionsChannelInterpretation, ChannelInterpretation noOptionsChannelInterpretation) = EvaluationContext.Result.Should().BeOfType<(ChannelInterpretation, ChannelInterpretation)>().Subject;
7779
_ = emptyOptionsChannelInterpretation.Should().Be(noOptionsChannelInterpretation);
7880
}
81+
82+
[TestCase(ChannelCountMode.Max)]
83+
[TestCase(ChannelCountMode.Explicit)]
84+
[TestCase(ChannelCountMode.ClampedMax)]
85+
[Test]
86+
public async Task CreateAsync_WithDifferentChannelCountModes_SetsChannelCount_ExceptForUnsupportedValues(ChannelCountMode mode)
87+
{
88+
// Arrange
89+
AfterRenderAsync = async () =>
90+
{
91+
TAudioNodeOptions options = new();
92+
options.ChannelCountMode = mode;
93+
94+
await using TAudioNode node = await CreateAsync(EvaluationContext.JSRuntime, await EvaluationContext.GetAudioContext(), options);
95+
96+
return await node.GetChannelCountModeAsync();
97+
};
98+
99+
// Act
100+
await OnAfterRerenderAsync();
101+
102+
// Assert
103+
if (UnsupportedChannelCountModes.TryGetValue(mode, out Type? exceptionType))
104+
{
105+
_ = EvaluationContext.Result.Should().Be(null);
106+
_ = EvaluationContext.Exception.Should().BeOfType(exceptionType);
107+
}
108+
else
109+
{
110+
_ = EvaluationContext.Exception.Should().BeNull();
111+
_ = EvaluationContext.Result.Should().Be(mode);
112+
}
113+
}
79114
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL.Exceptions;
2+
using Microsoft.JSInterop;
23

34
namespace IntegrationTests.AudioNodeTests;
45

56
public class ChannelMergerNodeTest : AudioNodeWithAudioNodeOptions<ChannelMergerNode, ChannelMergerOptions>
67
{
78
public override async Task<ChannelMergerNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, ChannelMergerOptions? options)
89
=> await ChannelMergerNode.CreateAsync(jSRuntime, context, options);
10+
11+
public override Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => new()
12+
{
13+
[ChannelCountMode.Max] = typeof(InvalidStateErrorException),
14+
[ChannelCountMode.ClampedMax] = typeof(InvalidStateErrorException),
15+
};
916
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL.Exceptions;
2+
using Microsoft.JSInterop;
23

34
namespace IntegrationTests.AudioNodeTests;
45

56
public class ChannelSplitterNodeTest : AudioNodeWithAudioNodeOptions<ChannelSplitterNode, ChannelSplitterOptions>
67
{
78
public override async Task<ChannelSplitterNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, ChannelSplitterOptions? options)
89
=> await ChannelSplitterNode.CreateAsync(jSRuntime, context, options);
10+
11+
public override Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => new()
12+
{
13+
[ChannelCountMode.Max] = typeof(InvalidStateErrorException),
14+
[ChannelCountMode.ClampedMax] = typeof(InvalidStateErrorException),
15+
};
916
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
using Microsoft.JSInterop;
1+
namespace IntegrationTests.AudioNodeTests;
22

3-
namespace IntegrationTests.AudioNodeTests;
4-
5-
public class ConstantSourceNodeTest : AudioNodeWithAudioNodeOptions<ConstantSourceNode, ConstantSourceOptions>
3+
public class ConstantSourceNodeTest : AudioNodeTest<ConstantSourceNode>
64
{
7-
public override async Task<ConstantSourceNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, ConstantSourceOptions? options)
8-
=> await ConstantSourceNode.CreateAsync(jSRuntime, context, options);
5+
public override async Task<ConstantSourceNode> GetDefaultInstanceAsync()
6+
{
7+
return await ConstantSourceNode.CreateAsync(EvaluationContext.JSRuntime, await EvaluationContext.GetAudioContext());
8+
}
99
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL.Exceptions;
2+
using Microsoft.JSInterop;
23

34
namespace IntegrationTests.AudioNodeTests;
45

56
public class ConvolverNodeTest : AudioNodeWithAudioNodeOptions<ConvolverNode, ConvolverOptions>
67
{
78
public override async Task<ConvolverNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, ConvolverOptions? options)
89
=> await ConvolverNode.CreateAsync(jSRuntime, context, options);
10+
11+
public override Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => new()
12+
{
13+
[ChannelCountMode.Max] = typeof(NotSupportedErrorException)
14+
};
915
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL.Exceptions;
2+
using Microsoft.JSInterop;
23

34
namespace IntegrationTests.AudioNodeTests;
45

56
public class DynamicsCompressorNodeTest : AudioNodeWithAudioNodeOptions<DynamicsCompressorNode, DynamicsCompressorOptions>
67
{
78
public override async Task<DynamicsCompressorNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, DynamicsCompressorOptions? options)
89
=> await DynamicsCompressorNode.CreateAsync(jSRuntime, context, options);
10+
11+
public override Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => new()
12+
{
13+
[ChannelCountMode.Max] = typeof(NotSupportedErrorException)
14+
};
915
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL.Exceptions;
2+
using Microsoft.JSInterop;
23

34
namespace IntegrationTests.AudioNodeTests;
45

56
public class PannerNodeTest : AudioNodeWithAudioNodeOptions<PannerNode, PannerOptions>
67
{
78
public override async Task<PannerNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, PannerOptions? options)
89
=> await PannerNode.CreateAsync(jSRuntime, context, options);
10+
11+
public override Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => new()
12+
{
13+
[ChannelCountMode.Max] = typeof(NotSupportedErrorException)
14+
};
915
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
using Microsoft.JSInterop;
1+
using KristofferStrube.Blazor.WebIDL.Exceptions;
2+
using Microsoft.JSInterop;
23

34
namespace IntegrationTests.AudioNodeTests;
45

56
public class StereoPannerNodeTest : AudioNodeWithAudioNodeOptions<StereoPannerNode, StereoPannerOptions>
67
{
78
public override async Task<StereoPannerNode> CreateAsync(IJSRuntime jSRuntime, AudioContext context, StereoPannerOptions? options)
89
=> await StereoPannerNode.CreateAsync(jSRuntime, context, options);
10+
11+
public override Dictionary<ChannelCountMode, Type> UnsupportedChannelCountModes => new()
12+
{
13+
[ChannelCountMode.Max] = typeof(NotSupportedErrorException)
14+
};
915
}

0 commit comments

Comments
 (0)