#if ANDROID
using Android.Media;
#endif
namespace XFEExtension.NetCore.MAUI.Audio;
public class AudioPlayer : IDisposable
{
#if ANDROID
private bool disposedValue;
private AudioTrack audioTrack;
private bool isPlaying;
public bool IsPlaying
{
get => isPlaying;
set
{
if (value)
StartPlayback();
else
StopPlayback();
}
}
public int SampleRate { get; set; } = 44100;
public ChannelOut ChannelConfig { get; set; } = ChannelOut.Mono;
public Encoding AudioFormat { get; set; } = Encoding.Pcm16bit;
public AudioUsageKind AudioUsage { get; set; } = AudioUsageKind.Media;
public AudioContentType AudioContentType { get; set; } = AudioContentType.Music;
public AudioTrackMode AudioTrackMode { get; set; } = AudioTrackMode.Stream;
#endif
public void StartPlayback()
{
#if ANDROID
audioTrack.Play();
isPlaying = true;
#endif
}
public void StopPlayback()
{
#if ANDROID
isPlaying = false;
audioTrack.Stop();
#endif
}
public void PlayAudioData(byte[] audioData)
{
#if ANDROID
if (isPlaying && audioData is not null)
audioTrack.Write(audioData, 0, audioData.Length, WriteMode.NonBlocking);
#endif
}
#if ANDROID
public void PlayAudioData(byte[] audioData, WriteMode writeMode = WriteMode.NonBlocking)
{
if (isPlaying && audioData is not null)
audioTrack.Write(audioData, 0, audioData.Length, writeMode);
}
#endif
private void Initialize()
{
#if ANDROID
int bufferSizeInBytes = AudioTrack.GetMinBufferSize(SampleRate, ChannelConfig, AudioFormat);
var audioAttributes = new AudioAttributes.Builder()
?.SetUsage(AudioUsage)
?.SetContentType(AudioContentType)
?.Build();
audioTrack = new AudioTrack(
audioAttributes,
new AudioFormat.Builder()
?.SetEncoding(AudioFormat)
?.SetSampleRate(SampleRate)
?.SetChannelMask(ChannelConfig)
?.Build(),
bufferSizeInBytes,
AudioTrackMode,
0);
#endif
}
public AudioPlayer() => Initialize();
#if ANDROID
public AudioPlayer(int sampleRate = 44100, ChannelOut channelConfig = ChannelOut.Mono, Encoding audioFormat = Encoding.Pcm16bit, AudioUsageKind audioUsage = AudioUsageKind.Media, AudioContentType audioContentType = AudioContentType.Music, AudioTrackMode audioTrackMode = AudioTrackMode.Stream)
{
SampleRate = sampleRate;
ChannelConfig = channelConfig;
AudioFormat = audioFormat;
AudioUsage = audioUsage;
AudioContentType = audioContentType;
AudioTrackMode = audioTrackMode;
Initialize();
}
#endif
protected virtual void Dispose(bool disposing)
{
#if ANDROID
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)
audioTrack.Release();
}
// TODO: 释放未托管的资源(未托管的对象)并重写终结器
// TODO: 将大型字段设置为 null
disposedValue = true;
}
#endif
}
// // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
// ~AudioPlayer()
// {
// // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
// Dispose(disposing: false);
// }
public void Dispose()
{
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
#if ANDROID
using Android.Media;
#endif
namespace XFEExtension.NetCore.MAUI.Audio;
public class AudioPlayer : IDisposable
{
#if ANDROID
private bool disposedValue;
private AudioTrack audioTrack;
private bool isPlaying;
public bool IsPlaying
{
get => isPlaying;
set
{
if (value)
StartPlayback();
else
StopPlayback();
}
}
public int SampleRate { get; set; } = 44100;
public ChannelOut ChannelConfig { get; set; } = ChannelOut.Mono;
public Encoding AudioFormat { get; set; } = Encoding.Pcm16bit;
public AudioUsageKind AudioUsage { get; set; } = AudioUsageKind.Media;
public AudioContentType AudioContentType { get; set; } = AudioContentType.Music;
public AudioTrackMode AudioTrackMode { get; set; } = AudioTrackMode.Stream;
#endif
public void StartPlayback()
{
#if ANDROID
audioTrack.Play();
isPlaying = true;
#endif
}
public void StopPlayback()
{
#if ANDROID
isPlaying = false;
audioTrack.Stop();
#endif
}
public void PlayAudioData(byte[] audioData)
{
#if ANDROID
if (isPlaying && audioData is not null)
audioTrack.Write(audioData, 0, audioData.Length, WriteMode.NonBlocking);
#endif
}
#if ANDROID
public void PlayAudioData(byte[] audioData, WriteMode writeMode = WriteMode.NonBlocking)
{
if (isPlaying && audioData is not null)
audioTrack.Write(audioData, 0, audioData.Length, writeMode);
}
#endif
private void Initialize()
{
#if ANDROID
int bufferSizeInBytes = AudioTrack.GetMinBufferSize(SampleRate, ChannelConfig, AudioFormat);
var audioAttributes = new AudioAttributes.Builder()
?.SetUsage(AudioUsage)
?.SetContentType(AudioContentType)
?.Build();
audioTrack = new AudioTrack(
audioAttributes,
new AudioFormat.Builder()
?.SetEncoding(AudioFormat)
?.SetSampleRate(SampleRate)
?.SetChannelMask(ChannelConfig)
?.Build(),
bufferSizeInBytes,
AudioTrackMode,
0);
#endif
}
public AudioPlayer() => Initialize();
#if ANDROID
public AudioPlayer(int sampleRate = 44100, ChannelOut channelConfig = ChannelOut.Mono, Encoding audioFormat = Encoding.Pcm16bit, AudioUsageKind audioUsage = AudioUsageKind.Media, AudioContentType audioContentType = AudioContentType.Music, AudioTrackMode audioTrackMode = AudioTrackMode.Stream)
{
SampleRate = sampleRate;
ChannelConfig = channelConfig;
AudioFormat = audioFormat;
AudioUsage = audioUsage;
AudioContentType = audioContentType;
AudioTrackMode = audioTrackMode;
Initialize();
}
#endif
protected virtual void Dispose(bool disposing)
{
#if ANDROID
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)
audioTrack.Release();
}
// TODO: 释放未托管的资源(未托管的对象)并重写终结器
// TODO: 将大型字段设置为 null
disposedValue = true;
}
#endif
}
// // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
// ~AudioPlayer()
// {
// // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
// Dispose(disposing: false);
// }
public void Dispose()
{
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}