AudioKit.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /****************************************************************************
  2. * Copyright (c) 2017 ~ 2021.1 liangxie
  3. *
  4. * http://qframework.io
  5. * https://github.com/liangxiegame/QFramework
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. ****************************************************************************/
  25. using System;
  26. using System.Collections.Generic;
  27. using UnityEngine;
  28. namespace QFramework
  29. {
  30. public class AudioKit
  31. {
  32. /// <summary>
  33. /// 音频相关的设置
  34. /// </summary>
  35. public static readonly AudioKitSettings Settings = new AudioKitSettings();
  36. public static AudioPlayer MusicPlayer
  37. {
  38. get { return AudioManager.Instance.MusicPlayer; }
  39. }
  40. public static AudioKitConfig Config = new AudioKitConfig();
  41. /// <summary>
  42. /// 播放背景音乐
  43. /// </summary>
  44. /// <param name="musicName"></param>
  45. /// <param name="onBeganCallback"></param>
  46. /// <param name="onEndCallback"></param>
  47. /// <param name="loop"></param>
  48. /// <param name="allowMusicOff"></param>
  49. /// <param name="volume"></param>
  50. public static void PlayMusic(string musicName, bool loop = true, System.Action onBeganCallback = null,
  51. System.Action onEndCallback = null, bool allowMusicOff = true, float volume = -1f)
  52. {
  53. AudioManager.Instance.CheckAudioListener();
  54. var audioMgr = AudioManager.Instance;
  55. audioMgr.CurrentMusicName = musicName;
  56. if (!Settings.IsMusicOn.Value && allowMusicOff)
  57. {
  58. onBeganCallback?.Invoke();
  59. onEndCallback?.Invoke();
  60. return;
  61. }
  62. Debug.Log(">>>>>> Start Play Music");
  63. // TODO: 需要按照这个顺序去 之后查一下原因
  64. // 需要先注册事件,然后再play
  65. MusicPlayer.SetOnStartListener(musicUnit =>
  66. {
  67. onBeganCallback?.Invoke();
  68. if (volume < 0)
  69. {
  70. MusicPlayer.SetVolume(Settings.MusicVolume.Value);
  71. }
  72. else
  73. {
  74. MusicPlayer.SetVolume(volume);
  75. }
  76. // 调用完就置为null,否则应用层每注册一个而没有注销,都会调用
  77. MusicPlayer.SetOnStartListener(null);
  78. });
  79. MusicPlayer.SetAudio(audioMgr.gameObject, musicName, loop);
  80. MusicPlayer.SetOnFinishListener(player =>
  81. {
  82. onEndCallback?.Invoke();
  83. // 调用完就置为null,否则应用层每注册一个而没有注销,都会调用
  84. player.SetOnFinishListener(null);
  85. });
  86. }
  87. public static void StopMusic()
  88. {
  89. AudioManager.Instance.MusicPlayer.Stop();
  90. }
  91. public static void PauseMusic()
  92. {
  93. AudioManager.Instance.MusicPlayer.Pause();
  94. }
  95. public static void ResumeMusic()
  96. {
  97. AudioManager.Instance.MusicPlayer.Resume();
  98. }
  99. public static AudioPlayer VoicePlayer
  100. {
  101. get { return AudioManager.Instance.VoicePlayer; }
  102. }
  103. public static void PlayVoice(string voiceName, bool loop = false, System.Action onBeganCallback = null,
  104. System.Action onEndedCallback = null)
  105. {
  106. var audioMgr = AudioManager.Instance;
  107. AudioManager.Instance.CheckAudioListener();
  108. audioMgr.CurrentVoiceName = voiceName;
  109. if (!Settings.IsVoiceOn.Value)
  110. {
  111. return;
  112. }
  113. VoicePlayer.SetOnStartListener(player =>
  114. {
  115. onBeganCallback?.Invoke();
  116. player.SetVolume(Settings.VoiceVolume.Value);
  117. // 调用完就置为null,否则应用层每注册一个而没有注销,都会调用
  118. VoicePlayer.SetOnStartListener(null);
  119. });
  120. VoicePlayer.SetAudio(AudioManager.Instance.gameObject, voiceName, loop);
  121. VoicePlayer.SetOnFinishListener(musicUnit =>
  122. {
  123. onEndedCallback?.Invoke();
  124. VoicePlayer.SetOnFinishListener(null);
  125. });
  126. }
  127. public static void PauseVoice()
  128. {
  129. VoicePlayer.Pause();
  130. }
  131. public static void ResumeVoice()
  132. {
  133. VoicePlayer.Resume();
  134. }
  135. public static void StopVoice()
  136. {
  137. VoicePlayer.Stop();
  138. }
  139. public static AudioPlayer PlaySound(string soundName, bool loop = false, Action<AudioPlayer> callBack = null,
  140. int customEventId = -1)
  141. {
  142. AudioManager.Instance.CheckAudioListener();
  143. if (!Settings.IsSoundOn.Value) return null;
  144. var soundPlayer = SafeObjectPool<AudioPlayer>.Instance.Allocate();
  145. soundPlayer.SetOnStartListener(player =>
  146. {
  147. player.SetVolume(Settings.SoundVolume.Value);
  148. soundPlayer.SetOnStartListener(null);
  149. });
  150. soundPlayer.SetAudio(AudioManager.Instance.gameObject, soundName, loop);
  151. soundPlayer.SetOnFinishListener(soundUnit =>
  152. {
  153. if (callBack != null)
  154. {
  155. callBack(soundUnit);
  156. }
  157. AudioManager.Instance.RemoveSoundPlayerFromPool(soundPlayer);
  158. });
  159. soundPlayer.customEventID = customEventId;
  160. AudioManager.Instance.AddSoundPlayer2Pool(soundPlayer);
  161. return soundPlayer;
  162. }
  163. public static void StopAllSound()
  164. {
  165. AudioManager.Instance.ForEachAllSound(player => player.Stop());
  166. AudioManager.Instance.ClearAllPlayingSound();
  167. }
  168. #region 梅川内酷需求
  169. public static void PlayMusic(AudioClip clip, bool loop = true, System.Action onBeganCallback = null,
  170. System.Action onEndCallback = null, bool allowMusicOff = true, float volume = -1f)
  171. {
  172. AudioManager.Instance.CheckAudioListener();
  173. var audioMgr = AudioManager.Instance;
  174. audioMgr.CurrentMusicName = "music" + clip.GetHashCode();
  175. if (!Settings.IsMusicOn.Value && allowMusicOff)
  176. {
  177. onBeganCallback?.Invoke();
  178. onEndCallback?.Invoke();
  179. return;
  180. }
  181. Debug.Log(">>>>>> Start Play Music");
  182. // TODO: 需要按照这个顺序去 之后查一下原因
  183. // 需要先注册事件,然后再play
  184. MusicPlayer.SetOnStartListener(musicUnit =>
  185. {
  186. onBeganCallback?.Invoke();
  187. if (volume < 0)
  188. {
  189. MusicPlayer.SetVolume(Settings.MusicVolume.Value);
  190. }
  191. else
  192. {
  193. MusicPlayer.SetVolume(volume);
  194. }
  195. // 调用完就置为null,否则应用层每注册一个而没有注销,都会调用
  196. MusicPlayer.SetOnStartListener(null);
  197. });
  198. MusicPlayer.SetAudioExt(audioMgr.gameObject, clip, audioMgr.CurrentMusicName, loop);
  199. MusicPlayer.SetOnFinishListener(musicUnit =>
  200. {
  201. onEndCallback?.Invoke();
  202. // 调用完就置为null,否则应用层每注册一个而没有注销,都会调用
  203. MusicPlayer.SetOnFinishListener(null);
  204. });
  205. }
  206. public static void PlayVoice(AudioClip clip, bool loop = false, System.Action onBeganCallback = null,
  207. System.Action onEndedCallback = null)
  208. {
  209. AudioManager.Instance.CheckAudioListener();
  210. var audioMgr = AudioManager.Instance;
  211. audioMgr.CurrentVoiceName = "voice" + clip.GetHashCode();
  212. if (!Settings.IsVoiceOn.Value)
  213. {
  214. return;
  215. }
  216. VoicePlayer.SetOnStartListener(musicUnit =>
  217. {
  218. onBeganCallback?.Invoke();
  219. VoicePlayer.SetOnStartListener(null);
  220. });
  221. VoicePlayer.SetAudioExt(AudioManager.Instance.gameObject, clip, audioMgr.CurrentVoiceName, loop);
  222. VoicePlayer.SetOnFinishListener(musicUnit =>
  223. {
  224. onEndedCallback?.Invoke();
  225. VoicePlayer.SetOnFinishListener(null);
  226. });
  227. }
  228. public static AudioPlayer PlaySound(AudioClip clip, bool loop = false, Action<AudioPlayer> callBack = null,
  229. int customEventId = -1)
  230. {
  231. AudioManager.Instance.CheckAudioListener();
  232. if (!Settings.IsSoundOn.Value) return null;
  233. var soundPlayer = SafeObjectPool<AudioPlayer>.Instance.Allocate();
  234. soundPlayer.SetAudioExt(AudioManager.Instance.gameObject, clip,"sound" + clip.GetHashCode(), loop);
  235. soundPlayer.SetVolume(Settings.SoundVolume.Value);
  236. soundPlayer.SetOnFinishListener(soundUnit =>
  237. {
  238. if (callBack != null)
  239. {
  240. callBack(soundUnit);
  241. }
  242. AudioManager.Instance.RemoveSoundPlayerFromPool(soundPlayer);
  243. });
  244. soundPlayer.customEventID = customEventId;
  245. AudioManager.Instance.AddSoundPlayer2Pool(soundPlayer);
  246. return soundPlayer;
  247. }
  248. #endregion
  249. }
  250. public class AudioKitConfig
  251. {
  252. public IAudioLoaderPool AudioLoaderPool = new DefaultAudioLoaderPool();
  253. }
  254. public interface IAudioLoader
  255. {
  256. AudioClip Clip { get; }
  257. AudioClip LoadClip(AudioSearchKeys audioSearchKeys);
  258. void LoadClipAsync(AudioSearchKeys audioSearchKeys, Action<bool,AudioClip> onLoad);
  259. void Unload();
  260. }
  261. public class AudioSearchKeys : IPoolType, IPoolable
  262. {
  263. public string AssetBundleName;
  264. public string AssetName;
  265. public void OnRecycled()
  266. {
  267. AssetBundleName = null;
  268. AssetName = null;
  269. }
  270. public bool IsRecycled { get; set; }
  271. public override string ToString()
  272. {
  273. return
  274. $"AudioSearchKeys AssetName:{AssetName} AssetBundleName:{AssetBundleName}";
  275. }
  276. public static AudioSearchKeys Allocate()
  277. {
  278. return SafeObjectPool<AudioSearchKeys>.Instance.Allocate();
  279. }
  280. public void Recycle2Cache()
  281. {
  282. SafeObjectPool<AudioSearchKeys>.Instance.Recycle(this);
  283. }
  284. }
  285. public interface IAudioLoaderPool
  286. {
  287. IAudioLoader AllocateLoader();
  288. void RecycleLoader(IAudioLoader loader);
  289. }
  290. public abstract class AbstractAudioLoaderPool : IAudioLoaderPool
  291. {
  292. private Stack<IAudioLoader> mPool = new Stack<IAudioLoader>(16);
  293. public IAudioLoader AllocateLoader()
  294. {
  295. return mPool.Count > 0 ? mPool.Pop() : CreateLoader();
  296. }
  297. protected abstract IAudioLoader CreateLoader();
  298. public void RecycleLoader(IAudioLoader loader)
  299. {
  300. mPool.Push(loader);
  301. }
  302. }
  303. public class DefaultAudioLoaderPool : AbstractAudioLoaderPool
  304. {
  305. protected override IAudioLoader CreateLoader()
  306. {
  307. return new DefaultAudioLoader();
  308. }
  309. }
  310. public class DefaultAudioLoader : IAudioLoader
  311. {
  312. private AudioClip mClip;
  313. public AudioClip Clip => mClip;
  314. public AudioClip LoadClip(AudioSearchKeys panelSearchKeys)
  315. {
  316. mClip = Resources.Load<AudioClip>(panelSearchKeys.AssetName);
  317. return mClip;
  318. }
  319. public void LoadClipAsync(AudioSearchKeys audioSearchKeys, Action<bool,AudioClip> onLoad)
  320. {
  321. var resourceRequest = Resources.LoadAsync<AudioClip>(audioSearchKeys.AssetName);
  322. resourceRequest.completed += operation =>
  323. {
  324. var clip = resourceRequest.asset as AudioClip;
  325. onLoad(clip, clip);
  326. };
  327. }
  328. public void Unload()
  329. {
  330. Resources.UnloadAsset(mClip);
  331. }
  332. }
  333. }