可能的性能优化
This commit is contained in:
@@ -62,19 +62,12 @@ namespace OCES.Audio
|
||||
{
|
||||
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
|
||||
float outgoingVolume = this.m_fader.CurrentVolume;
|
||||
float fadeOutOffSet = transition?.FadeOutOffset ?? 0f;
|
||||
float fadeOutTime = transition?.FadeOutTime ?? 0f;
|
||||
float fadeInOffSet = transition?.FadeInOffset ?? 0f;
|
||||
float fadeInTime = transition?.FadeInTime ?? 0f;
|
||||
|
||||
// ContainerPlayHandle outgoingHandle = this.m_currentHandle;
|
||||
// float outgoingVolume = this.m_currentVolume;
|
||||
|
||||
this.m_coroutineHost.StartCoroutine(
|
||||
this.m_fader.FadeOutBranch(outgoing, outgoingVolume,fadeOutOffSet, fadeOutTime));
|
||||
this.m_fader.FadeOutBranch(outgoing, outgoingVolume, transition));
|
||||
|
||||
yield return this.m_coroutineHost.StartCoroutine(
|
||||
this.m_fader.FadeInBranch(newContainerId, fadeInOffSet, fadeInTime));
|
||||
this.m_fader.FadeInBranch(newContainerId, transition));
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
@@ -18,11 +18,15 @@ namespace OCES.Audio
|
||||
readonly Dictionary<uint, int> m_clipConcurrentCount = new();
|
||||
readonly List<ActiveSound> m_activeSounds = new();
|
||||
|
||||
// 复用列表,避免 TryPlay 每帧分配临时 List(原 LINQ .Where().ToList())
|
||||
readonly List<ActiveSound> m_tempSameObject = new();
|
||||
readonly List<ActiveSound> m_tempSameGroup = new();
|
||||
readonly List<ActiveSound> m_tempLowerPriority = new();
|
||||
|
||||
AudioGroupConfig m_groupConfig;
|
||||
AudioMixerGroup m_sfxGroup;
|
||||
AudioMixerGroup m_musicGroup;
|
||||
AudioMixerGroup m_voiceGroup;
|
||||
AudioMixerGroup m_ambienceGroup;
|
||||
AudioSourcePool m_pool;
|
||||
AudioContainerSelector m_containerSelector;
|
||||
PitchStepManager m_pitchStepManager;
|
||||
@@ -60,8 +64,6 @@ namespace OCES.Audio
|
||||
|
||||
AudioMixerGroup[] sfx = Find("Master/SFX");
|
||||
if (sfx.Length > 0) this.m_sfxGroup = sfx[0];
|
||||
AudioMixerGroup[] ambience = Find("Master/SFX/Ambience");
|
||||
if (ambience.Length > 0) this.m_ambienceGroup = ambience[0];
|
||||
AudioMixerGroup[] voice = Find("Master/Voice");
|
||||
if (voice.Length > 0) this.m_voiceGroup = voice[0];
|
||||
return;
|
||||
@@ -87,15 +89,20 @@ namespace OCES.Audio
|
||||
|
||||
// 第二层:单 AudioObject/Clip 并发控制
|
||||
if (audioObject.ThrottleCount != 0)
|
||||
{ // TODO 这里和下面的组控制,每次都会分配新List,可以考虑做成成员变量,每次用完clear
|
||||
// TODO Linq表达式好用但是GC性能差。如果性能有问题可以考虑换成普通表达
|
||||
List<ActiveSound> sameObject = this.m_activeSounds
|
||||
.Where(a => a.AudioObject.Id == audioObject.Id)
|
||||
.ToList();
|
||||
{
|
||||
this.m_tempSameObject.Clear();
|
||||
foreach (ActiveSound activeSound in this.m_activeSounds)
|
||||
{
|
||||
if (activeSound.AudioObject.Id == audioObject.Id)
|
||||
{
|
||||
this.m_tempSameObject.Add(activeSound);
|
||||
}
|
||||
}
|
||||
|
||||
if (sameObject.Count >= audioObject.ThrottleCount &&
|
||||
!TryKill(sameObject, audioObject.KillMode, $"[Object] {audioObject.Name[0]}"))
|
||||
if (this.m_tempSameObject.Count >= audioObject.ThrottleCount &&
|
||||
!TryKill(this.m_tempSameObject, audioObject.KillMode, $"[Object] {audioObject.Name[0]}"))
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
// 第三层:Group 并发控制
|
||||
@@ -105,18 +112,28 @@ namespace OCES.Audio
|
||||
groupConfig = this.m_groupConfig.QueryById(1);
|
||||
Debug.Log($"未找到{audioObject.Id}对应的组文件,已使用默认配置组1。");
|
||||
}
|
||||
List<ActiveSound> sameGroup = this.m_activeSounds
|
||||
.Where(a => a.AudioObject.Group == audioObject.Group)
|
||||
.ToList();
|
||||
|
||||
if (sameGroup.Count >= groupConfig.GroupThrottleCount)
|
||||
this.m_tempSameGroup.Clear();
|
||||
foreach (ActiveSound activeSound in this.m_activeSounds)
|
||||
{
|
||||
List<ActiveSound> lowerPriority = sameGroup
|
||||
.Where(a => a.AudioObject.Priority > audioObject.Priority)
|
||||
.ToList();
|
||||
if (activeSound.AudioObject.Group == audioObject.Group)
|
||||
{
|
||||
this.m_tempSameGroup.Add(activeSound);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_tempSameGroup.Count >= groupConfig.GroupThrottleCount)
|
||||
{
|
||||
this.m_tempLowerPriority.Clear();
|
||||
foreach (ActiveSound activeSound in this.m_tempSameGroup)
|
||||
{
|
||||
if (activeSound.AudioObject.Priority > audioObject.Priority)
|
||||
{
|
||||
this.m_tempLowerPriority.Add(activeSound);
|
||||
}
|
||||
}
|
||||
|
||||
List<ActiveSound> killCandidates = lowerPriority.Count > 0 ? lowerPriority : sameGroup;
|
||||
KillMode killMode = lowerPriority.Count > 0 ? groupConfig.KillMode : audioObject.KillMode;
|
||||
List<ActiveSound> killCandidates = this.m_tempLowerPriority.Count > 0 ? this.m_tempLowerPriority : this.m_tempSameGroup;
|
||||
KillMode killMode = this.m_tempLowerPriority.Count > 0 ? groupConfig.KillMode : audioObject.KillMode;
|
||||
|
||||
if (!TryKill(killCandidates, killMode, $"[Group] {audioObject.Name[0]}"))
|
||||
return;
|
||||
@@ -125,11 +142,16 @@ namespace OCES.Audio
|
||||
// 第四层:全局并发控制
|
||||
if (this.m_activeSounds.Count >= k_maxGlobalConcurrent)
|
||||
{
|
||||
List<ActiveSound> lowerPriority = this.m_activeSounds
|
||||
.Where(a => a.AudioObject.Priority > audioObject.Priority)
|
||||
.ToList();
|
||||
this.m_tempLowerPriority.Clear();
|
||||
foreach (ActiveSound activeSound in this.m_activeSounds)
|
||||
{
|
||||
if (activeSound.AudioObject.Priority > audioObject.Priority)
|
||||
{
|
||||
this.m_tempLowerPriority.Add(activeSound);
|
||||
}
|
||||
}
|
||||
|
||||
if (lowerPriority.Count == 0 || !TryKill(lowerPriority, KillMode.Oldest, "[Global]"))
|
||||
if (this.m_tempLowerPriority.Count == 0 || !TryKill(this.m_tempLowerPriority, KillMode.Oldest, "[Global]"))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,19 +46,19 @@ namespace OCES.Audio
|
||||
/// <summary>
|
||||
/// 淡出分支:fire-and-forget,由调用方 StartCoroutine
|
||||
/// </summary>
|
||||
internal IEnumerator FadeOutBranch(ContainerPlayHandle outgoingHandle, float outgoingVolume, float fadeOutOffset, float fadeOutTime)
|
||||
internal IEnumerator FadeOutBranch(ContainerPlayHandle outgoingHandle, float outgoingVolume, ITransitionConfig transition)
|
||||
{
|
||||
if (outgoingHandle == null) yield break;
|
||||
|
||||
if (fadeOutOffset > 0f)
|
||||
if (transition?.FadeOutOffset > 0f)
|
||||
{
|
||||
Debug.Log($"Waiting for {fadeOutOffset} to fade out.");
|
||||
yield return new WaitForSeconds(fadeOutOffset);
|
||||
Debug.Log($"Waiting for {transition.FadeOutOffset} to fade out.");
|
||||
yield return new WaitForSeconds(transition.FadeOutOffset);
|
||||
}
|
||||
|
||||
if (fadeOutTime > 0f )
|
||||
if (transition?.FadeOutTime > 0f )
|
||||
yield return this.m_coroutineHost.StartCoroutine(
|
||||
FadeOut(outgoingHandle, outgoingVolume, fadeOutTime));
|
||||
FadeOut(outgoingHandle, outgoingVolume, transition.FadeOutTime));
|
||||
else
|
||||
StopHandle(outgoingHandle);
|
||||
}
|
||||
@@ -67,12 +67,12 @@ namespace OCES.Audio
|
||||
/// 淡入分支:等待 FadeInOffset 后启动新音乐并淡入。
|
||||
/// 主协程 yield return 此分支,以便 DoTransition 在新音乐就绪后才结束。
|
||||
/// </summary>
|
||||
internal IEnumerator FadeInBranch(uint newContainerId, float fadeInOffset, float fadeInTime, Action onContainerStarted = null)
|
||||
internal IEnumerator FadeInBranch(uint newContainerId, ITransitionConfig transition, Action onContainerStarted = null)
|
||||
{
|
||||
if (fadeInOffset > 0f)
|
||||
if (transition?.FadeOutOffset > 0f)
|
||||
{
|
||||
Debug.Log($"Waiting {fadeInOffset} to fade in.");
|
||||
yield return new WaitForSeconds(fadeInOffset);
|
||||
Debug.Log($"Waiting {transition.FadeInOffset} to fade in.");
|
||||
yield return new WaitForSeconds(transition.FadeInOffset);
|
||||
}
|
||||
|
||||
if (newContainerId == 0)
|
||||
@@ -82,13 +82,13 @@ namespace OCES.Audio
|
||||
yield break;
|
||||
}
|
||||
|
||||
float startVolume = fadeInTime > 0f ? 0f : 1f;
|
||||
float startVolume = transition?.FadeOutOffset > 0f ? 0f : 1f;
|
||||
StartNew(newContainerId, startVolume);
|
||||
|
||||
if (fadeInTime > 0f )
|
||||
if (transition?.FadeOutOffset > 0f)
|
||||
{
|
||||
yield return this.m_coroutineHost.StartCoroutine(
|
||||
FadeIn(CurrentHandle, fadeInTime));
|
||||
FadeIn(CurrentHandle, transition.FadeInTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+27
@@ -62,4 +62,31 @@ namespace OCES.Audio
|
||||
void DeSerialize(BinaryReader reader);
|
||||
void Serialize(BinaryWriter writer);
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// 辅助接口,让泛型方法同时处理 MusicPath 和 AmbiencePath
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
public interface IPathEntry
|
||||
{
|
||||
uint Id { get; }
|
||||
string Path { get; }
|
||||
uint ContainerId { get; }
|
||||
int Priority { get; }
|
||||
}
|
||||
|
||||
public interface ITransitionConfig
|
||||
{
|
||||
float FadeOutOffset { get; }
|
||||
float FadeOutTime { get; }
|
||||
float FadeInOffset { get; }
|
||||
float FadeInTime { get; }
|
||||
}
|
||||
|
||||
public partial class MusicTransition : ITransitionConfig { }
|
||||
public partial class AmbienceTransition : ITransitionConfig { }
|
||||
|
||||
|
||||
public partial class MusicPath : IPathEntry { }
|
||||
public partial class AmbiencePath : IPathEntry { }
|
||||
}
|
||||
@@ -89,16 +89,12 @@ namespace OCES.Audio
|
||||
// ── 2 & 3. 淡出与淡入并行:两条分支从同一时刻起算各自的 Offset,互不等待 ──
|
||||
ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
|
||||
float outVol = this.m_fader.CurrentVolume;
|
||||
float fadeOutOffset = transition?.FadeOutOffset ?? 0f;
|
||||
float fadeOutTime = transition?.FadeOutTime ?? 0f;
|
||||
float fadeInOffset = transition?.FadeInOffset ?? 0f;
|
||||
float fadeInTime = transition?.FadeInTime ?? 0f;
|
||||
|
||||
this.m_coroutineHost.StartCoroutine(
|
||||
this.m_fader.FadeOutBranch(outgoing, outVol, fadeOutOffset, fadeOutTime));
|
||||
this.m_fader.FadeOutBranch(outgoing, outVol, transition));
|
||||
|
||||
yield return this.m_coroutineHost.StartCoroutine(
|
||||
this.m_fader.FadeInBranch(newContainerId, fadeInOffset, fadeInTime,
|
||||
this.m_fader.FadeInBranch(newContainerId, transition,
|
||||
onContainerStarted: () =>
|
||||
{
|
||||
// Music 独有:记录新 container 和播放起始时间
|
||||
|
||||
@@ -136,19 +136,4 @@ namespace OCES.Audio
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────
|
||||
// 辅助接口,让泛型方法同时处理 MusicPath 和 AmbiencePath
|
||||
// ─────────────────────────────────────────────
|
||||
|
||||
public interface IPathEntry
|
||||
{
|
||||
uint Id { get; }
|
||||
string Path { get; }
|
||||
uint ContainerId { get; }
|
||||
int Priority { get; }
|
||||
}
|
||||
|
||||
public partial class MusicPath : IPathEntry { }
|
||||
public partial class AmbiencePath : IPathEntry { }
|
||||
}
|
||||
Reference in New Issue
Block a user