diff --git a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs
index fcb4abdd807..106cf49e745 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs
@@ -8,7 +8,7 @@ namespace BootstrapBlazor.Server.Components.Samples;
///
/// VideoDevice Component
///
-public partial class VideoDevices
+public partial class VideoDevices : IAsyncDisposable
{
[Inject, NotNull]
private IVideoDevice? VideoDeviceService { get; set; }
@@ -21,13 +21,18 @@ public partial class VideoDevices
private string? _previewUrl;
+ private bool _isOpen = false;
+
private async Task OnRequestDevice()
{
var devices = await VideoDeviceService.GetDevices();
if (devices != null)
{
+ _devices.Clear();
_devices.AddRange(devices);
_items = [.. _devices.Select(i => new SelectedItem(i.DeviceId, i.Label))];
+
+ _deviceId = _items.FirstOrDefault()?.Value;
}
}
@@ -40,12 +45,13 @@ private async Task OnOpenVideo()
DeviceId = _deviceId,
VideoSelector = ".bb-video"
};
- await VideoDeviceService.Open(constraints);
+ _isOpen = await VideoDeviceService.Open(constraints);
}
}
private async Task OnCloseVideo()
{
+ _isOpen = false;
_previewUrl = "";
await VideoDeviceService.Close(".bb-video");
}
@@ -55,8 +61,22 @@ private async Task OnCapture()
_previewUrl = await VideoDeviceService.GetPreviewUrl();
}
- private async Task OnFlip()
+ private async Task DisposeAsync(bool disposing)
+ {
+ if (disposing)
+ {
+ await OnCloseVideo();
+ }
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async ValueTask DisposeAsync()
{
- await VideoDeviceService.Flip();
+ await DisposeAsync(true);
+ GC.SuppressFinalize(this);
}
}
diff --git a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.css b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.css
index 386d7ebb984..75a4e73f32a 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.css
+++ b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.css
@@ -2,7 +2,6 @@
min-height: 240px;
height: auto;
width: auto;
- transform: scaleX(-1);
margin-top: 1rem;
display: block;
}
@@ -10,7 +9,6 @@
.bb-image {
border: 1px solid var(--bs-border-color);
border-radius: var(--bs-border-radius);
- transform: scaleX(-1);
margin-top: 1rem;
display: block;
}
diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj
index 0e6eb0e364b..1a7f7ef8660 100644
--- a/src/BootstrapBlazor/BootstrapBlazor.csproj
+++ b/src/BootstrapBlazor/BootstrapBlazor.csproj
@@ -1,7 +1,7 @@
- 9.6.1-beta01
+ 9.6.1-beta02
diff --git a/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs b/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
index d7292f54682..8b9f2c68c77 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
@@ -21,16 +21,16 @@ private async Task LoadModule()
return await module.InvokeAsync?>("enumerateDevices");
}
- public async Task Open(MediaTrackConstraints constraints)
+ public async Task Open(MediaTrackConstraints constraints)
{
var module = await LoadModule();
- await module.InvokeVoidAsync("open", constraints);
+ return await module.InvokeAsync("open", constraints);
}
- public async Task Close(string? videoSelector)
+ public async Task Close(string? videoSelector)
{
var module = await LoadModule();
- await module.InvokeVoidAsync("close", videoSelector);
+ return await module.InvokeAsync("close", videoSelector);
}
public async Task Capture()
@@ -44,10 +44,4 @@ public async Task Capture()
var module = await LoadModule();
return await module.InvokeAsync("getPreviewUrl");
}
-
- public async Task Flip()
- {
- var module = await LoadModule();
- await module.InvokeAsync("flip");
- }
}
diff --git a/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs b/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs
index afd44842007..ebe2a6123ed 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs
@@ -22,12 +22,12 @@ class DefaultVideoDevice(IMediaDevices deviceService) : IVideoDevice
return ret;
}
- public Task Open(MediaTrackConstraints constraints)
+ public Task Open(MediaTrackConstraints constraints)
{
return deviceService.Open(constraints);
}
- public Task Close(string? videoSelector)
+ public Task Close(string? videoSelector)
{
return deviceService.Close(videoSelector);
}
@@ -41,9 +41,4 @@ public Task Capture()
{
return deviceService.GetPreviewUrl();
}
-
- public Task Flip()
- {
- return deviceService.Flip();
- }
}
diff --git a/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs b/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
index ea4988a9940..24140322fbe 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
@@ -21,14 +21,14 @@ public interface IMediaDevices
///
///
///
- Task Open(MediaTrackConstraints constraints);
+ Task Open(MediaTrackConstraints constraints);
///
/// The close() method of the MediaDevices interface stops capturing media from the specified device and closes the MediaStream object.
///
///
///
- Task Close(string? videoSelector);
+ Task Close(string? videoSelector);
///
/// The capture() method of the MediaDevices interface captures a still image from the specified video stream and saves it to the specified location.
@@ -41,10 +41,4 @@ public interface IMediaDevices
///
///
Task GetPreviewUrl();
-
- ///
- /// Flip the video device.
- ///
- ///
- Task Flip();
}
diff --git a/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs b/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
index 7adffb16911..d838d97ef95 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
@@ -21,14 +21,14 @@ public interface IVideoDevice
///
///
///
- Task Open(MediaTrackConstraints constraints);
+ Task Open(MediaTrackConstraints constraints);
///
/// Close the video device with the specified selector.
///
///
///
- Task Close(string? videoSelector);
+ Task Close(string? videoSelector);
///
/// Capture a still image from the video stream.
@@ -53,10 +53,4 @@ public interface IVideoDevice
///
///
Task GetPreviewUrl();
-
- ///
- /// Flip the video device.
- ///
- ///
- Task Flip();
}
diff --git a/src/BootstrapBlazor/wwwroot/modules/media.js b/src/BootstrapBlazor/wwwroot/modules/media.js
index 442bebfe87b..ef82408e9d8 100644
--- a/src/BootstrapBlazor/wwwroot/modules/media.js
+++ b/src/BootstrapBlazor/wwwroot/modules/media.js
@@ -29,34 +29,52 @@ export async function open(options) {
if (height) {
constrains.video.height = { ideal: height };
}
- const stream = await navigator.mediaDevices.getUserMedia(constrains);
- const media = registerBootstrapBlazorModule("MediaDevices");
- media.stream = stream;
- if (videoSelector) {
- const video = document.querySelector(videoSelector);
- if (video) {
- video.srcObject = stream;
+ let ret = false;
+ try {
+ const stream = await navigator.mediaDevices.getUserMedia(constrains);
+ const media = registerBootstrapBlazorModule("MediaDevices");
+ media.stream = stream;
+
+ if (videoSelector) {
+ const video = document.querySelector(videoSelector);
+ if (video) {
+ video.srcObject = stream;
+ }
}
+ ret = true;
+ }
+ catch (err) {
+ console.error("Error accessing media devices.", err);
}
+ return ret;
}
export async function close(videoSelector) {
- if (videoSelector) {
- const video = document.querySelector(videoSelector);
- if (video) {
- video.pause();
- const stream = video.srcObject;
+ let ret = false;
+
+ try {
+ if (videoSelector) {
+ const video = document.querySelector(videoSelector);
+ if (video) {
+ video.pause();
+ const stream = video.srcObject;
+ closeStream(stream);
+ video.srcObject = null;
+ }
+ }
+ const media = registerBootstrapBlazorModule("MediaDevices");
+ const { stream } = media;
+ if (stream && stream.active) {
closeStream(stream);
- video.srcObject = null;
}
+ media.stream = null;
+ ret = true;
}
- const media = registerBootstrapBlazorModule("MediaDevices");
- const { stream } = media;
- if (stream && stream.active) {
- closeStream(stream);
+ catch (err) {
+ console.error("Error closing media devices.", err);
}
- media.stream = null;
+ return ret;
}
export async function getPreviewUrl() {
@@ -75,31 +93,6 @@ export async function getPreviewUrl() {
return url;
}
-export async function flip() {
- const media = registerBootstrapBlazorModule("MediaDevices");
- const { stream } = media;
- if (stream && stream.active) {
- const tracks = stream.getVideoTracks();
- if (tracks) {
- const track = tracks[0];
- const constraints = track.getSettings();
- const { facingMode } = constraints;
- if (facingMode === void 0) {
- console.log('facingMode is not supported');
- return;
- }
-
- if (facingMode === "user" || facingMode.exact === "user" || facingMode.ideal === "user") {
- constraints.facingMode = { ideal: "environment" }
- }
- else {
- constraints.facingMode = { ideal: "user" }
- }
- await track.applyConstraints(constraints);
- }
- }
-}
-
const closeStream = stream => {
if (stream) {
const tracks = stream.getTracks();
diff --git a/test/UnitTest/Services/VideoDeviceTest.cs b/test/UnitTest/Services/VideoDeviceTest.cs
index 3446801668d..7b19d907d64 100644
--- a/test/UnitTest/Services/VideoDeviceTest.cs
+++ b/test/UnitTest/Services/VideoDeviceTest.cs
@@ -26,6 +26,8 @@ public async Task GetDevices_Ok()
public async Task Open_Ok()
{
Context.JSInterop.Setup("getPreviewUrl").SetResult("blob:https://test-preview");
+ Context.JSInterop.Setup("open", _ => true).SetResult(true);
+ Context.JSInterop.Setup("close", _ => true).SetResult(true);
var service = Context.Services.GetRequiredService();
var options = new MediaTrackConstraints()
@@ -36,8 +38,11 @@ public async Task Open_Ok()
Width = 480,
VideoSelector = ".bb-video"
};
- await service.Open(options);
- await service.Close(".bb-video");
+ var open = await service.Open(options);
+ Assert.True(open);
+
+ var close = await service.Close(".bb-video");
+ Assert.True(close);
Assert.Equal("test-device-id", options.DeviceId);
Assert.Equal("user", options.FacingMode);
@@ -46,7 +51,6 @@ public async Task Open_Ok()
Assert.Equal(".bb-video", options.VideoSelector);
await service.Capture();
- await service.Flip();
var url = await service.GetPreviewUrl();
Assert.Equal("blob:https://test-preview", url);
}