325 lines
11 KiB
C#
325 lines
11 KiB
C#
|
//using MoPhoGames.USpeak.Core;
|
|||
|
using System.Collections.Generic;
|
|||
|
using Thousandto.Code.Center;
|
|||
|
using Thousandto.Core.Asset;
|
|||
|
using Thousandto.Core.Base;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
namespace Thousandto.Code.Logic
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// UIEntergameForm的逻辑处理类
|
|||
|
/// </summary>
|
|||
|
public partial class ChatSystem
|
|||
|
{
|
|||
|
public const int MAX_RECORD_DURATION = 15; //最长录音时间
|
|||
|
public int VoiceIndex; //接收到的语音序列,从0开始增加
|
|||
|
public int LocalVoiceIndex; //本人发送的语音,发送时就计算序列
|
|||
|
public MyAction _action; //回调
|
|||
|
public MonoBehaviour Coro; //用于启动协程,每次打开聊天窗的时候赋值
|
|||
|
|
|||
|
private bool _recording; //是否正在录音
|
|||
|
private float MinLenght = 1.0f; //最短有效录音
|
|||
|
private int _audioLength; //录音时长
|
|||
|
private AudioClip _audioClip;
|
|||
|
private byte[] _compressedRecordData;
|
|||
|
|
|||
|
//通常的无损音质的采样率是44100,即每秒音频用44100个float数据表示,但是语音只需8000(通常移动电话是8000)就够了
|
|||
|
//不然音频数据太大,不利于传输和存储
|
|||
|
public const int SamplingRate = 8000;
|
|||
|
public AudioSource ChatAudioSource;
|
|||
|
|
|||
|
private Dictionary<int, byte[]> _voiceDataDic = new Dictionary<int, byte[]>();
|
|||
|
private Dictionary<string, string> _voiceKeyToVoiceData = new Dictionary<string, string>();
|
|||
|
|
|||
|
#region 录音操作
|
|||
|
public void StartRecord()
|
|||
|
{
|
|||
|
_audioLength = 0;
|
|||
|
_compressedRecordData = null;
|
|||
|
_recording = true;
|
|||
|
|
|||
|
StopPlayingAudio();
|
|||
|
SuspendAllSound();
|
|||
|
|
|||
|
//GameCenter.UniSoundSystem.SuspendSystem();
|
|||
|
//按钮按下开始录音
|
|||
|
//Microphone.End(null);//这句可以不需要,但是在开始录音以前调用一次是好习惯
|
|||
|
//string[] micDevices = Microphone.devices;
|
|||
|
//for (int i = 0; micDevices != null && i < micDevices.Length; ++i)
|
|||
|
//{
|
|||
|
// UnityEngine.Debug.LogError("话筒: " + micDevices[i]);
|
|||
|
//}
|
|||
|
_audioClip = null;
|
|||
|
//_audioClip = Microphone.Start(null, false, MAX_RECORD_DURATION, SamplingRate);
|
|||
|
}
|
|||
|
|
|||
|
//是否正在录音
|
|||
|
public bool IsRecording()
|
|||
|
{
|
|||
|
return _recording;
|
|||
|
}
|
|||
|
|
|||
|
public void EndRecord()
|
|||
|
{
|
|||
|
/*
|
|||
|
//按钮弹起结束录音
|
|||
|
int audioLength;//录音的长度,单位为秒,ui上可能需要显示
|
|||
|
int lastPos = Microphone.GetPosition(null);
|
|||
|
if (Microphone.IsRecording(null))
|
|||
|
{
|
|||
|
//录音小于10秒
|
|||
|
audioLength = lastPos / SamplingRate;//录音时长
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
audioLength = MAX_RECORD_DURATION;
|
|||
|
}
|
|||
|
Microphone.End(null);//此时录音结束,clip已可以播放了
|
|||
|
|
|||
|
ResumeAllSound();
|
|||
|
//GameCenter.UniSoundSystem.ResumeSystem();
|
|||
|
if (audioLength < MinLenght) return;//录音小于2秒就不处理了
|
|||
|
|
|||
|
|
|||
|
int samples = 0;
|
|||
|
_compressedRecordData = null;// USpeakAudioClipCompressor.CompressAudioClip(_audioClip, out samples, BandMode.Narrow);
|
|||
|
//_audioClip = null;
|
|||
|
_audioLength = audioLength;
|
|||
|
_recording = false;
|
|||
|
*/
|
|||
|
}
|
|||
|
|
|||
|
public void SuspendAllSound()
|
|||
|
{
|
|||
|
if (GameCenter.GameSetting.GetSetting(GameSettingKeyCode.EnableBGMusic) != 0)
|
|||
|
{
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Music, 0f);
|
|||
|
}
|
|||
|
|
|||
|
if (GameCenter.GameSetting.GetSetting(GameSettingKeyCode.EnableSound) != 0)
|
|||
|
{
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Sfx, 0f);
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Ambient, 0f);
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Speech, 0f);
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.UI, 0f);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ResumeAllSound()
|
|||
|
{
|
|||
|
if (GameCenter.GameSetting.GetSetting(GameSettingKeyCode.EnableBGMusic) != 0)
|
|||
|
{
|
|||
|
float v = (float)GameCenter.GameSetting.GetSetting(GameSettingKeyCode.BGMusicVolume)/100f;
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Music, v);
|
|||
|
}
|
|||
|
|
|||
|
if (GameCenter.GameSetting.GetSetting(GameSettingKeyCode.EnableSound) != 0)
|
|||
|
{
|
|||
|
float v = (float)GameCenter.GameSetting.GetSetting(GameSettingKeyCode.SoundVolume) / 100f;
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Sfx, v);
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Ambient, v);
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.Speech, v);
|
|||
|
AudioPlayer.SetVolume(AudioTypeCode.UI, v);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SendRecord(ChatInfo info)
|
|||
|
{
|
|||
|
if (_recording)
|
|||
|
{
|
|||
|
EndRecord();
|
|||
|
}
|
|||
|
|
|||
|
LocalVoiceIndex = ++VoiceIndex;
|
|||
|
|
|||
|
addVoiceDataToCache(LocalVoiceIndex, _compressedRecordData);
|
|||
|
|
|||
|
string content = byteToString(_compressedRecordData);
|
|||
|
MSG_Chat.ChatReqCS req = new MSG_Chat.ChatReqCS();
|
|||
|
req.chattype = info.ChatType;
|
|||
|
req.recRoleId = info.Receiver;
|
|||
|
req.condition = content;
|
|||
|
req.voiceLen = _audioLength;
|
|||
|
req.chatchannel = info.Channel;
|
|||
|
req.Send();
|
|||
|
|
|||
|
//UnityEngine.Debug.LogError("录音时长:" + _audioLength);
|
|||
|
//UnityEngine.Debug.LogError("录音数据长度:" + _compressedRecordData.Length);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region 语音播放操作
|
|||
|
//是否有语音在播放
|
|||
|
public bool IsAudioPlaying()
|
|||
|
{
|
|||
|
if (ChatAudioSource != null)
|
|||
|
{
|
|||
|
return ChatAudioSource.isPlaying;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
//关闭正在播放的语音
|
|||
|
public void StopPlayingAudio()
|
|||
|
{
|
|||
|
if (ChatAudioSource != null && ChatAudioSource.isPlaying)
|
|||
|
{
|
|||
|
ChatAudioSource.Stop();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// method
|
|||
|
public bool PlayAudio(byte[] data, AudioSource audioSrc)
|
|||
|
{
|
|||
|
if (audioSrc == null)
|
|||
|
{
|
|||
|
return false;
|
|||
|
}
|
|||
|
audioSrc.clip = null;
|
|||
|
AudioClip clip = null;// USpeakAudioClipCompressor.DecompressAudioClip(data, 0, 1, false, BandMode.Narrow, 1.0f);
|
|||
|
// play test
|
|||
|
audioSrc.clip = clip;
|
|||
|
audioSrc.Play();
|
|||
|
|
|||
|
SuspendAllSound();
|
|||
|
//GameCenter.UniSoundSystem.SuspendSystem();
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
#region 窗体事件
|
|||
|
public void OnFormClose()
|
|||
|
{
|
|||
|
//关闭窗体时,关闭语音,并且恢复背景声音
|
|||
|
if (IsAudioPlaying())
|
|||
|
{
|
|||
|
StopPlayingAudio();
|
|||
|
}
|
|||
|
|
|||
|
ResumeAllSound();
|
|||
|
//GameCenter.UniSoundSystem.ResumeSystem();
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region 私有功能函数
|
|||
|
//添加聊天数据到缓存中保存
|
|||
|
private void addVoiceDataToCache(int index, byte[] data)
|
|||
|
{
|
|||
|
//超30个就remove
|
|||
|
if (_voiceDataDic.Count >= 30)
|
|||
|
{
|
|||
|
var itor = _voiceDataDic.Keys.GetEnumerator();
|
|||
|
itor.MoveNext();
|
|||
|
int key = itor.Current;
|
|||
|
_voiceDataDic.Remove(key);
|
|||
|
|
|||
|
//在_voiceKeyToVoiceData中去移除对应的key
|
|||
|
var itor2 = _voiceKeyToVoiceData.GetEnumerator();
|
|||
|
string keyStr = "" + key;
|
|||
|
while (itor2.MoveNext())
|
|||
|
{
|
|||
|
if (itor2.Current.Value == keyStr)
|
|||
|
{
|
|||
|
_voiceKeyToVoiceData.Remove(itor2.Current.Key);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (_voiceDataDic.ContainsKey(index))
|
|||
|
{
|
|||
|
_voiceDataDic[index] = data;
|
|||
|
}
|
|||
|
else
|
|||
|
_voiceDataDic.Add(index, data);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
private string byteToString(byte[] voiceData)
|
|||
|
{
|
|||
|
char[] charArray = new char[voiceData.Length];
|
|||
|
for (int i = 0; i < voiceData.Length; ++i)
|
|||
|
{
|
|||
|
charArray[i] = (char)voiceData[i];
|
|||
|
}
|
|||
|
|
|||
|
string str = new string(charArray);
|
|||
|
|
|||
|
return str;
|
|||
|
}
|
|||
|
|
|||
|
private byte[] stringToBytes(string str)
|
|||
|
{
|
|||
|
char[] charArray = str.ToCharArray();
|
|||
|
byte[] data = new byte[charArray.Length];
|
|||
|
for (int i = 0; i < charArray.Length; ++i)
|
|||
|
{
|
|||
|
data[i] = (byte)charArray[i];
|
|||
|
}
|
|||
|
return data;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region 协议请求
|
|||
|
public void ReqVoiceData(string key, MyAction action)
|
|||
|
{
|
|||
|
_action = action;
|
|||
|
if (_voiceKeyToVoiceData.ContainsKey(key))
|
|||
|
{
|
|||
|
int voiceIndexKey = int.Parse(_voiceKeyToVoiceData[key]);
|
|||
|
if (_voiceDataDic.ContainsKey(voiceIndexKey))
|
|||
|
{
|
|||
|
PlayAudio(_voiceDataDic[voiceIndexKey], ChatAudioSource);
|
|||
|
if (_action != null)
|
|||
|
_action();
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
MSG_Chat.ChatGetContentCS reqVoice = new MSG_Chat.ChatGetContentCS();
|
|||
|
reqVoice.key = key;
|
|||
|
reqVoice.Send();
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region 协议返回
|
|||
|
|
|||
|
public void GS2U_ChatGetContentSC(MSG_Chat.ChatGetContentSC result)
|
|||
|
{
|
|||
|
byte[] voiceData = stringToBytes(result.voice);
|
|||
|
|
|||
|
//有保存,重置数据
|
|||
|
if (_voiceKeyToVoiceData.ContainsKey(result.voiceKey))
|
|||
|
{
|
|||
|
int index = int.Parse(_voiceKeyToVoiceData[result.voiceKey]);
|
|||
|
addVoiceDataToCache(index, voiceData);
|
|||
|
}
|
|||
|
|
|||
|
PlayAudio(voiceData, ChatAudioSource);
|
|||
|
if (_action != null)
|
|||
|
_action();
|
|||
|
|
|||
|
//CoroutinePool.AddTask(playAudioIE(obj, this));
|
|||
|
}
|
|||
|
|
|||
|
public void TestOnChatVoiceReceive(int channel, int voiceID, int length)
|
|||
|
{
|
|||
|
//Audio: m_param1 = key; m_param2 = length m_param3 = ""
|
|||
|
ChatNode node = new ChatNode();
|
|||
|
node.ChannelID = channel;
|
|||
|
node.Param1 = "" + voiceID;
|
|||
|
node.Param2 = "" + length;
|
|||
|
node.Param3 = null;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|