Skip to content

Commit 2f518f9

Browse files
authored
feat(IAudioDevice): add IAudioDevice service (#5955)
* refactor: 重构代码 * feat: 增加 IAudioDevice 服务 * refactor: 增加注入服务代码 * refactor: 增加语音记录功能 * doc: 增加菜单 * doc: 增加示例代码 * refactor: 更新录音逻辑 * refactor: 更新样式 * doc: 增加源码映射文件 * refactor: 更新文档 * doc: 菜单本地化 * doc: 更新文档 * test: 增加单元测试 * refactor: 增加 type 区分音视频 * refactor: 增加资源销毁防止内存泄漏
1 parent 9fccdad commit 2f518f9

File tree

20 files changed

+390
-50
lines changed

20 files changed

+390
-50
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@page "/audio-device"
2+
@inject IStringLocalizer<AudioDevices> Localizer
3+
4+
<h3>@Localizer["AudioDeviceTitle"]</h3>
5+
6+
<h4>@Localizer["AudioDeviceIntro"]</h4>
7+
8+
<Pre>[Inject, NotNull]
9+
private IAudioDevice? AudioDeviceService { get; set; }</Pre>
10+
11+
<DemoBlock Title="@Localizer["BaseUsageTitle"]"
12+
Introduction="@Localizer["BaseUsageIntro"]"
13+
Name="Normal">
14+
<div class="row form-inline g-3">
15+
<div class="col-12">
16+
<div class="bb-actions">
17+
<Button Text="@Localizer["AudioDeviceRequestText"]" Icon="fa-solid fa-microphone" OnClick="OnRequestDevice"></Button>
18+
<Button Text="@Localizer["AudioDeviceOpenText"]" Icon="fa-solid fa-play" OnClick="OnOpen" IsDisabled="_isOpen || string.IsNullOrEmpty(_deviceId)"></Button>
19+
<Button Text="@Localizer["AudioDeviceCloseText"]" Icon="fa-solid fa-stop" OnClick="OnClose" IsDisabled="!_isOpen"></Button>
20+
</div>
21+
</div>
22+
<div class="col-12">
23+
<Select Items="@_items" @bind-Value="_deviceId" DisplayText="Devices" ShowLabel="true"></Select>
24+
</div>
25+
</div>
26+
27+
<audio class="bb-audio d-none" controls></audio>
28+
</DemoBlock>
29+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License
3+
// See the LICENSE file in the project root for more information.
4+
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
5+
6+
namespace BootstrapBlazor.Server.Components.Samples;
7+
8+
/// <summary>
9+
/// AudioDevice Component
10+
/// </summary>
11+
public partial class AudioDevices : IAsyncDisposable
12+
{
13+
[Inject, NotNull]
14+
private IAudioDevice? AudioDeviceService { get; set; }
15+
16+
private readonly List<IMediaDeviceInfo> _devices = [];
17+
18+
private List<SelectedItem> _items = [];
19+
20+
private string? _deviceId;
21+
22+
private bool _isOpen = false;
23+
24+
private async Task OnRequestDevice()
25+
{
26+
var devices = await AudioDeviceService.GetDevices();
27+
if (devices != null)
28+
{
29+
_devices.Clear();
30+
_devices.AddRange(devices);
31+
_items = [.. _devices.Select(i => new SelectedItem(i.DeviceId, i.Label))];
32+
33+
_deviceId = _items.FirstOrDefault()?.Value;
34+
}
35+
}
36+
37+
private async Task OnOpen()
38+
{
39+
if (!string.IsNullOrEmpty(_deviceId))
40+
{
41+
var constraints = new MediaTrackConstraints
42+
{
43+
DeviceId = _deviceId,
44+
Selector = ".bb-audio"
45+
};
46+
_isOpen = await AudioDeviceService.Open(constraints);
47+
}
48+
}
49+
50+
private async Task OnClose()
51+
{
52+
_isOpen = false;
53+
await AudioDeviceService.Close(".bb-audio");
54+
}
55+
56+
private async Task DisposeAsync(bool disposing)
57+
{
58+
if (disposing)
59+
{
60+
await OnClose();
61+
}
62+
}
63+
64+
/// <summary>
65+
/// <inheritdoc/>
66+
/// </summary>
67+
/// <returns></returns>
68+
/// <exception cref="NotImplementedException"></exception>
69+
public async ValueTask DisposeAsync()
70+
{
71+
await DisposeAsync(true);
72+
GC.SuppressFinalize(this);
73+
}
74+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.bb-actions {
2+
display: flex;
3+
flex-wrap: wrap;
4+
gap: .5rem .5rem;
5+
}
6+
7+
.bb-audio {
8+
margin-top: 1rem;
9+
width: 100%;
10+
}

src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<h4>@Localizer["VideoDeviceIntro"]</h4>
77

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

1111
<DemoBlock Title="@Localizer["BaseUsageTitle"]"
1212
Introduction="@Localizer["BaseUsageIntro"]"

src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private async Task OnOpenVideo()
4343
var constraints = new MediaTrackConstraints
4444
{
4545
DeviceId = _deviceId,
46-
VideoSelector = ".bb-video"
46+
Selector = ".bb-video"
4747
};
4848
_isOpen = await VideoDeviceService.Open(constraints);
4949
}
@@ -61,7 +61,7 @@ private async Task OnCapture()
6161
_previewUrl = await VideoDeviceService.GetPreviewUrl();
6262
}
6363

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

6666
private async Task DisposeAsync(bool disposing)
6767
{

src/BootstrapBlazor.Server/Extensions/MenusLocalizerExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1551,7 +1551,13 @@ void AddServices(DemoMenuItem item)
15511551
new()
15521552
{
15531553
IsNew = true,
1554-
Text = Localizer["VideoDevices"],
1554+
Text = Localizer["AudioDevice"],
1555+
Url = "audio-device"
1556+
},
1557+
new()
1558+
{
1559+
IsNew = true,
1560+
Text = Localizer["VideoDevice"],
15551561
Url = "video-device"
15561562
},
15571563
new()

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4921,7 +4921,8 @@
49214921
"ShieldBadge": "ShieldBadge",
49224922
"OtpInput": "OtpInput",
49234923
"TotpService": "ITotpService",
4924-
"VideoDevices": "IVideoDevice"
4924+
"VideoDevice": "IVideoDevice",
4925+
"AudioDevice": "IAudioDevice"
49254926
},
49264927
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
49274928
"TablesHeaderTitle": "Header grouping function",
@@ -7128,5 +7129,14 @@
71287129
"VideoDeviceCloseText": "Close",
71297130
"VideoDeviceCaptureText": "Capture",
71307131
"VideoDeviceFlipText": "Flip"
7132+
},
7133+
"BootstrapBlazor.Server.Components.Samples.AudioDevices": {
7134+
"AudioDeviceTitle": "IAudioDevice",
7135+
"AudioDeviceIntro": "Get audio equipment operation capabilities through this service",
7136+
"BaseUsageTitle": "Basic usage",
7137+
"BaseUsageIntro": "Perform different operations by calling different API methods",
7138+
"AudioDeviceRequestText": "List",
7139+
"AudioDeviceOpenText": "Record",
7140+
"AudioDeviceCloseText": "Stop"
71317141
}
71327142
}

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4921,7 +4921,8 @@
49214921
"ShieldBadge": "徽章组件 ShieldBadge",
49224922
"OtpInput": "验证码输入框 OtpInput",
49234923
"TotpService": "时间密码验证服务 ITotpService",
4924-
"VideoDevices": "视频设备服务 IVideoDevice"
4924+
"VideoDevice": "视频设备服务 IVideoDevice",
4925+
"AudioDevice": "音频设备服务 IAudioDevice"
49254926
},
49264927
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
49274928
"TablesHeaderTitle": "表头分组功能",
@@ -7128,5 +7129,16 @@
71287129
"VideoDeviceCloseText": "关闭设备",
71297130
"VideoDeviceCaptureText": "截图",
71307131
"VideoDeviceFlipText": "翻转镜头"
7132+
},
7133+
"BootstrapBlazor.Server.Components.Samples.AudioDevices": {
7134+
"AudioDeviceTitle": "IAudioDevice 音频设备服务",
7135+
"AudioDeviceIntro": "通过此服务获得音频设备操作能力",
7136+
"BaseUsageTitle": "基本用法",
7137+
"BaseUsageIntro": "通过调用不同的 api 方法进行不同操作",
7138+
"AudioDeviceRequestText": "枚举设备",
7139+
"AudioDeviceOpenText": "录音",
7140+
"AudioDeviceCloseText": "停止",
7141+
"AudioDevicePauseText": "暂停",
7142+
"AudioDeviceResumeText": "恢复"
71317143
}
71327144
}

src/BootstrapBlazor.Server/docs.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@
231231
"shield-badge": "ShieldBadges",
232232
"opt-input": "OtpInputs",
233233
"otp-service": "OtpServices",
234-
"video-device": "VideoDevices"
234+
"video-device": "VideoDevices",
235+
"audio-device": "AudioDevices"
235236
},
236237
"video": {
237238
"table": "BV1ap4y1x7Qn?p=1",

src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public static IServiceCollection AddBootstrapBlazor(this IServiceCollection serv
8888
services.TryAddScoped<IBluetooth, DefaultBluetooth>();
8989
services.TryAddScoped<IMediaDevices, DefaultMediaDevices>();
9090
services.TryAddScoped<IVideoDevice, DefaultVideoDevice>();
91+
services.TryAddScoped<IAudioDevice, DefaultAudioDevice>();
9192
services.AddScoped<TabItemTextOptions>();
9293
services.AddScoped<DialogService>();
9394
services.AddScoped<MaskService>();

0 commit comments

Comments
 (0)