Skip to content

Commit 2590302

Browse files
Updated video to use ConstrainDOMStringParameters for selecting device.
1 parent 51235fc commit 2590302

File tree

1 file changed

+54
-37
lines changed
  • samples/KristofferStrube.Blazor.MediaCaptureStreams.WasmExample/Pages

1 file changed

+54
-37
lines changed

samples/KristofferStrube.Blazor.MediaCaptureStreams.WasmExample/Pages/Video.razor

Lines changed: 54 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,21 @@ else
2626
@if (videoOptions.Count > 0)
2727
{
2828
<label for="videoSource">Video Source</label>
29-
<select id="videoSource" @bind=selectedVideoSource @bind:after="LoadMediaStream">
29+
<select id="videoSource" @bind=selectedVideoSource @bind:after="SelectDevice">
3030
@foreach (var option in videoOptions)
3131
{
3232
<option value="@option.id" selected="@(option.id == selectedVideoSource)">@option.label</option>
3333
}
3434
</select>
3535
<br />
3636
<label for="frameRate">Frame Rate (Current Camera Capabilites are @minimalFrameRate - @maximumFrameRate)</label>
37-
<input id="frameRate" type="number" step="1" @bind="frameRate" @bind:after="LoadMediaStream" />
37+
<input id="frameRate" type="number" step="1" @bind="frameRate" @bind:after="ChangeFrameRate" />
3838
}
3939
<video @ref="videoElement" width="100%" height="400" autoplay controls></video>
4040
}
4141

4242
@code {
43-
private MediaDevices mediaDevices = default!;
43+
private MediaDevices? mediaDevices = default;
4444
private MediaStreamTrack? videoStreamTrack;
4545
private string? error;
4646
private ElementReference videoElement;
@@ -51,17 +51,14 @@ else
5151
private double minimalFrameRate;
5252
private double maximumFrameRate;
5353

54-
protected override async Task OnInitializedAsync()
55-
{
56-
mediaDevices = await MediaDevicesService.GetMediaDevicesAsync();
57-
}
58-
5954
async Task OpenVideo()
6055
{
6156
try
6257
{
63-
await LoadMediaStream();
58+
if (mediaDevices is null)
59+
mediaDevices = await MediaDevicesService.GetMediaDevicesAsync();
6460

61+
await SelectDevice();
6562
var deviceInfos = await mediaDevices.EnumerateDevicesAsync();
6663
videoOptions.Clear();
6764
foreach (var device in deviceInfos)
@@ -80,45 +77,24 @@ else
8077
}
8178
catch (Exception ex)
8279
{
83-
error = $"{ex.GetType().Name}: {ex.Message}";
84-
await StopVideoTrack();
80+
throw;
81+
// await StopVideoTrack();
8582
}
8683
}
8784

88-
async Task LoadMediaStream()
85+
async Task ChangeFrameRate()
8986
{
9087
try
9188
{
9289
var mediaTrackConstraints = new MediaTrackConstraints()
9390
{
94-
AspectRatio = 16.0 / 9.0,
95-
FrameRate = frameRate is { } setFrameRate ? new ConstrainDoubleRange() { Exact = setFrameRate } : frameRate,
96-
DeviceId = selectedVideoSource is null ? null : new ConstrainDomString(selectedVideoSource)
91+
FrameRate = frameRate is { } setFrameRate ? new ConstrainDoubleRange() { Exact = setFrameRate } : frameRate
9792
};
98-
if (videoStreamTrack is null || shownVideoSource != selectedVideoSource)
93+
if (selectedVideoSource is not null)
9994
{
100-
var mediaStream = await mediaDevices.GetUserMediaAsync(new MediaStreamConstraints() { Video = mediaTrackConstraints });
101-
var videoTracks = await mediaStream.GetVideoTracksAsync();
102-
videoStreamTrack = videoTracks.FirstOrDefault();
103-
if (videoStreamTrack is not null)
104-
{
105-
var capabilities = await videoStreamTrack.GetCapabilitiesAsync();
106-
minimalFrameRate = capabilities.FrameRate?.Min ?? 0;
107-
maximumFrameRate = capabilities.FrameRate?.Max ?? 0;
108-
frameRate = (maximumFrameRate + minimalFrameRate) / 2.0;
109-
selectedVideoSource = capabilities.DeviceId;
110-
shownVideoSource = selectedVideoSource;
111-
}
112-
113-
StateHasChanged();
114-
// We don't have a wrapper for HtmlMediaElement's yet so we use simple JSInterop for this part.
115-
var htmlMediaElement = await JSRuntime.InvokeAsync<IJSObjectReference>("getReference", videoElement);
116-
await JSRuntime.InvokeVoidAsync("setAttribute", htmlMediaElement, "srcObject", mediaStream.JSReference);
117-
}
118-
else
119-
{
120-
await videoStreamTrack.ApplyContraintsAsync(mediaTrackConstraints);
95+
mediaTrackConstraints.DeviceId = new ConstrainDOMStringParameters() { Exact = selectedVideoSource };
12196
}
97+
await videoStreamTrack.ApplyContraintsAsync(mediaTrackConstraints);
12298
}
12399
catch (OverconstrainedErrorException ex)
124100
{
@@ -130,6 +106,44 @@ else
130106
error = $"{ex.GetType().Name}: {ex.Message}";
131107
await StopVideoTrack();
132108
}
109+
catch (Exception)
110+
{
111+
throw;
112+
}
113+
}
114+
115+
async Task SelectDevice()
116+
{
117+
if (selectedVideoSource != null && shownVideoSource == selectedVideoSource)
118+
return; // They picked the same device
119+
120+
var mediaTrackConstraints = new MediaTrackConstraints();
121+
if (selectedVideoSource is not null)
122+
{
123+
mediaTrackConstraints.DeviceId = new ConstrainDOMStringParameters() { Exact = selectedVideoSource };
124+
}
125+
126+
await using var mediaStream = await mediaDevices!.GetUserMediaAsync(new MediaStreamConstraints() { Video = mediaTrackConstraints });
127+
var videoTracks = await mediaStream.GetVideoTracksAsync();
128+
videoStreamTrack = videoTracks.FirstOrDefault();
129+
foreach (var unusedTrack in videoTracks.Skip(1))
130+
{
131+
await unusedTrack.DisposeAsync();
132+
}
133+
if (videoStreamTrack is not null)
134+
{
135+
var capabilities = await videoStreamTrack.GetCapabilitiesAsync();
136+
minimalFrameRate = capabilities.FrameRate?.Min ?? 0;
137+
maximumFrameRate = capabilities.FrameRate?.Max ?? 0;
138+
frameRate = (maximumFrameRate + minimalFrameRate) / 2.0;
139+
selectedVideoSource = capabilities.DeviceId;
140+
shownVideoSource = selectedVideoSource;
141+
}
142+
143+
StateHasChanged();
144+
// We don't have a wrapper for HtmlMediaElement's yet so we use simple JSInterop for this part.
145+
await using var htmlMediaElement = await JSRuntime.InvokeAsync<IJSObjectReference>("getReference", videoElement);
146+
await JSRuntime.InvokeVoidAsync("setAttribute", htmlMediaElement, "srcObject", mediaStream.JSReference);
133147
}
134148

135149
async Task StopVideoTrack()
@@ -142,6 +156,9 @@ else
142156
frameRate = null;
143157
if (mediaDevices is not null)
144158
await mediaDevices.DisposeAsync();
159+
mediaDevices = null;
160+
shownVideoSource = null;
161+
selectedVideoSource = null;
145162
}
146163

147164
public async ValueTask DisposeAsync()

0 commit comments

Comments
 (0)