XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEExtension.NetCore.MAUI.Audio

【DLL】简化安卓录制和播放音频的操作

公开
关注 0 Fork 0 Star 0
UTF-8
#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);
    }
}