备份CatanBuilding瘦身独立工程
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
internal static class AudioConvert
|
||||
{
|
||||
#if (UNITY_ANDROID || UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
[DllImport("audio-convert")]
|
||||
public static extern IntPtr convert_wav_to_amrwb(IntPtr wavSrc, int wavSrcSize, ref int status, ref int amrSize);
|
||||
|
||||
[DllImport("audio-convert")]
|
||||
public static extern IntPtr convert_amrwb_to_wav(IntPtr amrSrc, int amrSrcSize, ref int status, ref int wavSize);
|
||||
|
||||
[DllImport("audio-convert")]
|
||||
public static extern void free_memory(IntPtr ptr);
|
||||
|
||||
|
||||
#elif UNITY_IOS
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern IntPtr convert_wav_to_amrwb(IntPtr wavSrc, int wavSrcSize, ref int status, ref int amrSize);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern IntPtr convert_amrwb_to_wav(IntPtr amrSrc, int amrSrcSize, ref int status, ref int wavSize);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
public static extern void free_memory(IntPtr ptr);
|
||||
|
||||
#endif
|
||||
|
||||
public static byte[] ConvertToAmrwb(byte[] wavBuffer)
|
||||
{
|
||||
int status = 0;
|
||||
int amrSize = 0;
|
||||
|
||||
IntPtr wavSrcPtr = Marshal.AllocHGlobal(wavBuffer.Length);
|
||||
Marshal.Copy(wavBuffer, 0, wavSrcPtr, wavBuffer.Length);
|
||||
|
||||
IntPtr amrPtr = AudioConvert.convert_wav_to_amrwb(wavSrcPtr, wavBuffer.Length, ref status, ref amrSize);
|
||||
|
||||
Marshal.FreeHGlobal(wavSrcPtr);
|
||||
|
||||
if (amrPtr != null && status == 0) {
|
||||
byte[] amrBuffer = new byte[amrSize];
|
||||
Marshal.Copy(amrPtr, amrBuffer, 0, amrSize);
|
||||
AudioConvert.free_memory(amrPtr);
|
||||
return amrBuffer;
|
||||
}
|
||||
|
||||
if (amrPtr != null)
|
||||
AudioConvert.free_memory(amrPtr);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] ConvertToWav(byte[] amrBuffer)
|
||||
{
|
||||
int status = 0;
|
||||
int wavSize = 0;
|
||||
|
||||
IntPtr amrSrcPtr = Marshal.AllocHGlobal(amrBuffer.Length);
|
||||
Marshal.Copy(amrBuffer, 0, amrSrcPtr, amrBuffer.Length);
|
||||
|
||||
IntPtr wavPtr = AudioConvert.convert_amrwb_to_wav(amrSrcPtr, amrBuffer.Length, ref status, ref wavSize);
|
||||
|
||||
Marshal.FreeHGlobal(amrSrcPtr);
|
||||
|
||||
if (wavPtr != null && status == 0) {
|
||||
byte[] wavBuffer = new byte[wavSize];
|
||||
Marshal.Copy(wavPtr, wavBuffer, 0, wavSize);
|
||||
AudioConvert.free_memory(wavPtr);
|
||||
return wavBuffer;
|
||||
}
|
||||
|
||||
if (wavPtr != null)
|
||||
AudioConvert.free_memory(wavPtr);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfaf510d97fd04302bf3d50f2486b91d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,324 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
using AOT;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
static public class AudioRecorderNative
|
||||
{
|
||||
public enum AudioDeviceType
|
||||
{
|
||||
Microphone = 0,
|
||||
Speaker = 1,
|
||||
}
|
||||
public interface IAudioRecorderListener
|
||||
{
|
||||
void RecordStart(bool success);
|
||||
void RecordEnd();
|
||||
void OnRecord(RTMAudioData audioData);
|
||||
void OnVolumn(double db);
|
||||
void PlayStart(bool success);
|
||||
void PlayEnd();
|
||||
}
|
||||
|
||||
static internal IAudioRecorderListener audioRecorderListener;
|
||||
static internal string language;
|
||||
static volatile bool cancelRecord = false;
|
||||
static volatile bool recording = false;
|
||||
|
||||
delegate void VolumnCallbackDelegate(float volumn);
|
||||
[MonoPInvokeCallback(typeof(VolumnCallbackDelegate))]
|
||||
private static void VolumnCallback(float volumn)
|
||||
{
|
||||
if (audioRecorderListener != null)
|
||||
{
|
||||
float minValue = -60;
|
||||
float range = 60;
|
||||
float outRange = 100;
|
||||
if (volumn < minValue)
|
||||
volumn = minValue;
|
||||
|
||||
volumn = (volumn + range) / range * outRange;
|
||||
audioRecorderListener.OnVolumn(volumn);
|
||||
}
|
||||
}
|
||||
|
||||
delegate void StartRecordCallbackDelegate(bool success);
|
||||
[MonoPInvokeCallback(typeof(StartRecordCallbackDelegate))]
|
||||
private static void StartRecordCallback(bool success)
|
||||
{
|
||||
if (success == false)
|
||||
recording = false;
|
||||
if (audioRecorderListener != null)
|
||||
audioRecorderListener.RecordStart(success);
|
||||
}
|
||||
|
||||
delegate void StopRecordCallbackDelegate(IntPtr data, int length, long time);
|
||||
[MonoPInvokeCallback(typeof(StopRecordCallbackDelegate))]
|
||||
private static void StopRecordCallback(IntPtr data, int length, long time)
|
||||
{
|
||||
recording = false;
|
||||
if (audioRecorderListener != null)
|
||||
{
|
||||
audioRecorderListener.RecordEnd();
|
||||
if (cancelRecord)
|
||||
{
|
||||
cancelRecord = false;
|
||||
return;
|
||||
}
|
||||
if (data == IntPtr.Zero)
|
||||
return;
|
||||
byte[] payload = new byte[length];
|
||||
Marshal.Copy(data, payload, 0, length);
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
RTMAudioData audioData = new RTMAudioData(AudioConvert.ConvertToAmrwb(payload), language, time);
|
||||
#else
|
||||
RTMAudioData audioData = new RTMAudioData(payload, language, time);
|
||||
#endif
|
||||
audioRecorderListener.OnRecord(audioData);
|
||||
}
|
||||
}
|
||||
|
||||
delegate void PlayFinishCallbackDelegate();
|
||||
[MonoPInvokeCallback(typeof(PlayFinishCallbackDelegate))]
|
||||
private static void PlayFinishCallback()
|
||||
{
|
||||
if (audioRecorderListener != null)
|
||||
audioRecorderListener.PlayEnd();
|
||||
}
|
||||
|
||||
delegate void PlayStartCallbackDelegate(bool success);
|
||||
[MonoPInvokeCallback(typeof(PlayStartCallbackDelegate))]
|
||||
private static void PlayStartCallback(bool success)
|
||||
{
|
||||
audioRecorderListener?.PlayStart(success);
|
||||
}
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
delegate void AudioDeviceChangedDelegate(int type);
|
||||
static bool microphoneChanged = false;
|
||||
static bool speakerChanged = false;
|
||||
[MonoPInvokeCallback(typeof(AudioDeviceChangedDelegate))]
|
||||
private static void AudioDeviceChangedCallback(int type)
|
||||
{
|
||||
AudioDeviceType deviceType = (AudioDeviceType)type;
|
||||
if (deviceType == AudioDeviceType.Microphone)
|
||||
microphoneChanged = true;
|
||||
if (deviceType == AudioDeviceType.Speaker)
|
||||
speakerChanged = true;
|
||||
}
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void initAudioDeviceChecker(AudioDeviceChangedDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startRecord(VolumnCallbackDelegate callback, StartRecordCallbackDelegate startCallback, bool update);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopRecord(StopRecordCallbackDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startPlay(byte[] data, int length, PlayFinishCallbackDelegate callback, PlayStartCallbackDelegate playStartCallback, bool update);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopPlay();
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void playWithPath(byte[] data, int length, PlayFinishCallbackDelegate callback);
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startRecord(VolumnCallbackDelegate callback, StartRecordCallbackDelegate startCallback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopRecord(StopRecordCallbackDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void startPlay(byte[] data, int length, PlayFinishCallbackDelegate callback, PlayStartCallbackDelegate playStartCallback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void stopPlay();
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void playWithPath(byte[] data, int length, PlayFinishCallbackDelegate callback);
|
||||
#elif UNITY_IOS
|
||||
[DllImport("__Internal")]
|
||||
private static extern void startRecord(VolumnCallbackDelegate callback, StartRecordCallbackDelegate startCallback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
private static extern void stopRecord(StopRecordCallbackDelegate callback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
private static extern void startPlay(byte[] data, int length, PlayFinishCallbackDelegate callback, PlayStartCallbackDelegate playStartCallback);
|
||||
|
||||
[DllImport("__Internal")]
|
||||
private static extern void stopPlay();
|
||||
#elif UNITY_ANDROID
|
||||
class AudioRecordAndroidProxy : AndroidJavaProxy
|
||||
{
|
||||
public AudioRecordAndroidProxy() : base("com.NetForUnity.IAudioAction")
|
||||
{
|
||||
}
|
||||
|
||||
public void startRecord(bool success, string errorMsg)
|
||||
{
|
||||
if (success == false)
|
||||
recording = false;
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.RecordStart(success);
|
||||
}
|
||||
|
||||
public void stopRecord()
|
||||
{
|
||||
recording = false;
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.RecordEnd();
|
||||
}
|
||||
|
||||
public void startBroad(bool success)
|
||||
{
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.PlayStart(success);
|
||||
}
|
||||
|
||||
public void broadFinish()
|
||||
{
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
AudioRecorderNative.audioRecorderListener.PlayEnd();
|
||||
}
|
||||
|
||||
public void listenVolume(double db)
|
||||
{
|
||||
if (AudioRecorderNative.audioRecorderListener != null)
|
||||
{
|
||||
float minValue = -60;
|
||||
float range = 60;
|
||||
float outRange = 100;
|
||||
if (db < minValue)
|
||||
db = minValue;
|
||||
|
||||
db = (db + range) / range * outRange;
|
||||
|
||||
AudioRecorderNative.audioRecorderListener.OnVolumn(db);
|
||||
}
|
||||
}
|
||||
}
|
||||
static AndroidJavaObject AudioRecord = null;
|
||||
#endif
|
||||
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
[DllImport("RTMNative")]
|
||||
internal static extern void destroy();
|
||||
#endif
|
||||
|
||||
static public void Init(string language, IAudioRecorderListener listener)
|
||||
{
|
||||
AudioRecorderNative.language = language;
|
||||
audioRecorderListener = listener;
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
initAudioDeviceChecker(AudioDeviceChangedCallback);
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
|
||||
#elif UNITY_ANDROID
|
||||
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
||||
AndroidJavaObject appconatext = jc.GetStatic<AndroidJavaObject>("currentActivity");
|
||||
if (AudioRecord == null)
|
||||
{
|
||||
AndroidJavaClass playerClass = new AndroidJavaClass("com.NetForUnity.RTMAudio");
|
||||
AudioRecord = playerClass.CallStatic<AndroidJavaObject>("getInstance");
|
||||
}
|
||||
AudioRecord.Call("init", appconatext, language, new AudioRecordAndroidProxy());
|
||||
#else
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
static public bool IsRecording()
|
||||
{
|
||||
return recording;
|
||||
}
|
||||
|
||||
static public void StartRecord()
|
||||
{
|
||||
recording = true;
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
startRecord(VolumnCallback, StartRecordCallback, microphoneChanged);
|
||||
microphoneChanged = false;
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
startRecord(VolumnCallback, StartRecordCallback);
|
||||
#elif UNITY_ANDROID
|
||||
if (AudioRecord != null)
|
||||
AudioRecord.Call("startRecord");
|
||||
#else
|
||||
startRecord(VolumnCallback, StartRecordCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public void StopRecord()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
stopRecord(StopRecordCallback);
|
||||
#elif UNITY_ANDROID
|
||||
AndroidJavaObject audio = AudioRecord.Call<AndroidJavaObject>("stopRecord");
|
||||
if (audio == null)
|
||||
{
|
||||
if (audioRecorderListener != null)
|
||||
audioRecorderListener.OnRecord(null);
|
||||
return;
|
||||
}
|
||||
int duration = audio.Get<int>("duration");
|
||||
byte[] audioData = audio.Get<byte[]>("audioData");
|
||||
//byte[] audioData = (byte[])(Array)audio.Get<sbyte[]>("audioData");
|
||||
if (cancelRecord)
|
||||
{
|
||||
cancelRecord = false;
|
||||
return;
|
||||
}
|
||||
if (audioRecorderListener != null)
|
||||
{
|
||||
RTMAudioData data = new RTMAudioData(audioData, language, duration);
|
||||
audioRecorderListener.OnRecord(data);
|
||||
}
|
||||
#else
|
||||
stopRecord(StopRecordCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public void CancelRecord()
|
||||
{
|
||||
cancelRecord = true;
|
||||
StopRecord();
|
||||
}
|
||||
|
||||
static public void Play(RTMAudioData data)
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
byte[] wavBuffer = AudioConvert.ConvertToWav(data.Audio);
|
||||
startPlay(wavBuffer, wavBuffer.Length, PlayFinishCallback, PlayStartCallback, speakerChanged);
|
||||
speakerChanged = false;
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
startPlay(data.Audio, data.Audio.Length, PlayFinishCallback, PlayStartCallback);
|
||||
#elif UNITY_ANDROID
|
||||
if (AudioRecord != null)
|
||||
AudioRecord.Call("broadAudio", AudioConvert.ConvertToWav(data.Audio));
|
||||
#else
|
||||
startPlay(data.Audio, data.Audio.Length, PlayFinishCallback, PlayStartCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static public void StopPlay()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
stopPlay();
|
||||
#elif UNITY_ANDROID
|
||||
if (AudioRecord != null)
|
||||
AudioRecord.Call("stopAudio");
|
||||
#else
|
||||
stopPlay();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 297ecbe86374440b18db4b398678923e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,337 @@
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public class AudioRecorder : Singleton<AudioRecorder>
|
||||
{
|
||||
public interface IMicrophone {
|
||||
void Start();
|
||||
void End();
|
||||
void OnRecord(RTMAudioData audioData);
|
||||
}
|
||||
|
||||
public static int RECORD_SAMPLE_RATE = 16000;
|
||||
private int LOUDNESS_SAMPLE_WINDOW = 128;
|
||||
private int UPDATE_LOUDNESS_MS = 50;
|
||||
|
||||
private int maxRecordSeconds = 60;
|
||||
private bool isPause;
|
||||
private bool isFocus;
|
||||
|
||||
private string lang;
|
||||
private string device;
|
||||
private bool isRecording;
|
||||
private float loudness;
|
||||
private long lastUpdateLoudnessTime = 0;
|
||||
|
||||
private int position;
|
||||
private AudioClip clipRecord;
|
||||
private IMicrophone micPhone;
|
||||
private object selfLocker = new object();
|
||||
|
||||
void OnEnable() {
|
||||
this.isPause = false;
|
||||
this.isFocus = false;
|
||||
}
|
||||
|
||||
void OnDisable() {
|
||||
StopAllCoroutines();
|
||||
CancelInput();
|
||||
}
|
||||
|
||||
void OnApplicationPause() {
|
||||
if (!this.isPause) {
|
||||
CancelInput();
|
||||
} else {
|
||||
this.isFocus = true;
|
||||
}
|
||||
|
||||
this.isPause = true;
|
||||
}
|
||||
|
||||
void OnApplicationFocus() {
|
||||
if (isFocus) {
|
||||
isPause = false;
|
||||
isFocus = false;
|
||||
}
|
||||
|
||||
if (isPause) {
|
||||
isFocus = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Update() {
|
||||
lock (selfLocker) {
|
||||
if (!isRecording)
|
||||
return;
|
||||
|
||||
long now = ClientEngine.GetCurrentMilliseconds();
|
||||
if (now - lastUpdateLoudnessTime > UPDATE_LOUDNESS_MS) {
|
||||
lastUpdateLoudnessTime = now;
|
||||
UpdateLoudness();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateLoudness() {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
float levelMax = 0;
|
||||
float[] data = new float[LOUDNESS_SAMPLE_WINDOW];
|
||||
int pos = Microphone.GetPosition(device) - (LOUDNESS_SAMPLE_WINDOW + 1);
|
||||
|
||||
if (pos < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
clipRecord.GetData(data, pos);
|
||||
|
||||
for (int i = 0; i < LOUDNESS_SAMPLE_WINDOW; i++) {
|
||||
float wavePeak = data[i] * data[i];
|
||||
if (levelMax < wavePeak) {
|
||||
levelMax = wavePeak;
|
||||
}
|
||||
}
|
||||
loudness = levelMax;
|
||||
#endif
|
||||
}
|
||||
|
||||
private IEnumerator TimeDown() {
|
||||
int time = 0;
|
||||
while (++time <= this.maxRecordSeconds) {
|
||||
lock (selfLocker) {
|
||||
if (!isRecording) {
|
||||
yield return 0;
|
||||
}
|
||||
}
|
||||
yield return new WaitForSeconds(1);
|
||||
}
|
||||
FinishInput();
|
||||
}
|
||||
|
||||
public void Init(string lang, string device, IMicrophone micPhone) {
|
||||
position = 0;
|
||||
isRecording = false;
|
||||
this.lang = lang;
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone != null) {
|
||||
this.micPhone = micPhone;
|
||||
}
|
||||
|
||||
lock (selfLocker) {
|
||||
this.device = device;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void SetLanguage(string lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
public int GetRelativeLoudness(float maxLoudness) {
|
||||
float loudnessNormalized = loudness;
|
||||
if (loudnessNormalized > maxLoudness)
|
||||
loudnessNormalized = maxLoudness;
|
||||
return (int)(loudnessNormalized / maxLoudness * 100);
|
||||
}
|
||||
|
||||
public float GetAbsoluteLoudness() {
|
||||
return loudness;
|
||||
}
|
||||
|
||||
public void StartInput(int maxRecordSeconds = 60) {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Microphone.devices.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock (selfLocker) {
|
||||
if (device == null) {
|
||||
device = Microphone.devices[0];
|
||||
}
|
||||
|
||||
if (isRecording) {
|
||||
return;
|
||||
}
|
||||
this.maxRecordSeconds = maxRecordSeconds;
|
||||
isRecording = true;
|
||||
clipRecord = Microphone.Start(device, false, this.maxRecordSeconds, RECORD_SAMPLE_RATE);
|
||||
micPhone.Start();
|
||||
}
|
||||
StartCoroutine("TimeDown");
|
||||
#endif
|
||||
}
|
||||
|
||||
public void FinishInput() {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool timeDown = false;
|
||||
lock (selfLocker) {
|
||||
if (isRecording) {
|
||||
timeDown = true;
|
||||
isRecording = false;
|
||||
position = Microphone.GetPosition(device);
|
||||
Microphone.End(device);
|
||||
micPhone.End();
|
||||
}
|
||||
}
|
||||
|
||||
if (timeDown) {
|
||||
StopCoroutine("TimeDown");
|
||||
|
||||
if (micPhone != null && clipRecord != null) {
|
||||
GetAudioData(clipRecord);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
loudness = 0;
|
||||
}
|
||||
|
||||
public void CancelInput() {
|
||||
#if RTM_BUILD_NO_AUDIO
|
||||
throw new Exception("Audio is disabled, please remove the RTM_BUILD_NO_AUDIO define in \"Scripting Define Symbols\"");
|
||||
#else
|
||||
if (micPhone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool timeDown = false;
|
||||
lock (selfLocker) {
|
||||
if (isRecording) {
|
||||
timeDown = true;
|
||||
isRecording = false;
|
||||
Microphone.End(device);
|
||||
micPhone.End();
|
||||
}
|
||||
}
|
||||
|
||||
if (timeDown) {
|
||||
StopCoroutine("TimeDown");
|
||||
}
|
||||
#endif
|
||||
loudness = 0;
|
||||
}
|
||||
|
||||
private void GetAudioData(AudioClip clip) {
|
||||
var soundData = new float[clip.samples * clip.channels];
|
||||
clip.GetData(soundData, 0);
|
||||
var newData = new float[position * clip.channels];
|
||||
|
||||
for (int i = 0; i < newData.Length; i++) {
|
||||
newData[i] = soundData[i];
|
||||
}
|
||||
var newClip = AudioClip.Create (clip.name,
|
||||
position,
|
||||
clip.channels,
|
||||
clip.frequency,
|
||||
false);
|
||||
|
||||
newClip.SetData(newData, 0);
|
||||
long duration = (long)(newClip.length * 1000);
|
||||
|
||||
MemoryStream amrStream = new MemoryStream();
|
||||
ConvertAndWriteWav(amrStream, newClip);
|
||||
WriteWavHeader(amrStream, newClip);
|
||||
int lengthSamples = newClip.samples;
|
||||
|
||||
ClientEngine.RunTask(() => {
|
||||
micPhone.OnRecord(new RTMAudioData(AudioConvert.ConvertToAmrwb(amrStream.ToArray()), newData, RTMAudioData.DefaultCodec, lang, duration, lengthSamples, RECORD_SAMPLE_RATE));
|
||||
});
|
||||
}
|
||||
|
||||
private void ConvertAndWriteWav(MemoryStream stream, AudioClip clip) {
|
||||
float[] samples = new float[clip.samples];
|
||||
clip.GetData(samples, 0);
|
||||
|
||||
Int16[] intData = new Int16[samples.Length];
|
||||
|
||||
Byte[] bytesData = new Byte[samples.Length * 2];
|
||||
|
||||
int rescaleFactor = 32767;
|
||||
|
||||
for (int i = 0; i < samples.Length; i++)
|
||||
{
|
||||
intData[i] = (short)(samples[i] * rescaleFactor);
|
||||
Byte[] byteArr = new Byte[2];
|
||||
byteArr = BitConverter.GetBytes(intData[i]);
|
||||
byteArr.CopyTo(bytesData, i * 2);
|
||||
}
|
||||
stream.Write(bytesData, 0, bytesData.Length);
|
||||
}
|
||||
|
||||
public static void WriteWavHeader(MemoryStream stream, AudioClip clip)
|
||||
{
|
||||
int hz = clip.frequency;
|
||||
int channels = clip.channels;
|
||||
int samples = clip.samples;
|
||||
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
Byte[] riff = System.Text.Encoding.UTF8.GetBytes("RIFF");
|
||||
stream.Write(riff, 0, 4);
|
||||
|
||||
Byte[] chunkSize = BitConverter.GetBytes(stream.Length - 8);
|
||||
stream.Write(chunkSize, 0, 4);
|
||||
|
||||
Byte[] wave = System.Text.Encoding.UTF8.GetBytes("WAVE");
|
||||
stream.Write(wave, 0, 4);
|
||||
|
||||
Byte[] fmt = System.Text.Encoding.UTF8.GetBytes("fmt ");
|
||||
stream.Write(fmt, 0, 4);
|
||||
|
||||
Byte[] subChunk1 = BitConverter.GetBytes(16);
|
||||
stream.Write(subChunk1, 0, 4);
|
||||
UInt16 one = 1;
|
||||
Byte[] audioFormat = BitConverter.GetBytes(one);
|
||||
stream.Write(audioFormat, 0, 2);
|
||||
|
||||
Byte[] numChannels = BitConverter.GetBytes(channels);
|
||||
stream.Write(numChannels, 0, 2);
|
||||
|
||||
Byte[] sampleRate = BitConverter.GetBytes(hz);
|
||||
stream.Write(sampleRate, 0, 4);
|
||||
|
||||
Byte[] byteRate = BitConverter.GetBytes(hz * channels * 2);
|
||||
stream.Write(byteRate, 0, 4);
|
||||
|
||||
UInt16 blockAlign = (ushort)(channels * 2);
|
||||
stream.Write(BitConverter.GetBytes(blockAlign), 0, 2);
|
||||
|
||||
UInt16 bps = 16;
|
||||
Byte[] bitsPerSample = BitConverter.GetBytes(bps);
|
||||
stream.Write(bitsPerSample, 0, 2);
|
||||
|
||||
Byte[] datastring = System.Text.Encoding.UTF8.GetBytes("data");
|
||||
stream.Write(datastring, 0, 4);
|
||||
|
||||
Byte[] subChunk2 = BitConverter.GetBytes(samples * channels * 2);
|
||||
stream.Write(subChunk2, 0, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f568454c4f1fc45d4acea6416df9086e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,182 @@
|
||||
#if UNITY_2017_1_OR_NEWER
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using AOT;
|
||||
using UnityEngine;
|
||||
|
||||
namespace com.fpnn.rtm
|
||||
{
|
||||
public enum NetworkType
|
||||
{
|
||||
NetworkType_Uninited = -2,
|
||||
NetworkType_Unknown = -1,
|
||||
NetworkType_Unreachable = 0,
|
||||
NetworkType_4G = 1,
|
||||
NetworkType_Wifi = 2,
|
||||
}
|
||||
public class StatusMonitor : Singleton<StatusMonitor>
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void initNetworkStatusChecker(NetworkStatusDelegate callback);
|
||||
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void closeNetworkStatusChecker();
|
||||
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
[DllImport("RTMNative")]
|
||||
private static extern void initNetworkStatusChecker(NetworkStatusDelegate callback);
|
||||
#elif UNITY_IOS
|
||||
[DllImport("__Internal")]
|
||||
private static extern void initNetworkStatusChecker(NetworkStatusDelegate callback);
|
||||
#elif UNITY_ANDROID
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void HeadsetStatusDelegate(int networkStatus);
|
||||
|
||||
[MonoPInvokeCallback(typeof(HeadsetStatusDelegate))]
|
||||
public static void HeadsetStatusCallback(int headsetType)
|
||||
{
|
||||
}
|
||||
|
||||
static AndroidJavaObject AndroidNativeManager= null;
|
||||
class NetChangeListener : AndroidJavaProxy
|
||||
{
|
||||
Action<int> msgCallback;
|
||||
public NetChangeListener(Action<int> callback) : base("com.NetForUnity.INetChange") { msgCallback = callback; }
|
||||
public void netChangeNotify(int type)
|
||||
{
|
||||
msgCallback(type);
|
||||
}
|
||||
}
|
||||
class HeadsetListener: AndroidJavaProxy
|
||||
{
|
||||
Action<int> headsetCallback;
|
||||
public HeadsetListener(Action<int> callback) : base("com.NetForUnity.IHeadsetChange") { headsetCallback = callback; }
|
||||
|
||||
public void headsetChange(int type) // //0-无网 1-移动网络 2-wifi
|
||||
{
|
||||
headsetCallback(type);
|
||||
}
|
||||
}
|
||||
private static void initNetworkStatusChecker(Action<int> netChangeCallback, Action<int> headersetCallback)
|
||||
{
|
||||
if (AndroidNativeManager == null)
|
||||
{
|
||||
AndroidJavaClass playerClass = new AndroidJavaClass("com.NetForUnity.ListenUnity");
|
||||
AndroidNativeManager = playerClass.CallStatic<AndroidJavaObject>("getInstance");
|
||||
}
|
||||
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
||||
var context = jc.GetStatic<AndroidJavaObject>("currentActivity");
|
||||
AndroidNativeManager.Call("registerNetChange", context, new NetChangeListener(netChangeCallback));
|
||||
AndroidNativeManager.Call("registerHeadsetChange", context, new HeadsetListener(headersetCallback));
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
delegate void NetworkStatusDelegate(int networkStatus);
|
||||
|
||||
[MonoPInvokeCallback(typeof(NetworkStatusDelegate))]
|
||||
static void NetworkStatusCallback(int networkStatus)
|
||||
{
|
||||
RTMControlCenter.NetworkChanged((NetworkType)networkStatus);
|
||||
}
|
||||
|
||||
static private bool _isPause;
|
||||
static private bool _isFocus;
|
||||
static private bool _isBackground;
|
||||
|
||||
internal static bool IsBackground() { return _isBackground; }
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_isPause = false;
|
||||
_isFocus = true;
|
||||
_isBackground = false;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
initNetworkStatusChecker(NetworkStatusCallback);
|
||||
#elif (UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX)
|
||||
initNetworkStatusChecker(NetworkStatusCallback);
|
||||
#elif UNITY_IOS
|
||||
initNetworkStatusChecker(NetworkStatusCallback);
|
||||
#elif UNITY_ANDROID
|
||||
initNetworkStatusChecker(NetworkStatusCallback, HeadsetStatusCallback);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
closeNetworkStatusChecker();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//#if (UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN)
|
||||
// public void Start()
|
||||
// {
|
||||
// StartCoroutine(PerSecondCoroutine());
|
||||
// }
|
||||
//
|
||||
// public void OnDestroy()
|
||||
// {
|
||||
// StopAllCoroutines();
|
||||
// }
|
||||
//
|
||||
// private IEnumerator PerSecondCoroutine()
|
||||
// {
|
||||
// yield return new WaitForSeconds(1.0f);
|
||||
//
|
||||
// while (true)
|
||||
// {
|
||||
// CheckNetworkChange();
|
||||
//
|
||||
// yield return new WaitForSeconds(1.0f);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private void CheckNetworkChange()
|
||||
// {
|
||||
// int networkStatus = (int)Application.internetReachability;
|
||||
// RTMControlCenter.NetworkChanged((NetworkType)networkStatus);
|
||||
// }
|
||||
//#endif
|
||||
|
||||
private void CheckInBackground()
|
||||
{
|
||||
if (_isPause && !_isFocus)
|
||||
{
|
||||
if (_isBackground == false)
|
||||
{
|
||||
_isBackground = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_isBackground)
|
||||
{
|
||||
_isBackground = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnApplicationPause(bool pauseStatus)
|
||||
{
|
||||
_isPause = pauseStatus;
|
||||
CheckInBackground();
|
||||
}
|
||||
|
||||
void OnApplicationFocus(bool hasFocus)
|
||||
{
|
||||
_isFocus = hasFocus;
|
||||
CheckInBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d55621c6e649e4542952aed2bc0f5cf4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user