Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/AudioDevices.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
@page "/audio-device"
@inject IStringLocalizer<AudioDevices> Localizer

<h3>@Localizer["AudioDeviceTitle"]</h3>

<h4>@Localizer["AudioDeviceIntro"]</h4>

<Pre>[Inject, NotNull]
private IAudioDevice? AudioDeviceService { get; set; }</Pre>

<DemoBlock Title="@Localizer["BaseUsageTitle"]"
Introduction="@Localizer["BaseUsageIntro"]"
Name="Normal">
<div class="row form-inline g-3">
<div class="col-12">
<div class="bb-actions">
<Button Text="@Localizer["AudioDeviceRequestText"]" Icon="fa-solid fa-microphone" OnClick="OnRequestDevice"></Button>
<Button Text="@Localizer["AudioDeviceOpenText"]" Icon="fa-solid fa-play" OnClick="OnOpen" IsDisabled="_isOpen || string.IsNullOrEmpty(_deviceId)"></Button>
<Button Text="@Localizer["AudioDeviceCloseText"]" Icon="fa-solid fa-stop" OnClick="OnClose" IsDisabled="!_isOpen"></Button>
</div>
</div>
<div class="col-12">
<Select Items="@_items" @bind-Value="_deviceId" DisplayText="Devices" ShowLabel="true"></Select>
</div>
</div>

<audio class="bb-audio d-none" controls></audio>
</DemoBlock>

Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Server.Components.Samples;

/// <summary>
/// AudioDevice Component
/// </summary>
public partial class AudioDevices : IAsyncDisposable
{
[Inject, NotNull]
private IAudioDevice? AudioDeviceService { get; set; }

private readonly List<IMediaDeviceInfo> _devices = [];

private List<SelectedItem> _items = [];

private string? _deviceId;

private bool _isOpen = false;

private async Task OnRequestDevice()
{
var devices = await AudioDeviceService.GetDevices();
if (devices != null)
{
_devices.Clear();
_devices.AddRange(devices);
_items = [.. _devices.Select(i => new SelectedItem(i.DeviceId, i.Label))];

_deviceId = _items.FirstOrDefault()?.Value;
}
}

private async Task OnOpen()
{
if (!string.IsNullOrEmpty(_deviceId))
{
var constraints = new MediaTrackConstraints
{
DeviceId = _deviceId,
Selector = ".bb-audio"
};
_isOpen = await AudioDeviceService.Open(constraints);
}
}

private async Task OnClose()
{
_isOpen = false;
await AudioDeviceService.Close(".bb-audio");
}

private async Task DisposeAsync(bool disposing)
{
if (disposing)
{
await OnClose();
}
}

/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async ValueTask DisposeAsync()
{
await DisposeAsync(true);
GC.SuppressFinalize(this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.bb-actions {
display: flex;
flex-wrap: wrap;
gap: .5rem .5rem;
}

.bb-audio {
margin-top: 1rem;
width: 100%;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<h4>@Localizer["VideoDeviceIntro"]</h4>

<Pre>[Inject, NotNull]
private IBluetooth? BluetoothService { get; set; }</Pre>
private IVideoDevice? VideoDeviceService { get; set; }</Pre>

<DemoBlock Title="@Localizer["BaseUsageTitle"]"
Introduction="@Localizer["BaseUsageIntro"]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private async Task OnOpenVideo()
var constraints = new MediaTrackConstraints
{
DeviceId = _deviceId,
VideoSelector = ".bb-video"
Selector = ".bb-video"
};
_isOpen = await VideoDeviceService.Open(constraints);
}
Expand All @@ -61,7 +61,7 @@ private async Task OnCapture()
_previewUrl = await VideoDeviceService.GetPreviewUrl();
}

private Task OnApply(int width, int height) => VideoDeviceService.Apply(new MediaTrackConstraints() { Width = width, Height = height });
private async Task OnApply(int width, int height) => await VideoDeviceService.Apply(new MediaTrackConstraints() { Width = width, Height = height });

private async Task DisposeAsync(bool disposing)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1551,7 +1551,13 @@ void AddServices(DemoMenuItem item)
new()
{
IsNew = true,
Text = Localizer["VideoDevices"],
Text = Localizer["AudioDevice"],
Url = "audio-device"
},
new()
{
IsNew = true,
Text = Localizer["VideoDevice"],
Url = "video-device"
},
new()
Expand Down
12 changes: 11 additions & 1 deletion src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4921,7 +4921,8 @@
"ShieldBadge": "ShieldBadge",
"OtpInput": "OtpInput",
"TotpService": "ITotpService",
"VideoDevices": "IVideoDevice"
"VideoDevice": "IVideoDevice",
"AudioDevice": "IAudioDevice"
},
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
"TablesHeaderTitle": "Header grouping function",
Expand Down Expand Up @@ -7128,5 +7129,14 @@
"VideoDeviceCloseText": "Close",
"VideoDeviceCaptureText": "Capture",
"VideoDeviceFlipText": "Flip"
},
"BootstrapBlazor.Server.Components.Samples.AudioDevices": {
"AudioDeviceTitle": "IAudioDevice",
"AudioDeviceIntro": "Get audio equipment operation capabilities through this service",
"BaseUsageTitle": "Basic usage",
"BaseUsageIntro": "Perform different operations by calling different API methods",
"AudioDeviceRequestText": "List",
"AudioDeviceOpenText": "Record",
"AudioDeviceCloseText": "Stop"
}
}
14 changes: 13 additions & 1 deletion src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -4921,7 +4921,8 @@
"ShieldBadge": "徽章组件 ShieldBadge",
"OtpInput": "验证码输入框 OtpInput",
"TotpService": "时间密码验证服务 ITotpService",
"VideoDevices": "视频设备服务 IVideoDevice"
"VideoDevice": "视频设备服务 IVideoDevice",
"AudioDevice": "音频设备服务 IAudioDevice"
},
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
"TablesHeaderTitle": "表头分组功能",
Expand Down Expand Up @@ -7128,5 +7129,16 @@
"VideoDeviceCloseText": "关闭设备",
"VideoDeviceCaptureText": "截图",
"VideoDeviceFlipText": "翻转镜头"
},
"BootstrapBlazor.Server.Components.Samples.AudioDevices": {
"AudioDeviceTitle": "IAudioDevice 音频设备服务",
"AudioDeviceIntro": "通过此服务获得音频设备操作能力",
"BaseUsageTitle": "基本用法",
"BaseUsageIntro": "通过调用不同的 api 方法进行不同操作",
"AudioDeviceRequestText": "枚举设备",
"AudioDeviceOpenText": "录音",
"AudioDeviceCloseText": "停止",
"AudioDevicePauseText": "暂停",
"AudioDeviceResumeText": "恢复"
}
}
3 changes: 2 additions & 1 deletion src/BootstrapBlazor.Server/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@
"shield-badge": "ShieldBadges",
"opt-input": "OtpInputs",
"otp-service": "OtpServices",
"video-device": "VideoDevices"
"video-device": "VideoDevices",
"audio-device": "AudioDevices"
},
"video": {
"table": "BV1ap4y1x7Qn?p=1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public static IServiceCollection AddBootstrapBlazor(this IServiceCollection serv
services.TryAddScoped<IBluetooth, DefaultBluetooth>();
services.TryAddScoped<IMediaDevices, DefaultMediaDevices>();
services.TryAddScoped<IVideoDevice, DefaultVideoDevice>();
services.TryAddScoped<IAudioDevice, DefaultAudioDevice>();
services.AddScoped<TabItemTextOptions>();
services.AddScoped<DialogService>();
services.AddScoped<MaskService>();
Expand Down
34 changes: 34 additions & 0 deletions src/BootstrapBlazor/Services/MediaDevices/DefaultAudioDevice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Components;

class DefaultAudioDevice(IMediaDevices deviceService) : IAudioDevice
{
/// <summary>
/// <inheritdoc/>
/// </summary>
/// <returns></returns>
public async Task<List<IMediaDeviceInfo>?> GetDevices()
{
var ret = new List<IMediaDeviceInfo>();
var devices = await deviceService.EnumerateDevices();
if (devices != null)
{
ret.AddRange(devices.Where(d => d.Kind == "audioinput"));
}
return ret;
}

public Task<bool> Open(MediaTrackConstraints constraints)
{
return deviceService.Open("audio", constraints);
}

public Task<bool> Close(string? selector)
{
return deviceService.Close(selector);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ private async Task<JSModule> LoadModule()
return await module.InvokeAsync<List<MediaDeviceInfo>?>("enumerateDevices");
}

public async Task<bool> Open(MediaTrackConstraints constraints)
public async Task<bool> Open(string type, MediaTrackConstraints constraints)
{
var module = await LoadModule();
return await module.InvokeAsync<bool>("open", constraints);
return await module.InvokeAsync<bool>("open", type, constraints);
}

public async Task<bool> Close(string? videoSelector)
public async Task<bool> Close(string? selector)
{
var module = await LoadModule();
return await module.InvokeAsync<bool>("close", videoSelector);
return await module.InvokeAsync<bool>("close", selector);
}

public async Task Capture()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ class DefaultVideoDevice(IMediaDevices deviceService) : IVideoDevice

public Task<bool> Open(MediaTrackConstraints constraints)
{
return deviceService.Open(constraints);
return deviceService.Open("video", constraints);
}

public Task<bool> Close(string? videoSelector)
public Task<bool> Close(string? selector)
{
return deviceService.Close(videoSelector);
return deviceService.Close(selector);
}

public Task Capture()
Expand Down
32 changes: 32 additions & 0 deletions src/BootstrapBlazor/Services/MediaDevices/IAudioDevice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Components;

/// <summary>
/// Audio Media Device Interface
/// </summary>
public interface IAudioDevice
{
/// <summary>
/// Gets the list of audio devices.
/// </summary>
/// <returns></returns>
Task<List<IMediaDeviceInfo>?> GetDevices();

/// <summary>
/// Opens the audio device with the specified constraints.
/// </summary>
/// <param name="constraints"></param>
/// <returns></returns>
Task<bool> Open(MediaTrackConstraints constraints);

/// <summary>
/// Close the audio device with the specified selector.
/// </summary>
/// <param name="selector"></param>
/// <returns></returns>
Task<bool> Close(string? selector);
}
7 changes: 4 additions & 3 deletions src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ public interface IMediaDevices
/// <summary>
/// The open() method of the MediaDevices interface creates a new MediaStream object and starts capturing media from the specified device.
/// </summary>
/// <param name="type">video or audio</param>
/// <param name="constraints"></param>
/// <returns></returns>
Task<bool> Open(MediaTrackConstraints constraints);
Task<bool> Open(string type, MediaTrackConstraints constraints);

/// <summary>
/// The close() method of the MediaDevices interface stops capturing media from the specified device and closes the MediaStream object.
/// </summary>
/// <param name="videoSelector"></param>
/// <param name="selector"></param>
/// <returns></returns>
Task<bool> Close(string? videoSelector);
Task<bool> Close(string? selector);

/// <summary>
/// The capture() method of the MediaDevices interface captures a still image from the specified video stream and saves it to the specified location.
Expand Down
4 changes: 2 additions & 2 deletions src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public interface IVideoDevice
/// <summary>
/// Close the video device with the specified selector.
/// </summary>
/// <param name="videoSelector"></param>
/// <param name="selector"></param>
/// <returns></returns>
Task<bool> Close(string? videoSelector);
Task<bool> Close(string? selector);

/// <summary>
/// Capture a still image from the video stream.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,27 @@ namespace BootstrapBlazor.Components;
public class MediaTrackConstraints
{
/// <summary>
///
///
/// </summary>
public string DeviceId { get; set; } = "";

/// <summary>
///
///
/// </summary>
public string? VideoSelector { get; set; }
public string? Selector { get; set; }

/// <summary>
///
///
/// </summary>
public int? Width { get; set; }

/// <summary>
///
///
/// </summary>
public int? Height { get; set; }

/// <summary>
///
///
/// </summary>
public string? FacingMode { get; set; }
}
Loading