.NET 中创建录音机和播放器应用
前言
在本博客中,你将了解如何在 .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=""
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 中创建录音机和播放器应用的更多相关文章
- 【Blazor】在ASP.NET Core中使用Blazor组件 - 创建一个音乐播放器
前言 Blazor正式版的发布已经有一段时间了,.NET社区的各路高手也创建了一个又一个的Blazor组件库,其中就包括了我和其他小伙伴一起参与的AntDesign组件库,于上周终于发布了第一个版本0 ...
- Asp.Net MVC中Aplayer.js音乐播放器的使用
1.前言: Aplater.js是一款可爱.漂亮的Js音乐播放器,以前就了解过也弄过一些,现在就用mp3的格式来在.Net里面开发.管网 https://aplayer.js.org/ 2.入手: 在 ...
- html中嵌入flvplayer.swf播放器,播放视频
只需要改动红色的代码: <object classid='clsid:D27CDB6E-AE6D-11cf-96B8-4445535411111' codebase='http://downlo ...
- 22_Android中的本地音乐播放器和网络音乐播放器的编写,本地视频播放器和网络视频播放器,照相机案例,偷拍案例实现
1 编写以下案例: 当点击了"播放"之后,在手机上的/mnt/sdcard2/natural.mp3就会播放. 2 编写布局文件activity_main.xml <Line ...
- .NET 中创建支持集合初始化器的类型
对象初始化器和集合初始化器只是语法糖,但是能让你的代码看起来更加清晰.至少能让对象初始化的代码和其他业务执行的代码分开,可读性会好一些. 本文将编写一个类型,可以使用集合初始化器构造这个类型.不只是添 ...
- .NET中使用APlayer组件自制播放器
目录 说明 APlayer介绍 APlayer具备功能 APlayer使用 自制播放器Demo 未完成工作 源码下载 说明 由于需求原因,需要在项目中(桌面程序)集成一个在线播放视频的功能.大概要具备 ...
- 驳Linux不娱乐 堪比Win平台中十款播放器
播放器在我们日常生活中扮演着非常重要的角色,在Windows操作系统中,播放器被应用的非常广泛,不但我们可以听音乐,甚至还可以听广播,制作铃声,下载音乐等等.而在Linux发行版中,缺少娱乐性一直性W ...
- 【jquery】一款不错的音频播放器——Amazing Audio Player
前段时间分享了一款视频播放器,点击这里.今天介绍一款不错的音频播放器——Amazing Audio Player. 介绍: Amazing Audio Player 是一个使用很方便的 Windows ...
- Android(java)学习笔记234: 服务(service)之音乐播放器
1.我们播放音乐,希望在后台长期运行,不希望因为内存不足等等原因,从而导致被gc回收,音乐播放终止,所以我们这里使用服务Service创建一个音乐播放器. 2.创建一个音乐播放器项目(使用服务) (1 ...
- Android基于发展Service音乐播放器
这是一个基于Service组件的音乐播放器,程序的音乐将会由后台的Service组件负责播放,当后台的播放状态改变时,程序将会通过发送广播通知前台Activity更新界面:当用户单击前台Activit ...
随机推荐
- Go语言使用场景 | go语言与其它开源语言比较 | Go WEB框架选型
一.Go语言使用场景 1. 关于go语言 2007年,受够了C++煎熬的Google首席软件工程师Rob Pike纠集Robert Griesemer和Ken Thompson两位牛人,决定创造一种新 ...
- C/C++随堂笔记
注释:行注释 块注释: (1)#if 0 #endif (2)/* */ <>:表示系统文件 <stdlib.h>+syetem 调用windows中的程序 QT中 c ...
- 详解JAVA线程问题诊断工具Thread Dump
摘要:Thread Dump是非常有用的诊断Java应用问题的工具. 本文分享自华为云社区<调试排错 - Java 线程分析之线程Dump分析>,作者:龙哥手记. Thread Dump是 ...
- 2022年8月20,第一组,周鹏,从1到m中随机取n个数,n<=m,显示出所有取法
static Random a1 =new Random(); static int m = a1.nextInt(20)+1;//随机取一个1到20的值 static int n = a1.next ...
- APP上架因收集个人信息问题被拒绝该怎么解决?
近年来,随着信息技术的快速发展和移动互联网应用的普及,越来越多的应用大量收集.使用个人信息,给人们生活带来便利的同时,也出现了对个人信息的非法收集.滥用.泄漏等问题,个人信息安全面临严重威胁. 201 ...
- CentOS 7安装mysql5.7-单节点&主从
一 下载 Mysql5.7下载地址:https://dev.mysql.com/downloads/mysql/5.7.html#downloads Mysql精细版本存档版本下载地址:https:/ ...
- 算法之倍增和LCA:论点与点之间的攀亲戚
前言 我们在做树形题和图论题时常常遇到这样的问题:要求求出树上两点间的最近公共祖先(LCA),这时我们该怎么办? 思路一:暴力爬爬爬-- 很容易想到让两个点都往上爬,啥时候相遇了就是他们的最近公共祖先 ...
- 联邦学习(Federated Learning)
联邦学习的思想概括为:一种无需交换数据(只交换训练中间参数或结果)的分布式机器学习技术,在保护数据隐私的同时实现数据共享,解决数据孤岛问题. 本文仅介绍基本概念,详细请查看文末参考资料. 基本概念 联 ...
- vulnhub靶场之DIGITALWORLD.LOCAL: VENGEANCE
准备: 攻击机:虚拟机kali.本机win10. 靶机:digitalworld.local: VENGEANCE,下载地址:https://download.vulnhub.com/digitalw ...
- MySQL 如何实现数据插入
使用MySQL插入数据时,可以根据需求场景选择合适的插入语句,例如当数据重复时如何插入数据,如何从另一个表导入数据,如何批量插入数据等场景.本文通过给出每个使用场景下的实例来说明数据插入的实现过程和方 ...