//------------------------------------------------------------ // 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); } } } }