2024-12-14 18:27:59 +08:00

348 lines
8.1 KiB
C#

/****************************************************************************
* Copyright (c) 2016 ~ 2024 liangxiegame UNDER MIT LICENSE
*
* https://qframework.cn
* https://github.com/liangxiegame/QFramework
* https://gitee.com/liangxiegame/QFramework
****************************************************************************/
using System;
using UnityEngine;
using Object = UnityEngine.Object;
namespace QFramework
{
public class AudioPlayer : IPoolable, IPoolType,IAudioKitOnFinish
{
private IAudioLoader mLoader;
private AudioSource mAudioSource;
private string mName;
public BindableProperty<float> Volume { get; set; }
public string GetName => mName;
private AudioClip mAudioClip;
private TimeItem mTimeItem;
private Action mOnStart = null;
private Action mOnFinish = null;
private bool mIsPause = false;
private float mLeftDelayTime = -1;
private float mVolumeScale = 1.0f;
private float mVolume;
public AudioSource AudioSource => mAudioSource;
internal static AudioPlayer Allocate(BindableProperty<float> volume)
{
var player = SafeObjectPool<AudioPlayer>.Instance.Allocate();
player.Volume = volume;
player.OnAllocate();
return player;
}
public void OnAllocate()
{
mOnStart = null;
mOnFinish = null;
mVolume = 1.0f;
mVolumeScale = 1.0f;
Volume.RegisterWithInitValue(SetVolume);
}
public AudioPlayer OnStart(Action onStart)
{
if (onStart == null) return this;
if (mOnStart == null)
{
mOnStart = onStart;
}
else
{
mOnStart += onStart;
}
return this;
}
void IAudioKitOnFinish.OnFinish(Action onFinish)
{
if (onFinish == null) return;
if (mOnFinish == null)
{
mOnFinish = onFinish;
}
else
{
mOnFinish += onFinish;
}
}
public bool UsedCache { get; set; } = true;
public bool IsRecycled { get; set; } = false;
public bool IsLoop { get; set; }
public void SetAudioExt(GameObject root, AudioClip clip, string name, bool loop)
{
if (clip == null || mName == name)
{
return;
}
if (mAudioSource == null)
{
mAudioSource = root.AddComponent<AudioSource>();
}
CleanResources();
IsLoop = loop;
mName = name;
mAudioClip = clip;
PlayAudioClip();
}
public AudioPlayer SetAudio(GameObject root, string name, bool loop)
{
if (string.IsNullOrEmpty(name))
{
return this;
}
if (mName == name)
{
return this;
}
if (mAudioSource == null)
{
mAudioSource = root.AddComponent<AudioSource>();
}
//防止卸载后立马加载的情况
var preLoader = mLoader;
mLoader = null;
CleanResources();
mLoader = AudioKit.Config.AudioLoaderPool.AllocateLoader();
IsLoop = loop;
mName = name;
var keys = AudioSearchKeys.Allocate();
keys.AssetName = name;
mLoader.LoadClipAsync(keys, OnResLoadFinish);
keys.Recycle2Cache();
if (preLoader != null)
{
preLoader.Unload();
AudioKit.Config.AudioLoaderPool.RecycleLoader(preLoader);
preLoader = null;
}
return this;
}
public void Stop()
{
Release();
}
public void Pause()
{
if (mIsPause)
{
return;
}
mLeftDelayTime = -1;
//暂停
if (mTimeItem != null)
{
mLeftDelayTime = mTimeItem.SortScore - Timer.Instance.CurrentScaleTime;
mTimeItem.Cancel();
mTimeItem = null;
}
mIsPause = true;
mAudioSource.Pause();
}
public void Resume()
{
if (!mIsPause)
{
return;
}
if (mLeftDelayTime >= 0)
{
mTimeItem = Timer.Instance.Post2Scale(OnResumeTimeTick, mLeftDelayTime);
}
mIsPause = false;
mAudioSource.Play();
}
public AudioPlayer VolumeScale(float volumeScale)
{
mVolumeScale = volumeScale;
UpdateVolume();
return this;
}
void SetVolume(float volume)
{
mVolume = volume;
UpdateVolume();
}
void UpdateVolume()
{
if (mAudioSource)
{
mAudioSource.volume = mVolume * mVolumeScale;
}
}
private void OnResLoadFinish(bool result, AudioClip clip)
{
if (!result)
{
Release();
return;
}
mAudioClip = clip;
if (mAudioClip == null)
{
Debug.LogError("Asset Is Invalid AudioClip:" + mName);
Release();
return;
}
PlayAudioClip();
}
private void PlayAudioClip()
{
if (mAudioSource == null || mAudioClip == null)
{
Release();
return;
}
mAudioSource.clip = mAudioClip;
mAudioSource.loop = IsLoop;
UpdateVolume();
int loopCount = 1;
if (IsLoop)
{
loopCount = -1;
}
mTimeItem = Timer.Instance.Post2Scale(OnSoundPlayFinish, mAudioClip.length, loopCount);
mOnStart?.Invoke();
mOnStart = null;
mAudioSource.Play();
}
private void OnResumeTimeTick(int repeatCount)
{
OnSoundPlayFinish(repeatCount);
if (IsLoop)
{
mTimeItem = Timer.Instance.Post2Scale(OnSoundPlayFinish, mAudioClip.length, -1);
}
}
private void OnSoundPlayFinish(int count)
{
mOnFinish?.Invoke();
mOnFinish = null;
if (!IsLoop)
{
Release();
}
}
private void Release()
{
CleanResources();
if (UsedCache)
{
Recycle2Cache();
}
}
private void CleanResources()
{
mName = null;
mIsPause = false;
mLeftDelayTime = -1;
if (mTimeItem != null)
{
mTimeItem.Cancel();
mTimeItem = null;
}
if (mAudioSource)
{
if (mAudioSource.clip == mAudioClip)
{
mAudioSource.Stop();
mAudioSource.clip = null;
}
}
mAudioClip = null;
if (mLoader != null)
{
mLoader.Unload();
AudioKit.Config.AudioLoaderPool.RecycleLoader(mLoader);
mLoader = null;
}
}
public void OnRecycled()
{
Volume?.UnRegister(SetVolume);
Volume = null;
CleanResources();
}
public void Recycle2Cache()
{
if (!SafeObjectPool<AudioPlayer>.Instance.Recycle(this))
{
if (mAudioSource != null)
{
Object.Destroy(mAudioSource);
mAudioSource = null;
}
}
}
}
}