using UnityEngine; using System; using System.IO; using AX.AudioSystem; [RequireComponent(typeof(AudioSource))] public class AudioPlayer : MonoBehaviour { [Header("音频采样率")] public int SamplingRate = 8000; [Header("音频声道数,默认为单声道")] public int Channels = 1; [Header("音频录制最大时长,按秒计")] public int RecordMaxTime = 60; /// /// 表示当前播放器是否正在播放。 /// public bool IsPlaying { get { return !stopped && audioSource.isPlaying; } } /// /// 获得播放列表。 /// public PlayList PlayList { get { return playList; } } /// /// 获得当前已经播放到播放列表中哪一条曲目了。 /// public int PlayIndex { get { return playIndex; } set { if (value < -1 || value >= playList.Count) throw new InvalidOperationException("value"); playIndex = value; } } /// /// 表示要开始播放某曲目前的事件。 /// public event Action Playing; /// /// 表示播放某曲目结束后的事件。 /// public event Action Played; private AudioSource audioSource; private OpusDecoder opusDecoder; private BetterList audioBuffer; private BetterList opusBuffer; private float[] packageBuffer; private byte[] frameBuffer; private PlayList playList; private int playIndex; private bool stopped; private const int BufferSize = 8192; private byte[] buffer = new byte[BufferSize]; void Awake() { Initialize(); } void OnDisable() { Stop(); } void OnDestroy() { if (opusDecoder != null) { opusDecoder.Dispose(); opusDecoder = null; } } void Update() { // 自动播放列表中的语音消息 if (!stopped && playList.Count > 0) { // 已经全部播放过 if (playIndex != -1 && playIndex == playList.Count - 1 && playList[playIndex].Played && !playList[playIndex].Playing) return; // 正在播放 if (IsPlaying) return; // 当前项播放完毕 var curTrack = playList[playIndex]; curTrack.Playing = false; playList[playIndex] = curTrack; OnPlayed(playIndex, curTrack); // 准备播放下一条 var nextIndex = playIndex + 1; if (nextIndex != playList.Count) { var track = playList[nextIndex]; if (!track.Played) { playIndex = nextIndex; track.Played = true; track.Playing = true; playList[nextIndex] = track; PlayAudio(playList[nextIndex].Filename); } } } } /// /// 立即播放指定的音频文件,即使该播放器正在播放其它音频文件。 /// public void Play(string audioFile) { var index = playList.IndexOf(audioFile); if (index == -1) { playList.Add(audioFile, true, true); playIndex = playList.Count - 1; } else { playIndex = index; var track = playList[playIndex]; track.Played = true; track.Playing = true; playList[playIndex] = track; } if (IsPlaying) Stop(); stopped = false; PlayAudio(audioFile); } /// /// 排队播放音频文件。 /// public void PlayScheduled(string audioFile) { var index = playList.IndexOf(audioFile); if (index == -1) playList.Add(audioFile, false, false); stopped = false; } /// /// 播放音频。 /// public void Play() { stopped = false; } public void Stop() { if (opusDecoder != null) { audioSource.Stop(); if (audioSource.clip != null) { Destroy(audioSource.clip); audioSource.clip = null; } if (playIndex != -1) { var track = playList[playIndex]; track.Playing = false; playList[playIndex] = track; } } stopped = true; } private void Initialize() { if (opusDecoder == null) { audioSource = GetComponent(); audioBuffer = new BetterList(RecordMaxTime * SamplingRate * Channels + PromptTone.Data.Length); opusBuffer = new BetterList(200 * 1024); packageBuffer = new float[OpusDecoder.FrameMaxSize * Channels]; opusDecoder = new OpusDecoder((SamplingRate)SamplingRate, (Channel)Channels); playList = new PlayList(); playIndex = -1; } } private void PlayAudio(string audioFile) { OnPlaying(playIndex, playList[playIndex]); // 先从文件读取数据 using (var stream = new FileStream(audioFile, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize)) { var readLength = 0; while ((readLength = stream.Read(buffer, 0, BufferSize)) > 0) opusBuffer.AddRange(buffer, 0, readLength); } // 解析数据并解码音频 var length = 0; for (var i = 0; i < opusBuffer.Count; ++i) { length = opusBuffer[i]; if (length == 0) continue; if (frameBuffer == null || length != frameBuffer.Length) frameBuffer = new byte[length]; opusBuffer.CopyTo(i + 1, frameBuffer, 0, length); var decoded = opusDecoder.Decode(frameBuffer, packageBuffer); audioBuffer.AddRange(packageBuffer, 0, decoded); i += length; } var data = audioBuffer.ToArray(); audioBuffer.Clear(); opusBuffer.Clear(); var clip = AudioClip.Create("VoicePlayback", data.Length, Channels, SamplingRate, false); clip.SetData(data, 0); audioSource.clip = clip; audioSource.Play(); } public void Clear() { Stop(); PlayList.Clear(); playIndex = -1; } protected virtual void OnPlaying(int index, Track track) { if (Playing != null) Playing(index, track); } protected virtual void OnPlayed(int index, Track track) { if (Played != null) Played(index, track); } }