non-vr lobby, version fix
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.MacOS
|
||||
{
|
||||
public class AudioInChangeNotifier : IAudioInChangeNotifier
|
||||
{
|
||||
public bool IsSupported => true;
|
||||
|
||||
const string lib_name = "AudioIn";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreateChangeNotifier(int instanceID, Action<int> callback);
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_DestroyChangeNotifier(IntPtr handle);
|
||||
|
||||
private delegate void CallbackDelegate(int instanceID);
|
||||
|
||||
IntPtr handle;
|
||||
int instanceID;
|
||||
Action callback;
|
||||
|
||||
public AudioInChangeNotifier(Action callback, ILogger logger)
|
||||
{
|
||||
this.callback = callback;
|
||||
//nativeCallback(8888);
|
||||
var handle = Photon_Audio_In_CreateChangeNotifier(instanceCnt, nativeCallback);
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.instanceID = instanceCnt;
|
||||
instancePerHandle.Add(instanceCnt++, this);
|
||||
}
|
||||
}
|
||||
|
||||
// IL2CPP does not support marshaling delegates that point to instance methods to native code.
|
||||
// Using static method and per instance table.
|
||||
static int instanceCnt;
|
||||
private static Dictionary<int, AudioInChangeNotifier> instancePerHandle = new Dictionary<int, AudioInChangeNotifier>();
|
||||
[MonoPInvokeCallbackAttribute(typeof(CallbackDelegate))]
|
||||
private static void nativeCallback(int instanceID)
|
||||
{
|
||||
AudioInChangeNotifier instance;
|
||||
bool ok;
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
ok = instancePerHandle.TryGetValue(instanceID, out instance);
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
instance.callback();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>If not null, the enumerator is in invalid state.</summary>
|
||||
public string Error { get; private set; }
|
||||
|
||||
/// <summary>Disposes enumerator.
|
||||
/// Call it to free native resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
instancePerHandle.Remove(instanceID);
|
||||
}
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_DestroyChangeNotifier(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 893b0d66c964e974798c7da6a2e88cd0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.MacOS
|
||||
{
|
||||
public class MonoPInvokeCallbackAttribute : System.Attribute
|
||||
{
|
||||
private Type type;
|
||||
public MonoPInvokeCallbackAttribute(Type t) { type = t; }
|
||||
}
|
||||
|
||||
public class AudioInPusher : IAudioPusher<float>
|
||||
{
|
||||
const string lib_name = "AudioIn";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreatePusher(int instanceID, int deviceID, Action<int, IntPtr, int> pushCallback);
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_Destroy(IntPtr handler);
|
||||
|
||||
private delegate void CallbackDelegate(int instanceID, IntPtr buf, int len);
|
||||
|
||||
public AudioInPusher(int deviceID, ILogger logger)
|
||||
{
|
||||
this.deviceID = deviceID;
|
||||
try
|
||||
{
|
||||
handle = Photon_Audio_In_CreatePusher(instanceCnt, deviceID, nativePushCallback);
|
||||
instancePerHandle.Add(instanceCnt++, this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error = e.ToString();
|
||||
if (Error == null) // should never happen but since Error used as validity flag, make sure that it's not null
|
||||
{
|
||||
Error = "Exception in AudioInPusher constructor";
|
||||
}
|
||||
logger.LogError("[PV] AudioInPusher: " + Error);
|
||||
}
|
||||
}
|
||||
|
||||
private int deviceID;
|
||||
// IL2CPP does not support marshaling delegates that point to instance methods to native code.
|
||||
// Using static method and per instance table.
|
||||
static int instanceCnt;
|
||||
private static Dictionary<int, AudioInPusher> instancePerHandle = new Dictionary<int, AudioInPusher>();
|
||||
[MonoPInvokeCallbackAttribute(typeof(CallbackDelegate))]
|
||||
private static void nativePushCallback(int instanceID, IntPtr buf, int len)
|
||||
{
|
||||
AudioInPusher instance;
|
||||
if (instancePerHandle.TryGetValue(instanceID, out instance))
|
||||
{
|
||||
instance.push(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
IntPtr handle;
|
||||
Action<float[]> pushCallback;
|
||||
ObjectFactory<float[], int> bufferFactory;
|
||||
|
||||
// Supposed to be called once at voice initialization.
|
||||
// Otherwise recreate native object (instead of adding 'set callback' method to native interface)
|
||||
public void SetCallback(Action<float[]> callback, ObjectFactory<float[], int> bufferFactory)
|
||||
{
|
||||
this.bufferFactory = bufferFactory;
|
||||
this.pushCallback = callback;
|
||||
}
|
||||
private void push(IntPtr buf, int len)
|
||||
{
|
||||
if (this.pushCallback != null)
|
||||
{
|
||||
var bufManaged = bufferFactory.New(len);
|
||||
Marshal.Copy(buf, bufManaged, 0, len);
|
||||
pushCallback(bufManaged);
|
||||
}
|
||||
}
|
||||
|
||||
public int Channels { get { return 1; } }
|
||||
|
||||
public int SamplingRate { get { return 44100; } }
|
||||
|
||||
public string Error { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_Destroy(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
// TODO: Remove this from instancePerHandle
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0e2dc3e0f865a747b515b1a0450cc12
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.MacOS
|
||||
{
|
||||
public class AudioInReader : IAudioReader<float>
|
||||
{
|
||||
const string lib_name = "AudioIn";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreateReader(int deviceID);
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_Destroy(IntPtr handler);
|
||||
[DllImport(lib_name)]
|
||||
private static extern bool Photon_Audio_In_Read(IntPtr handle, float[] buf, int len);
|
||||
|
||||
IntPtr audioIn;
|
||||
|
||||
public AudioInReader(int deviceID, ILogger logger)
|
||||
{
|
||||
try
|
||||
{
|
||||
audioIn = Photon_Audio_In_CreateReader(deviceID);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error = e.ToString();
|
||||
if (Error == null) // should never happen but since Error used as validity flag, make sure that it's not null
|
||||
{
|
||||
Error = "Exception in AudioInReader constructor";
|
||||
}
|
||||
logger.LogError("[PV] AudioInReader: " + Error);
|
||||
}
|
||||
}
|
||||
public int Channels { get { return 1; } }
|
||||
|
||||
public int SamplingRate { get { return 44100; } }
|
||||
|
||||
public string Error { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (audioIn != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_Destroy(audioIn);
|
||||
audioIn = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Read(float[] buf)
|
||||
{
|
||||
return audioIn != IntPtr.Zero && Photon_Audio_In_Read(audioIn, buf, buf.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f22e06cf781af34abf9e24bf6010fce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.MacOS
|
||||
{
|
||||
/// <summary>Enumerates microphones available on device.
|
||||
/// </summary>
|
||||
public class AudioInEnumerator : DeviceEnumeratorBase
|
||||
{
|
||||
const string lib_name = "AudioIn";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreateMicEnumerator();
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_DestroyMicEnumerator(IntPtr handle);
|
||||
[DllImport(lib_name)]
|
||||
private static extern int Photon_Audio_In_MicEnumerator_Count(IntPtr handle);
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_MicEnumerator_NameAtIndex(IntPtr handle, int idx);
|
||||
[DllImport(lib_name)]
|
||||
private static extern int Photon_Audio_In_MicEnumerator_IDAtIndex(IntPtr handle, int idx);
|
||||
|
||||
IntPtr handle;
|
||||
public AudioInEnumerator(ILogger logger) : base(logger)
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// <summary>Refreshes the microphones list.
|
||||
/// </summary>
|
||||
public override void Refresh()
|
||||
{
|
||||
Dispose();
|
||||
try
|
||||
{
|
||||
handle = Photon_Audio_In_CreateMicEnumerator();
|
||||
var count = Photon_Audio_In_MicEnumerator_Count(handle);
|
||||
devices = new List<DeviceInfo>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
devices.Add(new DeviceInfo(Photon_Audio_In_MicEnumerator_IDAtIndex(handle, i), Marshal.PtrToStringAuto(Photon_Audio_In_MicEnumerator_NameAtIndex(handle, i))));
|
||||
}
|
||||
Error = null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error = e.ToString();
|
||||
if (Error == null) // should never happen but since Error used as validity flag, make sure that it's not null
|
||||
{
|
||||
Error = "Exception in AudioInEnumerator.Refresh()";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Disposes enumerator.
|
||||
/// Call it to free native resources.
|
||||
/// </summary>
|
||||
public override void Dispose()
|
||||
{
|
||||
if (handle != IntPtr.Zero && Error == null)
|
||||
{
|
||||
Photon_Audio_In_DestroyMicEnumerator(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7dcf1a594e0ea9845b5ec7ae2931428b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,83 @@
|
||||
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.IOS
|
||||
{
|
||||
public class AudioInChangeNotifier : IAudioInChangeNotifier
|
||||
{
|
||||
public bool IsSupported => true;
|
||||
|
||||
const string lib_name = "__Internal";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreateChangeNotifier(int instanceID, Action<int> callback);
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_DestroyChangeNotifier(IntPtr handle);
|
||||
|
||||
private delegate void CallbackDelegate(int instanceID);
|
||||
|
||||
IntPtr handle;
|
||||
int instanceID;
|
||||
Action callback;
|
||||
|
||||
public AudioInChangeNotifier(Action callback, ILogger logger)
|
||||
{
|
||||
this.callback = callback;
|
||||
var handle = Photon_Audio_In_CreateChangeNotifier(instanceCnt, nativeCallback);
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.instanceID = instanceCnt;
|
||||
instancePerHandle.Add(instanceCnt++, this);
|
||||
}
|
||||
}
|
||||
|
||||
public class MonoPInvokeCallbackAttribute : System.Attribute
|
||||
{
|
||||
private Type type;
|
||||
public MonoPInvokeCallbackAttribute(Type t) { type = t; }
|
||||
}
|
||||
|
||||
// IL2CPP does not support marshaling delegates that point to instance methods to native code.
|
||||
// Using static method and per instance table.
|
||||
static int instanceCnt;
|
||||
private static Dictionary<int, AudioInChangeNotifier> instancePerHandle = new Dictionary<int, AudioInChangeNotifier>();
|
||||
[MonoPInvokeCallbackAttribute(typeof(CallbackDelegate))]
|
||||
private static void nativeCallback(int instanceID)
|
||||
{
|
||||
AudioInChangeNotifier instance;
|
||||
bool ok;
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
ok = instancePerHandle.TryGetValue(instanceID, out instance);
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
instance.callback();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>If not null, the enumerator is in invalid state.</summary>
|
||||
public string Error { get; private set; }
|
||||
|
||||
/// <summary>Disposes enumerator.
|
||||
/// Call it to free native resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
instancePerHandle.Remove(instanceID);
|
||||
}
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_DestroyChangeNotifier(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18c26ffb450f01444a49013a7455b8e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,139 @@
|
||||
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.IOS
|
||||
{
|
||||
public class MonoPInvokeCallbackAttribute : System.Attribute
|
||||
{
|
||||
private Type type;
|
||||
public MonoPInvokeCallbackAttribute(Type t) { type = t; }
|
||||
}
|
||||
|
||||
public class AudioInPusher : IAudioPusher<float>, IResettable
|
||||
{
|
||||
const string lib_name = "__Internal";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreatePusher(int instanceID, Action<int, IntPtr, int> pushCallback, int sessionCategory, int sessionMode, int sessionCategoryOptions);
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_Reset(IntPtr handler);
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_Destroy(IntPtr handler);
|
||||
|
||||
private delegate void CallbackDelegate(int instanceID, IntPtr buf, int len);
|
||||
private bool initializationFinished;
|
||||
|
||||
public AudioInPusher(AudioSessionParameters sessParam, ILogger logger)
|
||||
{
|
||||
// initialization in a separate thread to avoid 0.5 - 1 sec. pauses in main thread execution
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
lock (instancePerHandle) // prevent concurrent initialization
|
||||
{
|
||||
try
|
||||
{
|
||||
var handle = Photon_Audio_In_CreatePusher(instanceCnt, nativePushCallback, (int)sessParam.Category, (int)sessParam.Mode, sessParam.CategoryOptionsToInt());
|
||||
this.handle = handle;
|
||||
this.instanceID = instanceCnt;
|
||||
instancePerHandle.Add(instanceCnt++, this);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error = e.ToString();
|
||||
if (Error == null) // should never happen but since Error used as validity flag, make sure that it's not null
|
||||
{
|
||||
Error = "Exception in AudioInPusher constructor";
|
||||
}
|
||||
logger.LogError("[PV] AudioInPusher: " + Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
initializationFinished = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
Util.SetThreadName(t, "[PV] IOSAudioInPusherCtr");
|
||||
t.Start();
|
||||
}
|
||||
|
||||
// IL2CPP does not support marshaling delegates that point to instance methods to native code.
|
||||
// Using static method and per instance table.
|
||||
static int instanceCnt;
|
||||
private static Dictionary<int, AudioInPusher> instancePerHandle = new Dictionary<int, AudioInPusher>();
|
||||
[MonoPInvokeCallbackAttribute(typeof(CallbackDelegate))]
|
||||
private static void nativePushCallback(int instanceID, IntPtr buf, int len)
|
||||
{
|
||||
AudioInPusher instance;
|
||||
bool ok;
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
ok = instancePerHandle.TryGetValue(instanceID, out instance);
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
instance.push(buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
IntPtr handle;
|
||||
int instanceID;
|
||||
Action<float[]> pushCallback;
|
||||
ObjectFactory<float[], int> bufferFactory;
|
||||
|
||||
// Supposed to be called once at voice initialization.
|
||||
// Otherwise recreate native object (instead of adding 'set callback' method to native interface)
|
||||
public void SetCallback(Action<float[]> callback, ObjectFactory<float[], int> bufferFactory)
|
||||
{
|
||||
this.bufferFactory = bufferFactory;
|
||||
this.pushCallback = callback;
|
||||
}
|
||||
private void push(IntPtr buf, int len)
|
||||
{
|
||||
if (this.pushCallback != null)
|
||||
{
|
||||
var bufManaged = bufferFactory.New(len);
|
||||
Marshal.Copy(buf, bufManaged, 0, len);
|
||||
pushCallback(bufManaged);
|
||||
}
|
||||
}
|
||||
|
||||
public int Channels { get { return 1; } }
|
||||
|
||||
public int SamplingRate { get { return 48000; } }
|
||||
|
||||
public string Error { get; private set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_Reset(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (instancePerHandle)
|
||||
{
|
||||
instancePerHandle.Remove(instanceID);
|
||||
|
||||
while (!initializationFinished) // should never happen because of lock if the thread in constructor started before Dispose() call
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
if (handle != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_Destroy(handle);
|
||||
handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a173aa7f3a7bbc94aa78a6747d55f3f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Photon.Voice.IOS
|
||||
{
|
||||
public class AudioInReader : IAudioReader<float>, IResettable
|
||||
{
|
||||
const string lib_name = "__Internal";
|
||||
[DllImport(lib_name)]
|
||||
private static extern IntPtr Photon_Audio_In_CreateReader(int sessionCategory, int sessionMode, int sessionCategoryOptions);
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_Reset(IntPtr handler);
|
||||
[DllImport(lib_name)]
|
||||
private static extern void Photon_Audio_In_Destroy(IntPtr handler);
|
||||
[DllImport(lib_name)]
|
||||
private static extern bool Photon_Audio_In_Read(IntPtr handle, float[] buf, int len);
|
||||
|
||||
IntPtr audioIn;
|
||||
private bool initializationFinished;
|
||||
|
||||
public AudioInReader(AudioSessionParameters sessParam, ILogger logger)
|
||||
{
|
||||
// initialization in a separate thread to avoid 0.5 - 1 sec. pauses in main thread execution
|
||||
var t = new Thread(() =>
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
try
|
||||
{
|
||||
var audioIn = Photon_Audio_In_CreateReader((int)sessParam.Category, (int)sessParam.Mode, sessParam.CategoryOptionsToInt());
|
||||
lock (this)
|
||||
{
|
||||
this.audioIn = audioIn;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Error = e.ToString();
|
||||
if (Error == null) // should never happen but since Error used as validity flag, make sure that it's not null
|
||||
{
|
||||
Error = "Exception in AudioInReader constructor";
|
||||
}
|
||||
logger.LogError("[PV] AudioInReader: " + Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
initializationFinished = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
Util.SetThreadName(t, "[PV] IOSAudioInReaderCtr");
|
||||
t.Start();
|
||||
}
|
||||
public int Channels { get { return 1; } }
|
||||
|
||||
public int SamplingRate { get { return 48000; } }
|
||||
|
||||
public string Error { get; private set; }
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (audioIn != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_Reset(audioIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
while (!initializationFinished) // should never happen because of lock if the thread in constructor started before Dispose() call
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
if (audioIn != IntPtr.Zero)
|
||||
{
|
||||
Photon_Audio_In_Destroy(audioIn);
|
||||
audioIn = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Read(float[] buf)
|
||||
{
|
||||
return audioIn != IntPtr.Zero && Photon_Audio_In_Read(audioIn, buf, buf.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c99541283e96384ea52e265269b1dee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,346 @@
|
||||
namespace Photon.Voice.IOS
|
||||
{
|
||||
public enum AudioSessionCategory // values are the same as in AudioIn.mm enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Use this category for background sounds such as rain, car engine noise, etc.
|
||||
/// Mixes with other music.
|
||||
/// </summary>
|
||||
/// <remarks>API_AVAILABLE(ios(3.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);</remarks>
|
||||
Ambient = 0,
|
||||
|
||||
/// <summary> Use this category for background sounds. Other music will stop playing. </summary>
|
||||
/// <remarks>API_AVAILABLE(ios(3.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);</remarks>
|
||||
SoloAmbient = 1,
|
||||
|
||||
/// <summary> Use this category for music tracks. </summary>
|
||||
/// <remarks>API_AVAILABLE(ios(3.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);</remarks>
|
||||
Playback = 2,
|
||||
|
||||
/// <summary> Use this category when recording audio. </summary>
|
||||
/// <remarks>API_AVAILABLE(ios(3.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);</remarks>
|
||||
Record = 3,
|
||||
|
||||
/// <summary> Use this category when recording and playing back audio. </summary>
|
||||
/// <remarks>API_AVAILABLE(ios(3.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);</remarks>
|
||||
PlayAndRecord = 4,
|
||||
|
||||
/// <summary> Use this category when using a hardware codec or signal processor while
|
||||
/// not playing or recording audio. </summary>
|
||||
/// <remarks>API_DEPRECATED("No longer supported", ios(3.0, 10.0)) API_UNAVAILABLE(watchos, tvos) API_UNAVAILABLE(macos);</remarks>
|
||||
AudioProcessing = 5,
|
||||
|
||||
/// <summary> Use this category to customize the usage of available audio accessories and built-in audio hardware.
|
||||
/// For example, this category provides an application with the ability to use an available USB output
|
||||
/// and headphone output simultaneously for separate, distinct streams of audio data. Use of
|
||||
/// this category by an application requires a more detailed knowledge of, and interaction with,
|
||||
/// the capabilities of the available audio routes. May be used for input, output, or both.
|
||||
/// Note that not all output types and output combinations are eligible for multi-route. Input is limited
|
||||
/// to the last-in input port. Eligible inputs consist of the following:
|
||||
/// AVAudioSessionPortUSBAudio, AVAudioSessionPortHeadsetMic, and AVAudioSessionPortBuiltInMic.
|
||||
/// Eligible outputs consist of the following:
|
||||
/// AVAudioSessionPortUSBAudio, AVAudioSessionPortLineOut, AVAudioSessionPortHeadphones, AVAudioSessionPortHDMI,
|
||||
/// and AVAudioSessionPortBuiltInSpeaker.
|
||||
/// Note that AVAudioSessionPortBuiltInSpeaker is only allowed to be used when there are no other eligible
|
||||
/// outputs connected. </summary>
|
||||
/// <remarks>API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);</remarks>
|
||||
MultiRoute = 6,
|
||||
}
|
||||
|
||||
public enum AudioSessionMode // values are the same as in AudioIn.mm enums
|
||||
{
|
||||
/// <summary>
|
||||
/// Modes modify the audio category in order to introduce behavior that is tailored to the specific
|
||||
/// use of audio within an application. Available in iOS 5.0 and greater.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The default mode
|
||||
/// API_AVAILABLE(ios(5.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
/// </remarks>
|
||||
Default = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Only valid with AVAudioSessionCategoryPlayAndRecord. Appropriate for Voice over IP
|
||||
/// (VoIP) applications. Reduces the number of allowable audio routes to be only those
|
||||
/// that are appropriate for VoIP applications and may engage appropriate system-supplied
|
||||
/// signal processing. Has the side effect of setting AVAudioSessionCategoryOptionAllowBluetooth
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// API_AVAILABLE(ios(5.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
/// </remarks>
|
||||
VoiceChat = 1,
|
||||
|
||||
/* Set by Game Kit on behalf of an application that uses a GKVoiceChat object; valid
|
||||
only with the AVAudioSessionCategoryPlayAndRecord category.
|
||||
Do not set this mode directly. If you need similar behavior and are not using
|
||||
a GKVoiceChat object, use AVAudioSessionModeVoiceChat instead. */
|
||||
// GameChat = 2, // API_AVAILABLE(ios(5.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
|
||||
/// <summary>
|
||||
/// Only valid with AVAudioSessionCategoryPlayAndRecord or AVAudioSessionCategoryRecord.
|
||||
/// Modifies the audio routing options and may engage appropriate system-supplied signal processing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// API_AVAILABLE(ios(5.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
/// </remarks>
|
||||
VideoRecording = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Appropriate for applications that wish to minimize the effect of system-supplied signal
|
||||
/// processing for input and/or output audio signals.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// API_AVAILABLE(ios(5.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
/// </remarks>
|
||||
Measurement = 4,
|
||||
|
||||
/// <summary>
|
||||
/// Engages appropriate output signal processing for movie playback scenarios. Currently
|
||||
/// only applied during playback over built-in speaker.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
/// </remarks>
|
||||
MoviePlayback = 5,
|
||||
|
||||
/// <summary>
|
||||
/// Only valid with kAudioSessionCategory_PlayAndRecord. Reduces the number of allowable audio
|
||||
/// routes to be only those that are appropriate for video chat applications. May engage appropriate
|
||||
/// system-supplied signal processing. Has the side effect of setting
|
||||
/// AVAudioSessionCategoryOptionAllowBluetooth and AVAudioSessionCategoryOptionDefaultToSpeaker.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
/// </remarks>
|
||||
VideoChat = 6,
|
||||
|
||||
/* Appropriate for applications which play spoken audio and wish to be paused (via audio session interruption) rather than ducked
|
||||
if another app (such as a navigation app) plays a spoken audio prompt. Examples of apps that would use this are podcast players and
|
||||
audio books. For more information, see the related category option AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers. */
|
||||
// SpokenAudio = 7, // API_AVAILABLE(ios(9.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
|
||||
|
||||
/* Appropriate for applications which play audio using text to speech. Setting this mode allows for different routing behaviors when
|
||||
connected to certain audio devices such as CarPlay. An example of an app that would use this mode is a turn by turn navigation app that
|
||||
plays short prompts to the user. Typically, these same types of applications would also configure their session to use
|
||||
AVAudioSessionCategoryOptionDuckOthers and AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers */
|
||||
// VoicePrompt = 8, // API_AVAILABLE(ios(12.0), watchos(5.0), tvos(12.0)) API_UNAVAILABLE(macos);
|
||||
}
|
||||
|
||||
public enum AudioSessionCategoryOption // values as defined in Apple Audio Session API
|
||||
{
|
||||
/*
|
||||
AVAudioSessionCategoryOptionMixWithOthers --
|
||||
This allows an application to set whether or not other active audio apps will be interrupted or mixed with
|
||||
when your app's audio session goes active. The typical cases are:
|
||||
(1) AVAudioSessionCategoryPlayAndRecord or AVAudioSessionCategoryMultiRoute
|
||||
this will default to false, but can be set to true. This would allow other applications to play in the background
|
||||
while an app had both audio input and output enabled
|
||||
(2) AVAudioSessionCategoryPlayback
|
||||
this will default to false, but can be set to true. This would allow other applications to play in the background,
|
||||
but an app will still be able to play regardless of the setting of the ringer switch
|
||||
(3) Other categories
|
||||
this defaults to false and cannot be changed (that is, the mix with others setting of these categories
|
||||
cannot be overridden. An application must be prepared for setting this property to fail as behaviour
|
||||
may change in future releases. If an application changes their category, they should reassert the
|
||||
option (it is not sticky across category changes).
|
||||
|
||||
AVAudioSessionCategoryOptionDuckOthers --
|
||||
This allows an application to set whether or not other active audio apps will be ducked when when your app's audio
|
||||
session goes active. An example of this is the Nike app, which provides periodic updates to its user (it reduces the
|
||||
volume of any music currently being played while it provides its status). This defaults to off. Note that the other
|
||||
audio will be ducked for as long as the current session is active. You will need to deactivate your audio
|
||||
session when you want full volume playback of the other audio.
|
||||
If your category is AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, or
|
||||
AVAudioSessionCategoryMultiRoute, by default the audio session will be non-mixable and non-ducking.
|
||||
Setting this option will also make your category mixable with others (AVAudioSessionCategoryOptionMixWithOthers
|
||||
will be set).
|
||||
|
||||
AVAudioSessionCategoryOptionAllowBluetooth --
|
||||
This allows an application to change the default behaviour of some audio session categories with regards to showing
|
||||
bluetooth Hands-Free Profile (HFP) devices as available routes. The current category behavior is:
|
||||
(1) AVAudioSessionCategoryPlayAndRecord
|
||||
this will default to false, but can be set to true. This will allow a paired bluetooth HFP device to show up as
|
||||
an available route for input, while playing through the category-appropriate output
|
||||
(2) AVAudioSessionCategoryRecord
|
||||
this will default to false, but can be set to true. This will allow a paired bluetooth HFP device to show up
|
||||
as an available route for input
|
||||
(3) Other categories
|
||||
this defaults to false and cannot be changed (that is, enabling bluetooth for input in these categories is
|
||||
not allowed)
|
||||
An application must be prepared for setting this option to fail as behaviour may change in future releases.
|
||||
If an application changes their category or mode, they should reassert the override (it is not sticky
|
||||
across category and mode changes).
|
||||
|
||||
AVAudioSessionCategoryOptionDefaultToSpeaker --
|
||||
This allows an application to change the default behaviour of some audio session categories with regards to
|
||||
the audio route. The current category behavior is:
|
||||
(1) AVAudioSessionCategoryPlayAndRecord category
|
||||
this will default to false, but can be set to true. this will route to Speaker (instead of Receiver)
|
||||
when no other audio route is connected.
|
||||
(2) Other categories
|
||||
this defaults to false and cannot be changed (that is, the default to speaker setting of these
|
||||
categories cannot be overridden
|
||||
An application must be prepared for setting this property to fail as behaviour may change in future releases.
|
||||
If an application changes their category, they should reassert the override (it is not sticky across
|
||||
category and mode changes).
|
||||
|
||||
AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers --
|
||||
If another app's audio session mode is set to AVAudioSessionModeSpokenAudio (podcast playback in the background for example),
|
||||
then that other app's audio will be interrupted when the current application's audio session goes active. An example of this
|
||||
is a navigation app that provides navigation prompts to its user (it pauses any spoken audio currently being played while it
|
||||
plays the prompt). This defaults to off. Note that the other app's audio will be paused for as long as the current session is
|
||||
active. You will need to deactivate your audio session to allow the other audio to resume playback.
|
||||
Setting this option will also make your category mixable with others (AVAudioSessionCategoryOptionMixWithOthers
|
||||
will be set). If you want other non-spoken audio apps to duck their audio when your app's session goes active, also set
|
||||
AVAudioSessionCategoryOptionDuckOthers.
|
||||
|
||||
AVAudioSessionCategoryOptionAllowBluetoothA2DP --
|
||||
This allows an application to change the default behaviour of some audio session categories with regards to showing
|
||||
bluetooth Advanced Audio Distribution Profile (A2DP), i.e. stereo Bluetooth, devices as available routes. The current
|
||||
category behavior is:
|
||||
(1) AVAudioSessionCategoryPlayAndRecord
|
||||
this will default to false, but can be set to true. This will allow a paired bluetooth A2DP device to show up as
|
||||
an available route for output, while recording through the category-appropriate input
|
||||
(2) AVAudioSessionCategoryMultiRoute and AVAudioSessionCategoryRecord
|
||||
this will default to false, and cannot be set to true.
|
||||
(3) Other categories
|
||||
this defaults to true and cannot be changed (that is, bluetooth A2DP ports are always supported in output-only categories).
|
||||
An application must be prepared for setting this option to fail as behaviour may change in future releases.
|
||||
If an application changes their category or mode, they should reassert the override (it is not sticky
|
||||
across category and mode changes).
|
||||
Setting both AVAudioSessionCategoryOptionAllowBluetooth and AVAudioSessionCategoryOptionAllowBluetoothA2DP is allowed. In cases
|
||||
where a single Bluetooth device supports both HFP and A2DP, the HFP ports will be given a higher priority for routing. For HFP
|
||||
and A2DP ports on separate hardware devices, the last-in wins rule applies.
|
||||
|
||||
AVAudioSessionCategoryOptionAllowAirPlay --
|
||||
This allows an application to change the default behaviour of some audio session categories with regards to showing
|
||||
AirPlay devices as available routes. See the documentation of AVAudioSessionCategoryOptionAllowBluetoothA2DP for details on
|
||||
how this option applies to specific categories.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// This allows an application to set whether or not other active audio apps will be interrupted or mixed with
|
||||
/// when your app's audio session goes active. The typical cases are:
|
||||
/// (1) AVAudioSessionCategoryPlayAndRecord or AVAudioSessionCategoryMultiRoute
|
||||
/// this will default to false, but can be set to true. This would allow other applications to play in the background
|
||||
/// while an app had both audio input and output enabled
|
||||
/// (2) AVAudioSessionCategoryPlayback
|
||||
/// this will default to false, but can be set to true. This would allow other applications to play in the background,
|
||||
/// but an app will still be able to play regardless of the setting of the ringer switch
|
||||
/// (3) Other categories
|
||||
/// this defaults to false and cannot be changed (that is, the mix with others setting of these categories
|
||||
/// cannot be overridden. An application must be prepared for setting this property to fail as behaviour
|
||||
/// may change in future releases. If an application changes their category, they should reassert the
|
||||
/// option (it is not sticky across category changes).
|
||||
/// MixWithOthers is only valid with AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute
|
||||
/// </summary>
|
||||
MixWithOthers = 0x1,
|
||||
/// <summary>
|
||||
/// This allows an application to set whether or not other active audio apps will be ducked when when your app's audio
|
||||
/// session goes active. An example of this is the Nike app, which provides periodic updates to its user (it reduces the
|
||||
/// volume of any music currently being played while it provides its status). This defaults to off. Note that the other
|
||||
/// audio will be ducked for as long as the current session is active. You will need to deactivate your audio
|
||||
/// session when you want full volume playback of the other audio.
|
||||
/// If your category is AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, or
|
||||
/// AVAudioSessionCategoryMultiRoute, by default the audio session will be non-mixable and non-ducking.
|
||||
/// Setting this option will also make your category mixable with others (AVAudioSessionCategoryOptionMixWithOthers
|
||||
/// will be set).
|
||||
/// DuckOthers is only valid with AVAudioSessionCategoryAmbient, AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute
|
||||
/// </summary>
|
||||
DuckOthers = 0x2,
|
||||
/// <summary>
|
||||
/// This allows an application to change the default behaviour of some audio session categories with regards to showing
|
||||
/// bluetooth Hands-Free Profile (HFP) devices as available routes. The current category behavior is:
|
||||
/// (1) AVAudioSessionCategoryPlayAndRecord
|
||||
/// this will default to false, but can be set to true. This will allow a paired bluetooth HFP device to show up as
|
||||
/// an available route for input, while playing through the category-appropriate output
|
||||
/// (2) AVAudioSessionCategoryRecord
|
||||
/// this will default to false, but can be set to true. This will allow a paired bluetooth HFP device to show up
|
||||
/// as an available route for input
|
||||
/// (3) Other categories
|
||||
/// this defaults to false and cannot be changed (that is, enabling bluetooth for input in these categories is
|
||||
/// not allowed)
|
||||
/// An application must be prepared for setting this option to fail as behaviour may change in future releases.
|
||||
/// If an application changes their category or mode, they should reassert the override (it is not sticky
|
||||
/// across category and mode changes).
|
||||
/// AllowBluetooth is only valid with AVAudioSessionCategoryRecord and AVAudioSessionCategoryPlayAndRecord
|
||||
/// </summary>
|
||||
AllowBluetooth = 0x4, // API_UNAVAILABLE(tvos, watchos, macos)
|
||||
/// <summary>
|
||||
/// This allows an application to change the default behaviour of some audio session categories with regards to
|
||||
/// the audio route. The current category behavior is:
|
||||
/// (1) AVAudioSessionCategoryPlayAndRecord category
|
||||
/// this will default to false, but can be set to true. this will route to Speaker (instead of Receiver)
|
||||
/// when no other audio route is connected.
|
||||
/// (2) Other categories
|
||||
/// this defaults to false and cannot be changed (that is, the default to speaker setting of these
|
||||
/// categories cannot be overridden
|
||||
/// An application must be prepared for setting this property to fail as behaviour may change in future releases.
|
||||
/// If an application changes their category, they should reassert the override (it is not sticky across
|
||||
/// category and mode changes).
|
||||
/// DefaultToSpeaker is only valid with AVAudioSessionCategoryPlayAndRecord
|
||||
/// </summary>
|
||||
DefaultToSpeaker = 0x8, // API_UNAVAILABLE(tvos, watchos, macos)
|
||||
/* InterruptSpokenAudioAndMixWithOthers is only valid with AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryPlayback, and AVAudioSessionCategoryMultiRoute */
|
||||
// InterruptSpokenAudioAndMixWithOthers = 0x11, // API_AVAILABLE(ios(9.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos)
|
||||
/* AllowBluetoothA2DP is only valid with AVAudioSessionCategoryPlayAndRecord */
|
||||
// AllowBluetoothA2DP = 0x20, // API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0)) API_UNAVAILABLE(macos)
|
||||
/* AllowAirPlay is only valid with AVAudioSessionCategoryPlayAndRecord */
|
||||
// AllowAirPlay = 0x40, // API_AVAILABLE(ios(10.0), tvos(10.0)) API_UNAVAILABLE(watchos, macos)
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct AudioSessionParameters
|
||||
{
|
||||
public AudioSessionCategory Category;//= AudioSessionCategory.PlayAndRecord;
|
||||
public AudioSessionMode Mode;// = AudioSessionMode.Default;
|
||||
public AudioSessionCategoryOption[] CategoryOptions;
|
||||
public int CategoryOptionsToInt()
|
||||
{
|
||||
int opt = 0;
|
||||
if (CategoryOptions != null)
|
||||
{
|
||||
for (int i = 0; i < CategoryOptions.Length; i++)
|
||||
{
|
||||
opt |= (int)CategoryOptions[i];
|
||||
}
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
var opt = "[";
|
||||
if (CategoryOptions != null)
|
||||
{
|
||||
for (int i = 0; i < CategoryOptions.Length; i++)
|
||||
{
|
||||
opt += CategoryOptions[i];
|
||||
if (i != CategoryOptions.Length - 1)
|
||||
{
|
||||
opt += ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
opt += "]";
|
||||
return string.Format("category = {0}, mode = {1}, options = {2}", Category, Mode, opt);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AudioSessionParametersPresets
|
||||
{
|
||||
public static AudioSessionParameters Game = new AudioSessionParameters()
|
||||
{
|
||||
Category = AudioSessionCategory.PlayAndRecord,
|
||||
Mode = AudioSessionMode.Default,
|
||||
CategoryOptions = new AudioSessionCategoryOption[] { AudioSessionCategoryOption.DefaultToSpeaker, AudioSessionCategoryOption.AllowBluetooth }
|
||||
};
|
||||
public static AudioSessionParameters VoIP = new AudioSessionParameters()
|
||||
{
|
||||
Category = AudioSessionCategory.PlayAndRecord,
|
||||
Mode = AudioSessionMode.VoiceChat,
|
||||
// VoiceChat should have the side effect of setting AVAudioSessionCategoryOptionAllowBluetooth according to doc
|
||||
// but tests don't confirm this
|
||||
CategoryOptions = new AudioSessionCategoryOption[] { AudioSessionCategoryOption.AllowBluetooth }
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76e6623773113024186d4ccda649c0a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user