344 lines
9.8 KiB
C#
344 lines
9.8 KiB
C#
|
/* Copyright (C) 2014 DaikonForge */
|
|||
|
|
|||
|
namespace DaikonForge.VoIP
|
|||
|
{
|
|||
|
using UnityEngine;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Collections;
|
|||
|
using System.Runtime.Serialization.Formatters.Binary;
|
|||
|
using System.IO;
|
|||
|
using System.Text;
|
|||
|
using System;
|
|||
|
using Cysharp.Threading.Tasks;
|
|||
|
|
|||
|
public class LocalVoiceController : VoiceControllerBase
|
|||
|
{
|
|||
|
public float PacketLoss = 0.1f;
|
|||
|
|
|||
|
//private bool recording = false;
|
|||
|
|
|||
|
private bool isCallBack = true;
|
|||
|
|
|||
|
public static int RecordMaxLength = 40;
|
|||
|
|
|||
|
FastList<VoicePacketWrapper> voiceArr = FastList<VoicePacketWrapper>.Obtain();
|
|||
|
|
|||
|
public VoicePacketWrapper[] temp;
|
|||
|
|
|||
|
public int recordLength = 0;
|
|||
|
|
|||
|
public Action<byte[], byte> EndCallBack;
|
|||
|
|
|||
|
private void Start()
|
|||
|
{
|
|||
|
Debug.Log("Start");
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 录音开始回调
|
|||
|
/// </summary>
|
|||
|
protected override void RecordingStart()
|
|||
|
{
|
|||
|
base.RecordingStart();
|
|||
|
voiceArr = FastList<VoicePacketWrapper>.Obtain();
|
|||
|
isCallBack = true;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 录音停止后回调
|
|||
|
/// </summary>
|
|||
|
protected override void RecordingEnd(int length)
|
|||
|
{
|
|||
|
if (!this.isCallBack)
|
|||
|
return;
|
|||
|
base.RecordingEnd(length);
|
|||
|
|
|||
|
recordLength = length;
|
|||
|
|
|||
|
Debug.Log("RecordingEnd copy start");
|
|||
|
|
|||
|
FastList<byte> allData = FastList<byte>.Obtain();
|
|||
|
//int len = 0;
|
|||
|
for (int i = 0, count = voiceArr.Count; i < count; i++)
|
|||
|
{
|
|||
|
|
|||
|
allData.AddRange(voiceArr[i].GetSampleData());
|
|||
|
voiceArr[i].ReleaseSampleData();
|
|||
|
}
|
|||
|
|
|||
|
EndCallBack?.Invoke(allData.ToArray(), (byte)length);
|
|||
|
//NativeToolkit.Instance.StopRecordingCallBack(allData.ToArray(), length);
|
|||
|
|
|||
|
allData.Release();
|
|||
|
voiceArr.Release();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 每一次framesize满了就会回调
|
|||
|
/// </summary>
|
|||
|
/// <param name="encodedFrame"></param>
|
|||
|
protected override void OnAudioDataEncoded( VoicePacketWrapper encodedFrame )
|
|||
|
{
|
|||
|
if (UnityEngine.Random.Range(0f, 1f) <= PacketLoss)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
voiceArr.Enqueue(encodedFrame);
|
|||
|
}
|
|||
|
|
|||
|
#region publicMethod
|
|||
|
/// <summary>
|
|||
|
/// 开始录音
|
|||
|
/// </summary>
|
|||
|
public void StartRecording()
|
|||
|
{
|
|||
|
base.microphone.StartRecording();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 停止录音
|
|||
|
/// </summary>
|
|||
|
public void StopRecording(bool callBack)
|
|||
|
{
|
|||
|
this.isCallBack = callBack;
|
|||
|
base.microphone.StopRecording();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 延迟停止录音
|
|||
|
/// </summary>
|
|||
|
public async void StopRecording_Delay(bool callBack)
|
|||
|
{
|
|||
|
this.isCallBack = callBack;
|
|||
|
await UniTask.WaitForSeconds(0.5f);
|
|||
|
base.microphone.StopRecording();
|
|||
|
}
|
|||
|
|
|||
|
public AudioClip Decode(byte[] allData, int seconds)
|
|||
|
{
|
|||
|
base.nextExpectedIndex = 0;
|
|||
|
Application.platform.ToString();
|
|||
|
int endIndex = 0;
|
|||
|
int mHeadEndIndex = 0;
|
|||
|
FastList<byte> head = null;
|
|||
|
FastList<byte> raw = null;
|
|||
|
bool isFirstSample = true;
|
|||
|
VoicePacketWrapper packet;
|
|||
|
for (int i = 0,length = allData.Length; i < length; i++)
|
|||
|
{
|
|||
|
if (i == endIndex)
|
|||
|
{
|
|||
|
if (i > 0)
|
|||
|
{
|
|||
|
packet = new VoicePacketWrapper(head.ToArray(), raw.ToArray());
|
|||
|
if (isFirstSample)
|
|||
|
{
|
|||
|
isFirstSample = false;
|
|||
|
speaker.SetSampleRate(packet.Frequency * 1000, seconds);
|
|||
|
}
|
|||
|
ReceiveAudioData(packet);
|
|||
|
|
|||
|
head.Release();
|
|||
|
raw.Release();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
head = FastList<byte>.Obtain(9);
|
|||
|
raw = FastList<byte>.Obtain();
|
|||
|
|
|||
|
endIndex = endIndex + allData[i];
|
|||
|
mHeadEndIndex = i + 9;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (i <= mHeadEndIndex)
|
|||
|
{
|
|||
|
head.Add(allData[i]);
|
|||
|
}
|
|||
|
else if(i > mHeadEndIndex && i < endIndex )
|
|||
|
{
|
|||
|
raw.Add(allData[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (head != null)
|
|||
|
{
|
|||
|
head.Release();
|
|||
|
}
|
|||
|
if (raw != null)
|
|||
|
{
|
|||
|
raw.Release();
|
|||
|
}
|
|||
|
|
|||
|
return speaker.GetAudioClip();
|
|||
|
}
|
|||
|
/**
|
|||
|
public AudioClip Decode(VoicePacketWrapper[] packets, int seconds)
|
|||
|
{
|
|||
|
VoicePacketWrapper packet;
|
|||
|
|
|||
|
base.nextExpectedIndex = 0;
|
|||
|
|
|||
|
for (int i = 0, length = packets.Length; i < length; i++)
|
|||
|
{
|
|||
|
packet = packets[i];
|
|||
|
if (i == 0)
|
|||
|
{
|
|||
|
speaker.SetSampleRate(packet.Frequency * 1000, seconds);
|
|||
|
}
|
|||
|
ReceiveAudioData(packet);
|
|||
|
}
|
|||
|
|
|||
|
return speaker.GetAudioClip();
|
|||
|
}
|
|||
|
|
|||
|
public AudioClip Decode(string[] headStrArr, string[] rawDataStrArr,int seconds)
|
|||
|
{
|
|||
|
byte[] headData = null;
|
|||
|
byte[] rawData = null;
|
|||
|
VoicePacketWrapper packet = new VoicePacketWrapper();
|
|||
|
|
|||
|
base.nextExpectedIndex = 0;
|
|||
|
|
|||
|
// -- -----test
|
|||
|
int headLength = 0;
|
|||
|
int rawLength = 0;
|
|||
|
|
|||
|
for (int i = 0,length = headStrArr.Length; i < length; i++)
|
|||
|
{
|
|||
|
int count = 0;
|
|||
|
headData = GetBytes(headStrArr[i], out count);
|
|||
|
rawData = GetBytes(rawDataStrArr[i], out count);
|
|||
|
|
|||
|
packet = new VoicePacketWrapper(headData, rawData);
|
|||
|
if (i == 0)
|
|||
|
{
|
|||
|
speaker.SetSampleRate(packet.Frequency * 1000, seconds);
|
|||
|
}
|
|||
|
ReceiveAudioData(packet);
|
|||
|
|
|||
|
headLength += headStrArr[i].Length;
|
|||
|
rawLength += rawDataStrArr[i].Length;
|
|||
|
}
|
|||
|
|
|||
|
Debug.Log(string.Format("xxxxxxxxxxxxxxxxxxxxxxxxxxxDecode {0} / {1} /{2} ", headLength, rawLength, (headLength + rawLength)));
|
|||
|
|
|||
|
return speaker.GetAudioClip();
|
|||
|
}
|
|||
|
**/
|
|||
|
|
|||
|
public override bool IsLocal
|
|||
|
{
|
|||
|
get { return true; }
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
public static string ToHexString(byte[] bytes) // 0xae00cf => "AE00CF "
|
|||
|
{
|
|||
|
string hexString = string.Empty;
|
|||
|
|
|||
|
if (bytes != null)
|
|||
|
{
|
|||
|
|
|||
|
StringBuilder strB = new StringBuilder();
|
|||
|
|
|||
|
for (int i = 0; i < bytes.Length; i++)
|
|||
|
{
|
|||
|
|
|||
|
strB.Append(bytes[i].ToString("X2"));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
hexString = strB.ToString();
|
|||
|
|
|||
|
}
|
|||
|
//hexString = System.Text.Encoding.UTF8.GetString(bytes);
|
|||
|
return hexString;
|
|||
|
}
|
|||
|
public static byte[] GetBytes(string hexString, out int discarded)
|
|||
|
{
|
|||
|
discarded = 0;
|
|||
|
string newString = "";
|
|||
|
char c;
|
|||
|
// remove all none A-F, 0-9, characters
|
|||
|
for (int i = 0; i < hexString.Length; i++)
|
|||
|
{
|
|||
|
c = hexString[i];
|
|||
|
if (Uri.IsHexDigit(c))
|
|||
|
newString += c;
|
|||
|
else
|
|||
|
discarded++;
|
|||
|
}
|
|||
|
// if odd number of characters, discard last character
|
|||
|
if (newString.Length % 2 != 0)
|
|||
|
{
|
|||
|
discarded++;
|
|||
|
newString = newString.Substring(0, newString.Length - 1);
|
|||
|
}
|
|||
|
|
|||
|
int byteLength = newString.Length / 2;
|
|||
|
byte[] bytes = new byte[byteLength];
|
|||
|
string hex;
|
|||
|
int j = 0;
|
|||
|
for (int i = 0; i < bytes.Length; i++)
|
|||
|
{
|
|||
|
hex = new System.String(new Char[] { newString[j], newString[j + 1] });
|
|||
|
bytes[i] = HexToByte(hex);
|
|||
|
j = j + 2;
|
|||
|
}
|
|||
|
//byte[] bytes = System.Text.Encoding.UTF8.GetBytes(hexString);
|
|||
|
|
|||
|
return bytes;
|
|||
|
}
|
|||
|
|
|||
|
private static byte HexToByte(string hex)
|
|||
|
{
|
|||
|
byte tt = byte.Parse(hex, System.Globalization.NumberStyles.HexNumber);
|
|||
|
return tt;
|
|||
|
}
|
|||
|
|
|||
|
public UnityAudioPlayer GetSpeaker()
|
|||
|
{
|
|||
|
if (speaker != null)
|
|||
|
return (UnityAudioPlayer)speaker;
|
|||
|
else
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 1. Narrow,2.Wide,3.UltraWide
|
|||
|
/// </summary>
|
|||
|
/// <param name="level"></param>
|
|||
|
public void SetMicphoneRecordingMode(int level)
|
|||
|
{
|
|||
|
FrequencyMode mode = FrequencyMode.Wide;
|
|||
|
switch (level)
|
|||
|
{
|
|||
|
case 1:
|
|||
|
mode = FrequencyMode.Narrow;
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
mode = FrequencyMode.Wide;
|
|||
|
break;
|
|||
|
case 3:
|
|||
|
mode = FrequencyMode.UltraWide;
|
|||
|
break;
|
|||
|
default:
|
|||
|
mode = FrequencyMode.Wide;
|
|||
|
break;
|
|||
|
}
|
|||
|
((MicrophoneInputDevice)microphone).Mode = mode;
|
|||
|
}
|
|||
|
|
|||
|
public void SetMaxRecordingTime(int recordingTime)
|
|||
|
{
|
|||
|
((MicrophoneInputDevice)microphone).maxRecordTime = recordingTime;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|