前言

在本博客中,你将了解如何在 .NET MAUI 中开发录音机和播放器。音频播放器将录制和播放音频文件。
此应用程序可以在Android和iOS上部署和使用。

预览

以下是该录音机和播放录音的应用程序屏幕截图。

先决条件

IDE: VisualStudio 2022
支持的平台:Android 和 IOS
支持的操作系统:Android(7.0 及以上)和 iOS(v12 及以上)

步骤1:在两个平台中添加所需的权限。

要录制音频并将其保存在设备中,应用程序必须访问设备的音频输入和存储。为此,需要授予以下权限:

  • RECORD_AUDIO

  • READ_EXTERNAL_STORAGE

  • WRITE_EXTERNAL_STORAGE

注意:在iOS中,您无法添加存储权限。在选中和请求时,它将始终返回"已授予"。
在 Android 中,将以下代码添加到 AndroidManifest.xml 文件中。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

在 iOS 中,将以下代码添加到 Info.plist 文件中。

<key>NSMicrophoneUsageDescription</key>
<string>The audio recorder app wants to use your microphone to record audio.</string>

步骤2:创建用于录制和播放音频的服务。

NET MAUI 没有能够直接使用的录制和播放音频功能。因此,必须在本机平台中创建用于录制和播放音频文件的服务。
在创建服务类之前,请创建用于调用本机方法的接口。

请参考以下代码。

public interface IAudioPlayer
{
void PlayAudio(string filePath);
void Pause();
void Stop();
string GetCurrentPlayTime();
bool CheckFinishedPlayingAudio();
}

public interface IRecordAudio
{
void StartRecord();
string StopRecord();
void PauseRecord();
void ResetRecord();
}

然后,创建服务以在两个平台上录制和播放音频。

安卓录音机服务

参考以下方法和属性来创建适用于 Android 的录音机服务:

  • 创建 MediaRecorder 类的实例,该实例将用于录制音频.

  • SetAudioSource(): 指定用于捕获音频输入的硬件设备.

  • SetOutputFile(): 指定输出音频文件的名称.

  • Prepare(): 初始化录音机.

  • Start(): 开始录制音频.

  • Reset(): 丢弃录制的音频并重置录音机.

  • Pause(): 将录制暂停在当前运行位置.

  • Resume(): 从暂停位置恢复录制.

  • Stop(): 停止录音.
    请参考以下代码。

public class RecordAudio : IRecordAudio
{
#region Fields
private MediaRecorder mediaRecorder;
private string storagePath;
private bool isRecordStarted = false;
#endregion
#region Methods

public void StartRecord()
{
if (mediaRecorder == null)
{
SetAudioFilePath();
mediaRecorder = new MediaRecorder();
mediaRecorder.Reset();
mediaRecorder.SetAudioSource(AudioSource.Mic);
mediaRecorder.SetOutputFormat(OutputFormat.AacAdts);
mediaRecorder.SetAudioEncoder(AudioEncoder.Aac);
mediaRecorder.SetOutputFile(storagePath);
mediaRecorder.Prepare();
mediaRecorder.Start();
}
else
{
mediaRecorder.Resume();
}
isRecordStarted = true;
}
public void PauseRecord()
{
if (mediaRecorder == null)
{
return;
}
mediaRecorder.Pause();
isRecordStarted = false;
}
public void ResetRecord()
{
if (mediaRecorder != null)
{
mediaRecorder.Resume();
mediaRecorder.Reset();
}
mediaRecorder = null;
isRecordStarted = false;
}
public string StopRecord()
{
if (mediaRecorder == null)
{
return string.Empty;
}
mediaRecorder.Resume();
mediaRecorder.Stop();
mediaRecorder = null;
isRecordStarted = false;
return storagePath;
}
private void SetAudioFilePath()
{
string fileName = "/Record_" + DateTime.UtcNow.ToString("ddMMM_hhmmss") + ".mp3";
var path = Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
storagePath = path + fileName;
Directory.CreateDirectory(path);
}
#endregion
}

适用于 iOS 的录音机服务

现在,使用AVAudioRecorder为iOS平台创建录音机服务:

  • 在尝试录制之前初始化音频会话。

  • 指定录制文件格式和保存录制内容的位置。记录格式被指定为 NSDictionary 中的条目,其中包含两个包含格式键和值的 NSObject 数组。

  • 准备好开始录制音频时调用 Record 方法。

  • 完成录制后,在录制器上调用 Stop() 方法。
    请参考以下代码。

public class RecordAudio : IRecordAudio
{
AVAudioRecorder recorder;
NSUrl url;
NSError error;
NSDictionary settings;
string audioFilePath;
public RecordAudio()
{
InitializeAudioSession();
}
private bool InitializeAudioSession()
{
var audioSession = AVAudioSession.SharedInstance();
var err = audioSession.SetCategory(AVAudioSessionCategory.PlayAndRecord);
if (err != null)
{
Console.WriteLine("audioSession: {0}", err);
return false;
}
err = audioSession.SetActive(true);
if (err != null)
{
Console.WriteLine("audioSession: {0}", err);
return false;
}
return false;
}
public void PauseRecord()
{
recorder.Pause();
}
public void ResetRecord()
{
recorder.Dispose();
recorder = null;
}
public void StartRecord()
{
if (recorder == null)
{
string fileName = "/Record_" + DateTime.UtcNow.ToString("ddMMM_hhmmss") + ".wav";
var docuFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
audioFilePath = docuFolder + fileName;
url = NSUrl.FromFilename(audioFilePath);
NSObject[] values = new NSObject[]
{
NSNumber.FromFloat(44100.0f),
NSNumber.FromInt32((int)AudioToolbox.AudioFormatType.LinearPCM),
NSNumber.FromInt32(2),
NSNumber.FromInt32(16),
NSNumber.FromBoolean(false),
NSNumber.FromBoolean(false)
};
NSObject[] key = new NSObject[]
{
AVAudioSettings.AVSampleRateKey,
AVAudioSettings.AVFormatIDKey,
AVAudioSettings.AVNumberOfChannelsKey,
AVAudioSettings.AVLinearPCMBitDepthKey,
AVAudioSettings.AVLinearPCMIsBigEndianKey,
AVAudioSettings.AVLinearPCMIsFloatKey
};
settings = NSDictionary.FromObjectsAndKeys(values, key);
recorder = AVAudioRecorder.Create(url, new AudioSettings(settings), out error);
recorder.PrepareToRecord();
recorder.Record();
}
else
{
recorder.Record();
}
}
public string StopRecord()
{
if (recorder == null)
{
return string.Empty;
}
recorder.Stop();
recorder = null;
return audioFilePath;
}
}

现在,来实现一个音频播放器服务,用于在两个平台上播放录制的音频。

适用于安卓的音频播放器服务

请按照以下步骤创建适用于 Android 的音频播放服务:

  • 创建 MediaPlayer 类的实例以播放音频文件。

  • 通过 SetDataSource 方法将音频文件的文件路径提供给媒体播放器实例。

  • 设置数据源后,通过调用 Prepare 方法准备媒体播放器。

  • 准备好媒体播放器后,使用 Start 方法开始播放音频。
    请参考以下代码。

public class AudioPlayer  : IAudioPlayer
{
#region Fields
private MediaPlayer _mediaPlayer;
private int currentPositionLength = 0;
private bool isPrepared;
private bool isCompleted;
#endregion

#region Methods
public void PlayAudio(string filePath)
{
if (_mediaPlayer != null && !_mediaPlayer.IsPlaying)
{
_mediaPlayer.SeekTo(currentPositionLength);
currentPositionLength = 0;
_mediaPlayer.Start();
}
else if (_mediaPlayer == null || !_mediaPlayer.IsPlaying)
{
try
{
isCompleted = false;
_mediaPlayer = new MediaPlayer();
_mediaPlayer.SetDataSource(filePath);
_mediaPlayer.SetAudioStreamType(Stream.Music);
_mediaPlayer.PrepareAsync();
_mediaPlayer.Prepared += (sender, args) =>
{
isPrepared = true;
_mediaPlayer.Start();
};
_mediaPlayer.Completion += (sender, args) =>
{
isCompleted = true;
};
}
catch (Exception e)
{
_mediaPlayer = null;
}
}
}
public void Pause()
{
if (_mediaPlayer != null && _mediaPlayer.IsPlaying)
{
_mediaPlayer.Pause();
currentPositionLength = _mediaPlayer.CurrentPosition;
}
}
public void Stop()
{
if (_mediaPlayer != null)
{
if (isPrepared)
{
_mediaPlayer.Stop();
_mediaPlayer.Release();
isPrepared = false;
}
isCompleted = false;
_mediaPlayer = null;
}
}
public string GetCurrentPlayTime()
{
if (_mediaPlayer != null)
{
var positionTimeSeconds =
double.Parse(_mediaPlayer.CurrentPosition.ToString());
positionTimeSeconds = positionTimeSeconds / 1000;
TimeSpan currentTime = TimeSpan.FromSeconds(positionTimeSeconds);
string currentPlayTime = string.Format("{0:mm\\:ss}", currentTime);
return currentPlayTime;
}
return null;
}
public bool CheckFinishedPlayingAudio()
{
return isCompleted;
}
#endregion
}

适用于 iOS 的音频播放器服务

使用 AVPlayer 类在 iOS 中创建音频播放服务:

  • 将音频文件配置为通过 AVPlayerItem 内置类播放。

  • 调用 Play 方法以开始播放音频。
    请参考以下代码。

public class AudioPlayer : IAudioPlayer
{
AVPlayer _player;
NSObject notificationHandle;
NSUrl url;
private bool isFinishedPlaying;
private bool isPlaying;

public bool IsPlaying
{
get { return isPlaying; }
set
{
if (_player.Rate == 1 && _player.Error == null)
isPlaying = true;
else
isPlaying = false;
}
}
public AudioPlayer()
{
RegisterNotification();
}
~AudioPlayer()
{
UnregisterNotification();
}
public void PlayAudio(string filePath)
{
isFinishedPlaying = false;
if (_player == null)
{
url = NSUrl.FromString(filePath);
AVPlayerItem avPlayerItem = new AVPlayerItem(URL);
_player = new AVPlayer(avPlayerItem);
_player.AutomaticallyWaitsToMinimizeStalling = false;
_player.Volume = 1;
_player.Play();
IsPlaying = true;
isFinishedPlaying = false;
}
else if (_player != null && !IsPlaying)
{
_player.Play();
IsPlaying = true;
isFinishedPlaying = false;
}
}
public void Pause()
{
if (_player != null && IsPlaying)
{
_player.Pause();
IsPlaying = false;
}
}
public void Stop()
{
if (_player != null)
{
_player.Dispose();
IsPlaying = false;
_player = null;
}
}
public string GetCurrentPlayTime()
{
if (_player != null)
{
var positionTimeSeconds = _player.CurrentTime.Seconds;
TimeSpan currentTime = TimeSpan.FromSeconds(positionTimeSeconds);
string currentPlayTime = string.Format("{0:mm\\:ss}", currentTime);
return currentPlayTime;
}
return null;
}
public bool CheckFinishedPlayingAudio()
{
return isFinishedPlaying;
}
private void RegisterNotification()
{
notificationHandle = NSNotificationCenter.DefaultCenter.AddObserver(AVPlayerItem.DidPlayToEndTimeNotification, HandleNotification);
}
private void UnregisterNotification()
{
NSNotificationCenter.DefaultCenter.RemoveObserver(notificationHandle);
}
private void HandleNotification(NSNotification notification)
{
isFinishedPlaying = true;
Stop();
}
}

步骤3:创建模型。

创建一个模型类以在列表中显示录制的音频文件。请参考以下代码。

public class Audio : INotifyPropertyChanged
{
#region Private
private bool isPlayVisible;
private bool isPauseVisible;
private string currentAudioPostion;
#endregion

#region Constructor
public Audio()
{
IsPlayVisible = true;
}
#endregion

#region Properties
public string AudioName { get; set; }
public string AudioURL { get; set; }
public string Caption { get; set; }
public bool IsPlayVisible
{
get { return isPlayVisible; }
set
{
isPlayVisible = value;
OnPropertyChanged();
IsPauseVisble = !value;
}
}
public bool IsPauseVisble
{
get { return isPauseVisible; }
set { isPauseVisible = value; OnPropertyChanged(); }
}
public string CurrentAudioPosition
{
get { return currentAudioPostion; }
set
{
if (string.IsNullOrEmpty(currentAudioPostion))
{
currentAudioPostion = string.Format("{0:mm\\:ss}", new TimeSpan());
}
else
{
currentAudioPostion = value;
}
OnPropertyChanged();
}
}
#endregion
}

在代码中,属性可以显示播放音频时间。

步骤4:创建 UI。

这里将创建一个简单的UI,用于显示录制的音频文件和录制音频。为此,这里使用 Syncfusion 的 ListView for .NET MAUI。安装 .NET MAUI 列表视图 NuGet 包,然后将其包含在应用程序中。

以下 XAML 代码将在 Syncfusion 的 .NET MAUI 列表视图控件中显示录制的音频。

<syncfusion:SfListView
x:Name="AudioList"
Grid.Row="0"
Grid.ColumnSpan="2"
Margin="0,8"
IsVisible="true"
ItemsSource="{Binding Audios}"
SelectionMode="None">
<syncfusion:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid
x:Name="PlayAudioGrid"
Margin="0,4,0,12"
BackgroundColor="Transparent"
HeightRequest="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="0"
Padding="0"
BackgroundColor="Transparent"
Command="{Binding Path=BindingContext.PlayAudioCommand, Source={x:Reference mainPage}}"
CommandParameter="{Binding .}"
FontFamily="AudioIconFonts"
FontSize="22"
IsVisible="{Binding IsPlayVisible}"
Text=""
TextColor="Black" />
<Button
Grid.Column="0"
Padding="0"
BackgroundColor="Transparent"
BorderColor="LightGray"
Command="{Binding Path=BindingContext.PauseAudioCommand, Source={x:Reference mainPage}}"
CommandParameter="{Binding .}"
FontFamily="AudioIconFonts"
FontSize="22"
IsVisible="{Binding IsPauseVisble}"
Text=""
TextColor="Black" />
<Label
Grid.Column="1"
FontSize="14"
Text="{Binding AudioName}"
TextColor="Black"
VerticalTextAlignment="Center" />
<Label
Grid.Column="2"
Margin="0,0,12,0"
FontSize="14"
IsVisible="{Binding IsPauseVisble}"
Text="{Binding CurrentAudioPosition}"
TextColor="Black"
VerticalTextAlignment="Center" />
<Button
Grid.Column="3"
BackgroundColor="Transparent"
Command="{Binding Path=BindingContext.DeleteCommand, Source={x:Reference mainPage}}"
CommandParameter="{Binding}"
FontFamily="AudioIconFonts"
FontSize="20"
Text="&#xe9ac"
TextColor="Red" />
</Grid>
</ViewCell>
</DataTemplate>
</syncfusion:SfListView.ItemTemplate>
</syncfusion:SfListView>

以下 XAML 代码用于设计用于录制音频的 UI。

<!--  Timer Label  -->
<StackLayout
Grid.Row="2"
Grid.ColumnSpan="2"
Margin="0,0,0,32"
VerticalOptions="End">
<Label
FontSize="14"
HorizontalTextAlignment="Center"
IsVisible="{Binding IsRecordingAudio}"
Text="Recording…"
TextColor="#7D898F" />
<Label
FontSize="60"
HorizontalTextAlignment="Center"
IsVisible="{Binding IsRecordingAudio}"
Text="{Binding TimerLabel}"
TextColor="Black" />
</StackLayout>

<!-- Button Setup -->
<Grid
Grid.Row="3"
Grid.ColumnSpan="2"
ColumnSpacing="60">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<!-- Retry -->
<Grid Grid.Column="0" RowDefinitions="auto,auto">
<Button
Grid.Row="0"
BackgroundColor="LightGray"
BorderColor="#5F49FF"
BorderWidth="1"
Command="{Binding ResetCommand}"
CornerRadius="25"
FontFamily="AudioIconFonts"
FontSize="22"
HeightRequest="50"
IsEnabled="{Binding IsRecordingAudio}"
Text=""
TextColor="#5F49FF"
WidthRequest="50">
<Button.Triggers>
<DataTrigger
Binding="{Binding IsRecordingAudio}"
TargetType="Button"
Value="False">
<Setter Property="TextColor" Value="Gray" />
<Setter Property="BorderColor" Value="Gray" />
</DataTrigger>
</Button.Triggers>
</Button>
<Label
Grid.Row="1"
HorizontalOptions="Center"
Text="Retry" />
</Grid>

<!-- Play -->
<Grid
Grid.Column="1"
HorizontalOptions="CenterAndExpand"
RowDefinitions="auto,auto">
<!-- Record Button -->
<Button
Grid.Row="0"
BackgroundColor="Red"
BorderColor="Red"
BorderWidth="1"
Command="{Binding RecordCommand}"
CornerRadius="25"
FontFamily="AudioIconFonts"
FontSize="22"
HeightRequest="50"
IsVisible="{Binding IsRecordButtonVisible}"
Text=""
TextColor="White"
WidthRequest="50" />
<Label
Grid.Row="1"
HorizontalOptions="Center"
IsVisible="{Binding IsRecordButtonVisible}"
Text="Record" />

<!-- Pause Button -->
<Button
Grid.Row="0"
BackgroundColor="Green"
BorderColor="Green"
BorderWidth="1"
Command="{Binding PauseCommand}"
CornerRadius="25"
FontFamily="AudioIconFonts"
FontSize="22"
HeightRequest="50"
IsVisible="{Binding IsPauseButtonVisible}"
Text=""
TextColor="White"
WidthRequest="50" />
<Label
Grid.Row="1"
HorizontalOptions="Center"
IsVisible="{Binding IsPauseButtonVisible}"
Text="Pause" />

<!-- Resume Button -->
<Button
Grid.Row="0"
BackgroundColor="Red"
BorderColor="Red"
BorderWidth="1"
Command="{Binding RecordCommand}"
CornerRadius="25"
FontFamily="AudioIconFonts"
FontSize="22"
HeightRequest="50"
IsVisible="{Binding IsResumeButtonVisible}"
Text=""
TextColor="White"
WidthRequest="50" />
<Label
Grid.Row="1"
HorizontalOptions="Center"
IsVisible="{Binding IsResumeButtonVisible}"
Text="Resume" />
</Grid>

<!-- Stop -->
<Grid Grid.Column="2" RowDefinitions="auto,auto">
<Button
Grid.Row="0"
BackgroundColor="LightGray"
BorderColor="#5F49FF"
BorderWidth="1"
Command="{Binding StopCommand}"
CornerRadius="25"
FontFamily="AudioIconFonts"
FontSize="22"
HeightRequest="50"
IsEnabled="{Binding IsRecordingAudio}"
Text=""
TextColor="#5F49FF"
WidthRequest="50">
<Button.Triggers>
<DataTrigger
Binding="{Binding IsRecordingAudio}"
TargetType="Button"
Value="False">
<Setter Property="TextColor" Value="Gray" />
<Setter Property="BorderColor" Value="Gray" />
</DataTrigger>
</Button.Triggers>
</Button>
<Label
Grid.Row="1"
HorizontalOptions="Center"
Text="Stop" />
</Grid>
</Grid>

步骤 5:注册依赖项注入以访问构造函数中的对象。

依赖关系注入是对象(客户端)接收依赖于它的其他对象(服务)的一种方式。若要了解有关在 .NET MAUI 中使用依赖项注入的详细信息.
请参阅以下代码以注册依赖项注入服务。首先,必须添加必要的服务。然后,可以直接访问所需类构造函数中的对象。因此才可以在视图模型中访问 AudioPlayerService 和 RecordAudioService 对象。

public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
fonts.AddFont("AudioIconFonts.ttf", "AudioIconFonts");
});
#if ANDROID || IOS
builder.Services.AddTransient<IAudioPlayerService, AudioPlayerService>();
builder.Services.AddTransient<IRecordAudioService, RecordAudioService>();
#endif
builder.Services.AddTransient<MainPage>();
builder.Services.AddTransient<AppShell>();
builder.ConfigureSyncfusionListView();
return builder.Build();
}

步骤6:创建视图模型。

这里遵循 MVVM(模型-视图-视图模型)结构来开发该应用程序。
因此,需要创建一个用于录制和播放音频的视图模型(MainPageViewModel.cs)文件。
在 ViewModel 中,生成一个音频集合来绑定录制音频的数据。

ViewModel 类中的属性
recordTime,playTimer:播放或录制音频时UI中使用的计时器属性。
IsRecordingAudio: 控制重置和停止选项的可见性。
IsPauseButtonVisible:控制 UI 中“暂停”按钮的可见性。
IsRecordButtonVisible:控制“录制”按钮的可见性。
IsResumeButtonVisible:控制“恢复”按钮的可见性。
audios:要在列表视图中显示的所有录制音频文件的集合。
recordAudioService,audioPlayerService:这些接口属性调用特定于本机平台的代码。
下面的代码示例演示录音机。

使用以下代码启动录制器。必须调用依赖服务方法 recordAudio.StartRecord() 来启动记录器。

只有授予权限,才能启动记录器。

private async void StartRecording()
{
if (!IsRecordingAudio)
{
var permissionStatus = await RequestandCheckPermission();
if (permissionStatus == PermissionStatus.Granted)
{
IsRecordingAudio = true;
IsPauseButtonVisible = true;
recordAudio.StartRecord();
IsRecordButtonVisible = false;
isRecord = true;
timerValue = new TimeSpan(0, 0, -1);
recordTimer.Start();
}
else
{
IsRecordingAudio = false;
IsPauseButtonVisible = false;
}
}
else
{
ResumeRecording();
}
}

使用 recordAudio.PauseRecord() 平台特定的方法暂停录制器。

private void PauseRecording()
{
isRecord = false;
IsPauseButtonVisible = false;
IsResumeButtonVisible = true;
recordAudio.PauseRecord();
}

以下方法用于从暂停位置继续录制。

private void ResumeRecording()
{
recordAudio.StartRecord();
IsResumeButtonVisible = false;
IsPauseButtonVisible = true;
isRecord = true;
}

使用以下代码重置记录器并从初始位置启动它。使用特定于平台的代码 recordAudio.ResetRecord() 重置录制器。

private void ResetRecording()
{
recordAudio.ResetRecord();
timerValue = new TimeSpan();
TimerLabel = string.Format("{0:mm\\:ss}", timerValue);
IsRecordingAudio = false;
IsPauseButtonVisible = false;
IsResumeButtonVisible = false;
StartRecording();
}

若要停止录制器,请使用特定于平台的代码 recordAudio.StopRecord()。

private async void StopRecording()
{
IsPauseButtonVisible = false;
IsResumeButtonVisible = false;
IsRecordingAudio = false;
IsRecordButtonVisible = true;
timerValue = new TimeSpan();
recordTimer.Stop();
RecentAudioFilePath = recordAudio.StopRecord();
await App.Current.MainPage.DisplayAlert("Alert", "Audio has been recorded", "Ok");
TimerLabel = string.Format("{0:mm\\:ss}", timerValue);
SendRecording();
}
private void SendRecording()
{
Audio recordedFile = new Audio() { AudioURL = RecentAudioFilePath };
if (recordedFile != null)
{
recordedFile.AudioName = Path.GetFileName(RecentAudioFilePath);
Audios.Insert(0, recordedFile);
}
}

以下代码用于获取录制权限

public async Task<PermissionStatus> RequestandCheckPermission()
{
PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
if (status != PermissionStatus.Granted)
await Permissions.RequestAsync<Permissions.StorageWrite>();

status = await Permissions.CheckStatusAsync<Permissions.Microphone>();
if (status != PermissionStatus.Granted)
await Permissions.RequestAsync<Permissions.Microphone>();
PermissionStatus storagePermission = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
PermissionStatus microPhonePermission = await Permissions.CheckStatusAsync<Permissions.Microphone>();
if (storagePermission == PermissionStatus.Granted && microPhonePermission == PermissionStatus.Granted)
{
return PermissionStatus.Granted;
}
return PermissionStatus.Denied;
}

下面的代码示例演示音频播放器。
调用特定于平台的方法 audioPlayer.PlayAudio(audioFilePath) 来播放音频。

private void StartPlayingAudio(object obj)
{
if (audioFile != null && audioFile != (Audio)obj)
{
AudioFile.IsPlayVisible = true;
StopAudio();
}
if (obj is Audio)
{
audioFile = (Audio)obj;
audioFile.IsPlayVisible = false;
string audioFilePath = AudioFile.AudioURL;
audioPlayer.PlayAudio(audioFilePath);
SetCurrentAudioPosition();
}
}

使用以下方法通过特定于平台的方法 audioPlayer.Pause() 暂停音频。

private void PauseAudio(object obj)
{
if (obj is Audio)
{
var audiophile = (Audio)obj;
audioFile.IsPlayVisible = true;
audioPlayer.Pause();
}
}

使用方法audioPlayer.Stop() 停止以下代码中的音频。

public void StopAudio()
{
if (AudioFile != null)
{
audioPlayer.Stop();
playTimer.Stop();
}
}

使用以下代码获取音频的当前位置并将其显示在 UI 中。

private void SetCurrentAudioPosition()
{
playTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
playTimer.Tick += (s, e) =>
{
if (AudioFile != null)
{
AudioFile.CurrentAudioPosition = audioPlayer.GetCurrentPlayTime();
bool isAudioCompleted = audioPlayer.CheckFinishedPlayingAudio();
if (isAudioCompleted)
{
AudioFile.IsPlayVisible = true;
playTimer.Stop();
}
}
};
playTimer.Start();
}

.NET 中创建录音机和播放器应用的更多相关文章

  1. 【Blazor】在ASP.NET Core中使用Blazor组件 - 创建一个音乐播放器

    前言 Blazor正式版的发布已经有一段时间了,.NET社区的各路高手也创建了一个又一个的Blazor组件库,其中就包括了我和其他小伙伴一起参与的AntDesign组件库,于上周终于发布了第一个版本0 ...

  2. Asp.Net MVC中Aplayer.js音乐播放器的使用

    1.前言: Aplater.js是一款可爱.漂亮的Js音乐播放器,以前就了解过也弄过一些,现在就用mp3的格式来在.Net里面开发.管网 https://aplayer.js.org/ 2.入手: 在 ...

  3. html中嵌入flvplayer.swf播放器,播放视频

    只需要改动红色的代码: <object classid='clsid:D27CDB6E-AE6D-11cf-96B8-4445535411111' codebase='http://downlo ...

  4. 22_Android中的本地音乐播放器和网络音乐播放器的编写,本地视频播放器和网络视频播放器,照相机案例,偷拍案例实现

    1 编写以下案例: 当点击了"播放"之后,在手机上的/mnt/sdcard2/natural.mp3就会播放. 2 编写布局文件activity_main.xml <Line ...

  5. .NET 中创建支持集合初始化器的类型

    对象初始化器和集合初始化器只是语法糖,但是能让你的代码看起来更加清晰.至少能让对象初始化的代码和其他业务执行的代码分开,可读性会好一些. 本文将编写一个类型,可以使用集合初始化器构造这个类型.不只是添 ...

  6. .NET中使用APlayer组件自制播放器

    目录 说明 APlayer介绍 APlayer具备功能 APlayer使用 自制播放器Demo 未完成工作 源码下载 说明 由于需求原因,需要在项目中(桌面程序)集成一个在线播放视频的功能.大概要具备 ...

  7. 驳Linux不娱乐 堪比Win平台中十款播放器

    播放器在我们日常生活中扮演着非常重要的角色,在Windows操作系统中,播放器被应用的非常广泛,不但我们可以听音乐,甚至还可以听广播,制作铃声,下载音乐等等.而在Linux发行版中,缺少娱乐性一直性W ...

  8. 【jquery】一款不错的音频播放器——Amazing Audio Player

    前段时间分享了一款视频播放器,点击这里.今天介绍一款不错的音频播放器——Amazing Audio Player. 介绍: Amazing Audio Player 是一个使用很方便的 Windows ...

  9. Android(java)学习笔记234: 服务(service)之音乐播放器

    1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...

  10. Android基于发展Service音乐播放器

    这是一个基于Service组件的音乐播放器,程序的音乐将会由后台的Service组件负责播放,当后台的播放状态改变时,程序将会通过发送广播通知前台Activity更新界面:当用户单击前台Activit ...

随机推荐

  1. python基础语法&数据类型&运算符

    1.标识符 # -*- coding:utf-8 -*- # @Time :2021/1/16 10:28 # @Author :QAbujiaban # @Email :wbxztoo@163.co ...

  2. 搭建漏洞环境及实战——在Windows系统中安装WAMP

    安装成功之后,打开显示 链接:https://pan.baidu.com/s/1NpU7fUYOO_CSM8dNXKdnCw 提取码:mxvw

  3. 《吐血整理》高级系列教程-吃透Fiddler抓包教程(37)-掌握Fiddler中Fiddler Script用法,你会有多牛逼-下篇

    1.简介 Fiddler是一款强大的HTTP抓包工具,它能记录所有客户端和服务器的http和https请求,允许你监视,设置断点,甚至修改输入输出数据. 使用Fiddler无论对开发还是测试来说,都有 ...

  4. 02-逻辑仿真工具VCS使用

    逻辑仿真工具VCS使用 1 Makefile执行VCS仿真 # Makefile for simulating the full_adder.v with the simulator VCS # -- ...

  5. C艹 里 printf 和 cout 的区别总结

    1. printf里面打出%需要连着打出两次 打出一次默认为格式标识符 打出两次: 2. 当 未完待续

  6. 花了半个小时基于 ChatGPT 搭建了一个微信机器人

    相信大家最近被 ChatGPT 刷屏了,其实在差不多一个月前就火过一次,不会那会好像只在程序员的圈子里面火起来了,并没有被大众认知到,不知道最近是因为什么又火起来了,而且这次搞的人尽皆知. 想着这么火 ...

  7. 洛谷p2669

    #include<bits/stdc++.h> using namespace std; int main() { int k,m=0,p=1;//p:给j个金币的第p天(1~j循环变化) ...

  8. mysql04-管理mysql常用指令

    https://www.runoob.com/mysql/mysql-administration.html 1.常用指令 USE 数据库名 :选择要操作的Mysql数据库,使用该命令后所有Mysql ...

  9. Python接口自动化测试(1)

    接口自动化测试三部曲:1.构造请求  2.判断结果  3.数据库查询 1.Python的第三方包:requests 简介:requests可以用来做接口测试.接口自动化测试.爬虫等 requests的 ...

  10. K3S 系列文章-5G IoT 网关设备 POD 访问报错 DNS 'i/o timeout'分析与解决

    开篇 <K3s 系列文章> <Rancher 系列文章> 问题概述 20220606 5G IoT 网关设备同时安装 K3S Server, 但是 POD 却无法访问互联网地址 ...