Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ private IAudioDevice? AudioDeviceService { get; set; }</Pre>
<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>
<Button Text="@Localizer["AudioDeviceDownloadText"]" Icon="fa-solid fa-download" OnClick="OnDownload" IsDisabled="!_isDownload"></Button>
</div>
</div>
<div class="col-12">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ public partial class AudioDevices : IAsyncDisposable
[Inject, NotNull]
private IAudioDevice? AudioDeviceService { get; set; }

[Inject, NotNull]
private DownloadService? DownloadService { get; set; }

private readonly List<IMediaDeviceInfo> _devices = [];

private List<SelectedItem> _items = [];
Expand All @@ -21,6 +24,8 @@ public partial class AudioDevices : IAsyncDisposable

private bool _isOpen = false;

private bool _isDownload = false;

private async Task OnRequestDevice()
{
var devices = await AudioDeviceService.GetDevices();
Expand Down Expand Up @@ -49,8 +54,18 @@ private async Task OnOpen()

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

private async Task OnDownload()
{
var stream = await AudioDeviceService.GetData();
if (stream != null)
{
await DownloadService.DownloadFromStreamAsync($"data_{DateTime.Now:HHmmss}.wav", stream);
}
}

private async Task DisposeAsync(bool disposing)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private async Task OnDownload()
var stream = await VideoDeviceService.GetPreviewData();
if (stream != null)
{
await DownloadService.DownloadFromStreamAsync("preview.png", stream);
await DownloadService.DownloadFromStreamAsync($"preview_{DateTime.Now:HHmmss}.png", stream);
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -7137,6 +7137,9 @@
"BaseUsageIntro": "Perform different operations by calling different API methods",
"AudioDeviceRequestText": "List",
"AudioDeviceOpenText": "Record",
"AudioDeviceCloseText": "Stop"
"AudioDeviceCloseText": "Stop",
"AudioDevicePauseText": "Pause",
"AudioDeviceResumeText": "Resume",
"AudioDeviceDownloadText": "Download"
}
}
3 changes: 2 additions & 1 deletion src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -7139,6 +7139,7 @@
"AudioDeviceOpenText": "录音",
"AudioDeviceCloseText": "停止",
"AudioDevicePauseText": "暂停",
"AudioDeviceResumeText": "恢复"
"AudioDeviceResumeText": "恢复",
"AudioDeviceDownloadText": "下载"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@ public Task<bool> Close(string? selector)
{
return deviceService.Close(selector);
}

public Task<Stream?> GetData()
{
return deviceService.GetAudioData();
}
}
12 changes: 12 additions & 0 deletions src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,16 @@ public async Task<bool> Apply(MediaTrackConstraints constraints)
var module = await LoadModule();
return await module.InvokeAsync<bool>("apply", constraints);
}

public async Task<Stream?> GetAudioData()
{
Stream? ret = null;
var module = await LoadModule();
var stream = await module.InvokeAsync<IJSStreamReference?>("getAudioData");
if (stream != null)
{
ret = await stream.OpenReadStreamAsync(stream.Length);
}
return ret;
}
}
6 changes: 6 additions & 0 deletions src/BootstrapBlazor/Services/MediaDevices/IAudioDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,10 @@ public interface IAudioDevice
/// <param name="selector"></param>
/// <returns></returns>
Task<bool> Close(string? selector);

/// <summary>
/// Gets the stream of the audio.
/// </summary>
/// <returns></returns>
Task<Stream?> GetData();
}
6 changes: 6 additions & 0 deletions src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ public interface IMediaDevices
/// <param name="constraints"></param>
/// <returns></returns>
Task<bool> Apply(MediaTrackConstraints constraints);

/// <summary>
/// Gets the stream of the audio.
/// </summary>
/// <returns></returns>
Task<Stream?> GetAudioData();
}
6 changes: 6 additions & 0 deletions src/BootstrapBlazor/wwwroot/modules/media.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ export async function record(options) {
audio.classList.remove("d-none");
audio.classList.remove("hidden");
audio.removeAttribute("hidden");
media.audioBlob = blob;
}
}
delete media.audioSelector;
Expand Down Expand Up @@ -233,3 +234,8 @@ export function stop(selector) {
}
return ret;
}

export function getAudioData() {
const media = registerBootstrapBlazorModule("MediaDevices");
return media.audioBlob
}
8 changes: 8 additions & 0 deletions test/UnitTest/Services/AudioDeviceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone

using Microsoft.JSInterop;
using UnitTest.Mock;

namespace UnitTest.Services;

public class AudioDeviceTest : BootstrapBlazorTestBase
Expand All @@ -28,6 +31,7 @@ public async Task Open_Ok()
{
Context.JSInterop.Setup<bool>("open", _ => true).SetResult(true);
Context.JSInterop.Setup<bool>("close", _ => true).SetResult(true);
Context.JSInterop.Setup<IJSStreamReference?>("getAudioData").SetResult(new MockJSStreamReference());

var service = Context.Services.GetRequiredService<IAudioDevice>();
var options = new MediaTrackConstraints()
Expand All @@ -40,5 +44,9 @@ public async Task Open_Ok()

var close = await service.Close(".bb-audio");
Assert.True(close);

var data = await service.GetData();
Assert.NotNull(data);
Assert.Equal(4, data.Length);
}
}