com.alicizax.unity.framework/Runtime/Audio/AudioClipCacheEntry.cs
陈思海 46194ddee8 重构音频模块 1. 高频、大量音频反复调用时,单帧 CPU 开销与 GC 最优 2. AudioClip / AudioSource 的加载、缓存淘汰、卸载形成完整闭环,避免线性遍历 3. AudioSource 对象池 + 播放请求 struct 全部池化覆盖所有分配点 4. 支持3D环境音并具备距离衰减、遮挡等空间属性 5. 新增音频类型(BGM/SFX/Voice/Ambient) 6. 可调式监控Debug信息 及时跟踪音频缓存 处理 句柄状态
重构音频模块
1. 高频、大量音频反复调用时,单帧 CPU 开销与 GC 最优
2. AudioClip / AudioSource 的加载、缓存淘汰、卸载形成完整闭环,避免线性遍历
3. AudioSource 对象池 + 播放请求 struct 全部池化覆盖所有分配点
4. 支持3D环境音并具备距离衰减、遮挡等空间属性
5. 新增音频类型(BGM/SFX/Voice/Ambient)
6. 可调式监控Debug信息 及时跟踪音频缓存 处理 句柄状态
2026-04-23 17:21:36 +08:00

146 lines
3.9 KiB
C#

using System;
using AlicizaX;
using UnityEngine;
using YooAsset;
namespace AlicizaX.Audio.Runtime
{
internal sealed class AudioClipCacheEntry : IMemory
{
private readonly Action<AssetHandle> _completedCallback;
public AudioService Owner;
public string Address;
public AssetHandle Handle;
public AudioClip Clip;
public AudioLoadRequest PendingHead;
public AudioLoadRequest PendingTail;
public AudioClipCacheEntry LruPrev;
public AudioClipCacheEntry LruNext;
public AudioClipCacheEntry AllPrev;
public AudioClipCacheEntry AllNext;
public int RefCount;
public bool Loading;
public bool Pinned;
public bool CacheAfterUse;
public bool InLru;
public float LastUseTime;
public AudioClipCacheEntry()
{
_completedCallback = OnLoadCompleted;
}
public Action<AssetHandle> CompletedCallback => _completedCallback;
public bool IsLoaded => Clip != null && Handle is { IsValid: true } && !Loading;
public void Initialize(AudioService owner, string address, bool pinned)
{
Owner = owner;
Address = address;
Pinned = pinned;
CacheAfterUse = pinned;
LastUseTime = Time.realtimeSinceStartup;
}
public void AddPending(AudioLoadRequest request)
{
request.Next = null;
if (PendingTail == null)
{
PendingHead = request;
PendingTail = request;
return;
}
PendingTail.Next = request;
PendingTail = request;
}
public int CountPending()
{
int count = 0;
AudioLoadRequest request = PendingHead;
while (request != null)
{
count++;
request = request.Next;
}
return count;
}
public void FillDebugInfo(AudioClipCacheDebugInfo info)
{
if (info == null)
{
return;
}
info.Address = Address;
info.Clip = Clip;
info.RefCount = RefCount;
info.PendingCount = CountPending();
info.Loading = Loading;
info.Pinned = Pinned;
info.CacheAfterUse = CacheAfterUse;
info.InLru = InLru;
info.IsLoaded = IsLoaded;
info.HasValidHandle = Handle is { IsValid: true };
info.LastUseTime = LastUseTime;
}
public void Clear()
{
if (Handle is { IsValid: true })
{
if (Loading)
{
Handle.Completed -= _completedCallback;
}
Handle.Dispose();
}
AudioLoadRequest request = PendingHead;
while (request != null)
{
AudioLoadRequest next = request.Next;
MemoryPool.Release(request);
request = next;
}
Owner = null;
Address = null;
Handle = null;
Clip = null;
PendingHead = null;
PendingTail = null;
LruPrev = null;
LruNext = null;
AllPrev = null;
AllNext = null;
RefCount = 0;
Loading = false;
Pinned = false;
CacheAfterUse = false;
InLru = false;
LastUseTime = 0f;
}
private void OnLoadCompleted(AssetHandle handle)
{
AudioService owner = Owner;
if (owner != null)
{
owner.OnClipLoadCompleted(this, handle);
}
else if (handle is { IsValid: true })
{
handle.Dispose();
}
}
}
}