//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 loyalsoft. All rights reserved.
// Homepage: http://www.game7000.com/
// Feedback: http://www.game7000.com/
//------------------------------------------------------------
using GameFramework.Resource;
using System;
using System.Collections.Generic;
namespace GameFramework.Sound
{
///
/// 声音管理器。
///
internal sealed partial class SoundManager : GameFrameworkModule, ISoundManager
{
private readonly Dictionary m_SoundGroups;
private readonly List m_SoundsBeingLoaded;
private readonly HashSet m_SoundsToReleaseOnLoad;
private readonly LoadAssetCallbacks m_LoadAssetCallbacks;
private IResourceManager m_ResourceManager;
private ISoundHelper m_SoundHelper;
private int m_Serial;
private EventHandler m_PlaySoundSuccessEventHandler;
private EventHandler m_PlaySoundFailureEventHandler;
private EventHandler m_PlaySoundUpdateEventHandler;
private EventHandler m_PlaySoundDependencyAssetEventHandler;
///
/// 初始化声音管理器的新实例。
///
public SoundManager()
{
m_SoundGroups = new Dictionary(StringComparer.Ordinal);
m_SoundsBeingLoaded = new List();
m_SoundsToReleaseOnLoad = new HashSet();
m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetFailureCallback, LoadAssetUpdateCallback, LoadAssetDependencyAssetCallback);
m_ResourceManager = null;
m_SoundHelper = null;
m_Serial = 0;
m_PlaySoundSuccessEventHandler = null;
m_PlaySoundFailureEventHandler = null;
m_PlaySoundUpdateEventHandler = null;
m_PlaySoundDependencyAssetEventHandler = null;
}
///
/// 获取声音组数量。
///
public int SoundGroupCount
{
get
{
return m_SoundGroups.Count;
}
}
///
/// 播放声音成功事件。
///
public event EventHandler PlaySoundSuccess
{
add
{
m_PlaySoundSuccessEventHandler += value;
}
remove
{
m_PlaySoundSuccessEventHandler -= value;
}
}
///
/// 播放声音失败事件。
///
public event EventHandler PlaySoundFailure
{
add
{
m_PlaySoundFailureEventHandler += value;
}
remove
{
m_PlaySoundFailureEventHandler -= value;
}
}
///
/// 播放声音更新事件。
///
public event EventHandler PlaySoundUpdate
{
add
{
m_PlaySoundUpdateEventHandler += value;
}
remove
{
m_PlaySoundUpdateEventHandler -= value;
}
}
///
/// 播放声音时加载依赖资源事件。
///
public event EventHandler PlaySoundDependencyAsset
{
add
{
m_PlaySoundDependencyAssetEventHandler += value;
}
remove
{
m_PlaySoundDependencyAssetEventHandler -= value;
}
}
///
/// 声音管理器轮询。
///
/// 逻辑流逝时间,以秒为单位。
/// 真实流逝时间,以秒为单位。
internal override void Update(float elapseSeconds, float realElapseSeconds)
{
}
///
/// 关闭并清理声音管理器。
///
internal override void Shutdown()
{
StopAllLoadedSounds();
m_SoundGroups.Clear();
m_SoundsBeingLoaded.Clear();
m_SoundsToReleaseOnLoad.Clear();
}
///
/// 设置资源管理器。
///
/// 资源管理器。
public void SetResourceManager(IResourceManager resourceManager)
{
if (resourceManager == null)
{
throw new GameFrameworkException("Resource manager is invalid.");
}
m_ResourceManager = resourceManager;
}
///
/// 设置声音辅助器。
///
/// 声音辅助器。
public void SetSoundHelper(ISoundHelper soundHelper)
{
if (soundHelper == null)
{
throw new GameFrameworkException("Sound helper is invalid.");
}
m_SoundHelper = soundHelper;
}
///
/// 是否存在指定声音组。
///
/// 声音组名称。
/// 指定声音组是否存在。
public bool HasSoundGroup(string soundGroupName)
{
if (string.IsNullOrEmpty(soundGroupName))
{
throw new GameFrameworkException("Sound group name is invalid.");
}
return m_SoundGroups.ContainsKey(soundGroupName);
}
///
/// 获取指定声音组。
///
/// 声音组名称。
/// 要获取的声音组。
public ISoundGroup GetSoundGroup(string soundGroupName)
{
if (string.IsNullOrEmpty(soundGroupName))
{
throw new GameFrameworkException("Sound group name is invalid.");
}
SoundGroup soundGroup = null;
if (m_SoundGroups.TryGetValue(soundGroupName, out soundGroup))
{
return soundGroup;
}
return null;
}
///
/// 获取所有声音组。
///
/// 所有声音组。
public ISoundGroup[] GetAllSoundGroups()
{
int index = 0;
ISoundGroup[] results = new ISoundGroup[m_SoundGroups.Count];
foreach (KeyValuePair soundGroup in m_SoundGroups)
{
results[index++] = soundGroup.Value;
}
return results;
}
///
/// 获取所有声音组。
///
/// 所有声音组。
public void GetAllSoundGroups(List results)
{
if (results == null)
{
throw new GameFrameworkException("Results is invalid.");
}
results.Clear();
foreach (KeyValuePair soundGroup in m_SoundGroups)
{
results.Add(soundGroup.Value);
}
}
///
/// 增加声音组。
///
/// 声音组名称。
/// 声音组辅助器。
/// 是否增加声音组成功。
public bool AddSoundGroup(string soundGroupName, ISoundGroupHelper soundGroupHelper)
{
return AddSoundGroup(soundGroupName, false, Constant.DefaultMute, Constant.DefaultVolume, soundGroupHelper);
}
///
/// 增加声音组。
///
/// 声音组名称。
/// 声音组中的声音是否避免被同优先级声音替换。
/// 声音组是否静音。
/// 声音组音量。
/// 声音组辅助器。
/// 是否增加声音组成功。
public bool AddSoundGroup(string soundGroupName, bool soundGroupAvoidBeingReplacedBySamePriority, bool soundGroupMute, float soundGroupVolume, ISoundGroupHelper soundGroupHelper)
{
if (string.IsNullOrEmpty(soundGroupName))
{
throw new GameFrameworkException("Sound group name is invalid.");
}
if (soundGroupHelper == null)
{
throw new GameFrameworkException("Sound group helper is invalid.");
}
if (HasSoundGroup(soundGroupName))
{
return false;
}
SoundGroup soundGroup = new SoundGroup(soundGroupName, soundGroupHelper)
{
AvoidBeingReplacedBySamePriority = soundGroupAvoidBeingReplacedBySamePriority,
Mute = soundGroupMute,
Volume = soundGroupVolume
};
m_SoundGroups.Add(soundGroupName, soundGroup);
return true;
}
///
/// 增加声音代理辅助器。
///
/// 声音组名称。
/// 要增加的声音代理辅助器。
public void AddSoundAgentHelper(string soundGroupName, ISoundAgentHelper soundAgentHelper)
{
if (m_SoundHelper == null)
{
throw new GameFrameworkException("You must set sound helper first.");
}
SoundGroup soundGroup = (SoundGroup)GetSoundGroup(soundGroupName);
if (soundGroup == null)
{
throw new GameFrameworkException(Utility.Text.Format("Sound group '{0}' is not exist.", soundGroupName));
}
soundGroup.AddSoundAgentHelper(m_SoundHelper, soundAgentHelper);
}
///
/// 获取所有正在加载声音的序列编号。
///
/// 所有正在加载声音的序列编号。
public int[] GetAllLoadingSoundSerialIds()
{
return m_SoundsBeingLoaded.ToArray();
}
///
/// 获取所有正在加载声音的序列编号。
///
/// 所有正在加载声音的序列编号。
public void GetAllLoadingSoundSerialIds(List results)
{
if (results == null)
{
throw new GameFrameworkException("Results is invalid.");
}
results.Clear();
results.AddRange(m_SoundsBeingLoaded);
}
///
/// 是否正在加载声音。
///
/// 声音序列编号。
/// 是否正在加载声音。
public bool IsLoadingSound(int serialId)
{
return m_SoundsBeingLoaded.Contains(serialId);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName)
{
return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, null, null);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 加载声音资源的优先级。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, int priority)
{
return PlaySound(soundAssetName, soundGroupName, priority, null, null);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 播放声音参数。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams)
{
return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, playSoundParams, null);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 用户自定义数据。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, object userData)
{
return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, null, userData);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 加载声音资源的优先级。
/// 播放声音参数。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, int priority, PlaySoundParams playSoundParams)
{
return PlaySound(soundAssetName, soundGroupName, priority, playSoundParams, null);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 加载声音资源的优先级。
/// 用户自定义数据。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, int priority, object userData)
{
return PlaySound(soundAssetName, soundGroupName, priority, null, userData);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 播放声音参数。
/// 用户自定义数据。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, PlaySoundParams playSoundParams, object userData)
{
return PlaySound(soundAssetName, soundGroupName, Resource.Constant.DefaultPriority, playSoundParams, userData);
}
///
/// 播放声音。
///
/// 声音资源名称。
/// 声音组名称。
/// 加载声音资源的优先级。
/// 播放声音参数。
/// 用户自定义数据。
/// 声音的序列编号。
public int PlaySound(string soundAssetName, string soundGroupName, int priority, PlaySoundParams playSoundParams, object userData)
{
if (m_ResourceManager == null)
{
throw new GameFrameworkException("You must set resource manager first.");
}
if (m_SoundHelper == null)
{
throw new GameFrameworkException("You must set sound helper first.");
}
if (playSoundParams == null)
{
playSoundParams = PlaySoundParams.Create();
}
int serialId = ++m_Serial;
PlaySoundErrorCode? errorCode = null;
string errorMessage = null;
SoundGroup soundGroup = (SoundGroup)GetSoundGroup(soundGroupName);
if (soundGroup == null)
{
errorCode = PlaySoundErrorCode.SoundGroupNotExist;
errorMessage = Utility.Text.Format("Sound group '{0}' is not exist.", soundGroupName);
}
else if (soundGroup.SoundAgentCount <= 0)
{
errorCode = PlaySoundErrorCode.SoundGroupHasNoAgent;
errorMessage = Utility.Text.Format("Sound group '{0}' is have no sound agent.", soundGroupName);
}
if (errorCode.HasValue)
{
if (m_PlaySoundFailureEventHandler != null)
{
PlaySoundFailureEventArgs playSoundFailureEventArgs = PlaySoundFailureEventArgs.Create(serialId, soundAssetName, soundGroupName, playSoundParams, errorCode.Value, errorMessage, userData);
m_PlaySoundFailureEventHandler(this, playSoundFailureEventArgs);
ReferencePool.Release(playSoundFailureEventArgs);
if (playSoundParams.Referenced)
{
ReferencePool.Release(playSoundParams);
}
return serialId;
}
throw new GameFrameworkException(errorMessage);
}
m_SoundsBeingLoaded.Add(serialId);
m_ResourceManager.LoadAsset(soundAssetName, priority, m_LoadAssetCallbacks, PlaySoundInfo.Create(serialId, soundGroup, playSoundParams, userData));
return serialId;
}
///
/// 停止播放声音。
///
/// 要停止播放声音的序列编号。
/// 是否停止播放声音成功。
public bool StopSound(int serialId)
{
return StopSound(serialId, Constant.DefaultFadeOutSeconds);
}
///
/// 停止播放声音。
///
/// 要停止播放声音的序列编号。
/// 声音淡出时间,以秒为单位。
/// 是否停止播放声音成功。
public bool StopSound(int serialId, float fadeOutSeconds)
{
if (IsLoadingSound(serialId))
{
m_SoundsToReleaseOnLoad.Add(serialId);
m_SoundsBeingLoaded.Remove(serialId);
return true;
}
foreach (KeyValuePair soundGroup in m_SoundGroups)
{
if (soundGroup.Value.StopSound(serialId, fadeOutSeconds))
{
return true;
}
}
return false;
}
///
/// 停止所有已加载的声音。
///
public void StopAllLoadedSounds()
{
StopAllLoadedSounds(Constant.DefaultFadeOutSeconds);
}
///
/// 停止所有已加载的声音。
///
/// 声音淡出时间,以秒为单位。
public void StopAllLoadedSounds(float fadeOutSeconds)
{
foreach (KeyValuePair soundGroup in m_SoundGroups)
{
soundGroup.Value.StopAllLoadedSounds(fadeOutSeconds);
}
}
///
/// 停止所有正在加载的声音。
///
public void StopAllLoadingSounds()
{
foreach (int serialId in m_SoundsBeingLoaded)
{
m_SoundsToReleaseOnLoad.Add(serialId);
}
}
///
/// 暂停播放声音。
///
/// 要暂停播放声音的序列编号。
public void PauseSound(int serialId)
{
PauseSound(serialId, Constant.DefaultFadeOutSeconds);
}
///
/// 暂停播放声音。
///
/// 要暂停播放声音的序列编号。
/// 声音淡出时间,以秒为单位。
public void PauseSound(int serialId, float fadeOutSeconds)
{
foreach (KeyValuePair soundGroup in m_SoundGroups)
{
if (soundGroup.Value.PauseSound(serialId, fadeOutSeconds))
{
return;
}
}
throw new GameFrameworkException(Utility.Text.Format("Can not find sound '{0}'.", serialId));
}
///
/// 恢复播放声音。
///
/// 要恢复播放声音的序列编号。
public void ResumeSound(int serialId)
{
ResumeSound(serialId, Constant.DefaultFadeInSeconds);
}
///
/// 恢复播放声音。
///
/// 要恢复播放声音的序列编号。
/// 声音淡入时间,以秒为单位。
public void ResumeSound(int serialId, float fadeInSeconds)
{
foreach (KeyValuePair soundGroup in m_SoundGroups)
{
if (soundGroup.Value.ResumeSound(serialId, fadeInSeconds))
{
return;
}
}
throw new GameFrameworkException(Utility.Text.Format("Can not find sound '{0}'.", serialId));
}
private void LoadAssetSuccessCallback(string soundAssetName, object soundAsset, float duration, object userData)
{
PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData;
if (playSoundInfo == null)
{
throw new GameFrameworkException("Play sound info is invalid.");
}
if (m_SoundsToReleaseOnLoad.Contains(playSoundInfo.SerialId))
{
m_SoundsToReleaseOnLoad.Remove(playSoundInfo.SerialId);
if (playSoundInfo.PlaySoundParams.Referenced)
{
ReferencePool.Release(playSoundInfo.PlaySoundParams);
}
ReferencePool.Release(playSoundInfo);
m_SoundHelper.ReleaseSoundAsset(soundAsset);
return;
}
m_SoundsBeingLoaded.Remove(playSoundInfo.SerialId);
PlaySoundErrorCode? errorCode = null;
ISoundAgent soundAgent = playSoundInfo.SoundGroup.PlaySound(playSoundInfo.SerialId, soundAsset, playSoundInfo.PlaySoundParams, out errorCode);
if (soundAgent != null)
{
if (m_PlaySoundSuccessEventHandler != null)
{
PlaySoundSuccessEventArgs playSoundSuccessEventArgs = PlaySoundSuccessEventArgs.Create(playSoundInfo.SerialId, soundAssetName, soundAgent, duration, playSoundInfo.UserData);
m_PlaySoundSuccessEventHandler(this, playSoundSuccessEventArgs);
ReferencePool.Release(playSoundSuccessEventArgs);
}
if (playSoundInfo.PlaySoundParams.Referenced)
{
ReferencePool.Release(playSoundInfo.PlaySoundParams);
}
ReferencePool.Release(playSoundInfo);
return;
}
m_SoundsToReleaseOnLoad.Remove(playSoundInfo.SerialId);
m_SoundHelper.ReleaseSoundAsset(soundAsset);
string errorMessage = Utility.Text.Format("Sound group '{0}' play sound '{1}' failure.", playSoundInfo.SoundGroup.Name, soundAssetName);
if (m_PlaySoundFailureEventHandler != null)
{
PlaySoundFailureEventArgs playSoundFailureEventArgs = PlaySoundFailureEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, errorCode.Value, errorMessage, playSoundInfo.UserData);
m_PlaySoundFailureEventHandler(this, playSoundFailureEventArgs);
ReferencePool.Release(playSoundFailureEventArgs);
if (playSoundInfo.PlaySoundParams.Referenced)
{
ReferencePool.Release(playSoundInfo.PlaySoundParams);
}
ReferencePool.Release(playSoundInfo);
return;
}
if (playSoundInfo.PlaySoundParams.Referenced)
{
ReferencePool.Release(playSoundInfo.PlaySoundParams);
}
ReferencePool.Release(playSoundInfo);
throw new GameFrameworkException(errorMessage);
}
private void LoadAssetFailureCallback(string soundAssetName, LoadResourceStatus status, string errorMessage, object userData)
{
PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData;
if (playSoundInfo == null)
{
throw new GameFrameworkException("Play sound info is invalid.");
}
if (m_SoundsToReleaseOnLoad.Contains(playSoundInfo.SerialId))
{
m_SoundsToReleaseOnLoad.Remove(playSoundInfo.SerialId);
if (playSoundInfo.PlaySoundParams.Referenced)
{
ReferencePool.Release(playSoundInfo.PlaySoundParams);
}
return;
}
m_SoundsBeingLoaded.Remove(playSoundInfo.SerialId);
string appendErrorMessage = Utility.Text.Format("Load sound failure, asset name '{0}', status '{1}', error message '{2}'.", soundAssetName, status, errorMessage);
if (m_PlaySoundFailureEventHandler != null)
{
PlaySoundFailureEventArgs playSoundFailureEventArgs = PlaySoundFailureEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, PlaySoundErrorCode.LoadAssetFailure, appendErrorMessage, playSoundInfo.UserData);
m_PlaySoundFailureEventHandler(this, playSoundFailureEventArgs);
ReferencePool.Release(playSoundFailureEventArgs);
if (playSoundInfo.PlaySoundParams.Referenced)
{
ReferencePool.Release(playSoundInfo.PlaySoundParams);
}
return;
}
throw new GameFrameworkException(appendErrorMessage);
}
private void LoadAssetUpdateCallback(string soundAssetName, float progress, object userData)
{
PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData;
if (playSoundInfo == null)
{
throw new GameFrameworkException("Play sound info is invalid.");
}
if (m_PlaySoundUpdateEventHandler != null)
{
PlaySoundUpdateEventArgs playSoundUpdateEventArgs = PlaySoundUpdateEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, progress, playSoundInfo.UserData);
m_PlaySoundUpdateEventHandler(this, playSoundUpdateEventArgs);
ReferencePool.Release(playSoundUpdateEventArgs);
}
}
private void LoadAssetDependencyAssetCallback(string soundAssetName, string dependencyAssetName, int loadedCount, int totalCount, object userData)
{
PlaySoundInfo playSoundInfo = (PlaySoundInfo)userData;
if (playSoundInfo == null)
{
throw new GameFrameworkException("Play sound info is invalid.");
}
if (m_PlaySoundDependencyAssetEventHandler != null)
{
PlaySoundDependencyAssetEventArgs playSoundDependencyAssetEventArgs = PlaySoundDependencyAssetEventArgs.Create(playSoundInfo.SerialId, soundAssetName, playSoundInfo.SoundGroup.Name, playSoundInfo.PlaySoundParams, dependencyAssetName, loadedCount, totalCount, playSoundInfo.UserData);
m_PlaySoundDependencyAssetEventHandler(this, playSoundDependencyAssetEventArgs);
ReferencePool.Release(playSoundDependencyAssetEventArgs);
}
}
}
}