non-vr lobby, version fix

This commit is contained in:
joonasp
2022-06-29 14:45:17 +03:00
parent 5774be9822
commit 04baadfad1
1774 changed files with 573069 additions and 1533 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: df603a30659a4c048b9c3fb7aa38b85d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum Bandwidth : int
{
/// <summary>
/// Up to 4Khz
/// </summary>
Narrowband = 1101,
/// <summary>
/// Up to 6Khz
/// </summary>
Mediumband = 1102,
/// <summary>
/// Up to 8Khz
/// </summary>
Wideband = 1103,
/// <summary>
/// Up to 12Khz
/// </summary>
SuperWideband = 1104,
/// <summary>
/// Up to 20Khz (High Definition)
/// </summary>
Fullband = 1105
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c527233af8a7c54fab631659436832c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum Channels : int
{
/// <summary>
/// 1 Channel
/// </summary>
Mono = 1,
/// <summary>
/// 2 Channels
/// </summary>
Stereo = 2
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4866c479545570d41abaff5f6a604676
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum Complexity : int
{
Complexity0 = 0,
Complexity1 = 1,
Complexity2 = 2,
Complexity3 = 3,
Complexity4 = 4,
Complexity5 = 5,
Complexity6 = 6,
Complexity7 = 7,
Complexity8 = 8,
Complexity9 = 9,
Complexity10 = 10
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5eb43bf1b9e449b438cbea885607ad3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
/// <summary>
/// Using a duration of less than 10 ms will prevent the encoder from using the LPC or hybrid modes.
/// </summary>
public enum Delay
{
/// <summary>
/// 2.5ms
/// </summary>
Delay2dot5ms = 5,
/// <summary>
/// 5ms
/// </summary>
Delay5ms = 10,
/// <summary>
/// 10ms
/// </summary>
Delay10ms = 20,
/// <summary>
/// 20ms
/// </summary>
Delay20ms = 40,
/// <summary>
/// 40ms
/// </summary>
Delay40ms = 80,
/// <summary>
/// 60ms
/// </summary>
Delay60ms = 120
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7fa617b20b39d3488d2d9fbc1abae43
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum ForceChannels : int
{
NoForce = -1000,
Mono = 1,
Stereo = 2
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41001579e394e2d4ea08c136c82de9f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum OpusApplicationType : int
{
/// <summary>
/// Gives best quality at a given bitrate for voice signals.
/// It enhances the input signal by high-pass filtering and emphasizing formants and harmonics.
/// Optionally it includes in-band forward error correction to protect against packet loss.
/// Use this mode for typical VoIP applications.
/// Because of the enhancement, even at high bitrates the output may sound different from the input.
/// </summary>
Voip = 2048,
/// <summary>
/// Gives best quality at a given bitrate for most non-voice signals like music.
/// Use this mode for music and mixed (music/voice) content, broadcast, and applications requiring less than 15 ms of coding delay.
/// </summary>
Audio = 2049,
/// <summary>
/// Configures low-delay mode that disables the speech-optimized mode in exchange for slightly reduced delay.
/// </summary>
RestrictedLowDelay = 2051
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0875bbb79a90bc1448ebc2142d1699bd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
internal enum OpusCtlGetRequest : int
{
Application = 4001,
Bitrate = 4003,
MaxBandwidth = 4005,
VBR = 4007,
Bandwidth = 4009,
Complexity = 4011,
InbandFec = 4013,
PacketLossPercentage = 4015,
Dtx = 4017,
VBRConstraint = 4021,
ForceChannels = 4023,
Signal = 4025,
LookAhead = 4027,
SampleRate = 4029,
FinalRange = 4031,
Pitch = 4033,
Gain = 4035,
LsbDepth = 4037,
LastPacketDurationRequest = 4039
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb806501c083df349acf30e98483b1b6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
internal enum OpusCtlSetRequest : int
{
Application = 4000,
Bitrate = 4002,
MaxBandwidth = 4004,
VBR = 4006,
Bandwidth = 4008,
Complexity = 4010,
InbandFec = 4012,
PacketLossPercentage = 4014,
Dtx = 4016,
VBRConstraint = 4020,
ForceChannels = 4022,
Signal = 4024,
Gain = 4034,
LsbDepth = 4036
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2685c657fd2eeb04caf2917098b69215
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum OpusStatusCode : int
{
OK = 0,
BadArguments = -1,
BufferTooSmall = -2,
InternalError = -3,
InvalidPacket = -4,
Unimplemented = -5,
InvalidState = -6,
AllocFail = -7
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: baf95840af423aa4d8afbbf5ccb17f1f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum SamplingRate : int
{
Sampling08000 = 8000,
Sampling12000 = 12000,
Sampling16000 = 16000,
Sampling24000 = 24000,
Sampling48000 = 48000
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ecca42cdd5ba70a44b9eada7e82d172a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace POpusCodec.Enums
{
public enum SignalHint : int
{
/// <summary>
/// (default)
/// </summary>
Auto = -1000,
/// <summary>
/// Bias thresholds towards choosing LPC or Hybrid modes
/// </summary>
Voice = 3001,
/// <summary>
/// Bias thresholds towards choosing MDCT modes.
/// </summary>
Music = 3002
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 740a25c5418bd1b449fc254e53be34b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,220 @@
using System;
using POpusCodec.Enums;
using System.Runtime.InteropServices;
using Photon.Voice;
namespace POpusCodec
{
public class OpusDecoder<T> : IDisposable
{
private const bool UseInbandFEC = true;
private bool TisFloat;
private int sizeofT;
private IntPtr _handle = IntPtr.Zero;
private const int MaxFrameSize = 5760;
private int _channelCount;
private static readonly T[] EmptyBuffer = new T[] { };
private Bandwidth? _previousPacketBandwidth = null;
public Bandwidth? PreviousPacketBandwidth
{
get
{
return _previousPacketBandwidth;
}
}
public OpusDecoder(SamplingRate outputSamplingRateHz, Channels numChannels)
{
TisFloat = default(T) is float;
sizeofT = Marshal.SizeOf(default(T));
if ((outputSamplingRateHz != SamplingRate.Sampling08000)
&& (outputSamplingRateHz != SamplingRate.Sampling12000)
&& (outputSamplingRateHz != SamplingRate.Sampling16000)
&& (outputSamplingRateHz != SamplingRate.Sampling24000)
&& (outputSamplingRateHz != SamplingRate.Sampling48000))
{
throw new ArgumentOutOfRangeException("outputSamplingRateHz", "Must use one of the pre-defined sampling rates (" + outputSamplingRateHz + ")");
}
if ((numChannels != Channels.Mono)
&& (numChannels != Channels.Stereo))
{
throw new ArgumentOutOfRangeException("numChannels", "Must be Mono or Stereo");
}
_channelCount = (int)numChannels;
_handle = Wrapper.opus_decoder_create(outputSamplingRateHz, numChannels);
if (_handle == IntPtr.Zero)
{
throw new OpusException(OpusStatusCode.AllocFail, "Memory was not allocated for the encoder");
}
}
private T[] buffer; // allocated for exactly 1 frame size as first valid frame received
private FrameBuffer prevPacketData;
bool prevPacketInvalid; // maybe false if prevPacket us null
// pass null to indicate packet loss
public T[] DecodePacket(ref FrameBuffer packetData)
{
if (this.buffer == null && packetData.Array == null)
{
return EmptyBuffer;
}
int numSamplesDecoded = 0;
if (this.buffer == null)
{
// on the first call we don't know frame size, use temporal buffer of maximal length
this.buffer = new T[MaxFrameSize * _channelCount];
}
bool packetInvalid;
if (packetData.Array == null)
{
packetInvalid = true;
}
else
{
int bandwidth = Wrapper.opus_packet_get_bandwidth(packetData.Ptr);
packetInvalid = bandwidth == (int)OpusStatusCode.InvalidPacket;
}
bool regularDecode = false;
if (UseInbandFEC)
{
if (prevPacketInvalid)
{
if (packetInvalid)
{
// no fec data, conceal previous frame
numSamplesDecoded = TisFloat ?
Wrapper.opus_decode(_handle, new FrameBuffer(), this.buffer as float[], 0, _channelCount) :
Wrapper.opus_decode(_handle, new FrameBuffer(), this.buffer as short[], 0, _channelCount);
//UnityEngine.Debug.Log("======================= Conceal");
}
else
{
// error correct previous frame with the help of the current
numSamplesDecoded = TisFloat ?
Wrapper.opus_decode(_handle, packetData, this.buffer as float[], 1, _channelCount) :
Wrapper.opus_decode(_handle, packetData, this.buffer as short[], 1, _channelCount);
//UnityEngine.Debug.Log("======================= FEC");
}
}
else
{
// decode previous frame
if (prevPacketData.Array != null) // is null on 1st call
{
numSamplesDecoded = TisFloat ?
Wrapper.opus_decode(_handle, prevPacketData, this.buffer as float[], 0, _channelCount) :
Wrapper.opus_decode(_handle, prevPacketData, this.buffer as short[], 0, _channelCount);
// prevPacketData is disposed below before copying packetData to it
regularDecode = true;
}
}
prevPacketData.Release();
prevPacketData = packetData;
packetData.Retain();
prevPacketInvalid = packetInvalid;
}
else
{
#pragma warning disable 162
// decode or conceal current frame
numSamplesDecoded = TisFloat ?
Wrapper.opus_decode(_handle, packetData, this.buffer as float[], 0, _channelCount) :
Wrapper.opus_decode(_handle, packetData, this.buffer as short[], 0, _channelCount);
regularDecode = true;
#pragma warning restore 162
}
if (numSamplesDecoded == 0)
return EmptyBuffer;
if (this.buffer.Length != numSamplesDecoded * _channelCount)
{
if (!regularDecode)
{
// wait for regular valid frame to imitialize the size
return EmptyBuffer;
}
// now that we know the frame size, allocate the buffer and copy data from temporal buffer
var tmp = this.buffer;
this.buffer = new T[numSamplesDecoded * _channelCount];
Buffer.BlockCopy(tmp, 0, this.buffer, 0, numSamplesDecoded * sizeofT);
}
return this.buffer;
}
public T[] DecodeEndOfStream()
{
int numSamplesDecoded = 0;
if (UseInbandFEC && !prevPacketInvalid)
{
// follow the same buffer initializatiopn pattern as in DecodeFrame() though buffer is already initialized most likely
if (this.buffer == null)
{
// on the first call we don't know frame size, use temporal buffer of maximal length
this.buffer = new T[MaxFrameSize * _channelCount];
}
// decode previous frame
if (prevPacketData.Array != null) // is null on 1st call
{
numSamplesDecoded = TisFloat ?
Wrapper.opus_decode(_handle, prevPacketData, this.buffer as float[], 1, _channelCount) :
Wrapper.opus_decode(_handle, prevPacketData, this.buffer as short[], 1, _channelCount);
}
prevPacketData.Release();
prevPacketData = new FrameBuffer();
prevPacketInvalid = false;
if (numSamplesDecoded == 0)
{
return EmptyBuffer;
}
else
{
// follow the same buffer initializatiopn pattern as in DecodeFrame()
if (this.buffer.Length != numSamplesDecoded * _channelCount)
{
// now that we know the frame size, allocate the buffer and copy data from temporal buffer
var tmp = this.buffer;
this.buffer = new T[numSamplesDecoded * _channelCount];
Buffer.BlockCopy(tmp, 0, this.buffer, 0, numSamplesDecoded * sizeofT);
}
return this.buffer;
}
}
else
{
prevPacketData.Release();
prevPacketData = new FrameBuffer();
prevPacketInvalid = false;
return EmptyBuffer;
}
}
public void Dispose()
{
prevPacketData.Release();
if (_handle != IntPtr.Zero)
{
Wrapper.opus_decoder_destroy(_handle);
_handle = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 111ab6962d87d294394acc522d2570a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,283 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using POpusCodec.Enums;
using System.Runtime.InteropServices;
namespace POpusCodec
{
static public class OpusLib
{
static public string Version
{
get
{
return Marshal.PtrToStringAnsi(Wrapper.opus_get_version_string());
}
}
}
public class OpusEncoder : IDisposable
{
public const int BitrateMax = -1;
private IntPtr _handle = IntPtr.Zero;
private const int RecommendedMaxPacketSize = 4000;
private int _frameSizePerChannel = 960;
private SamplingRate _inputSamplingRate = SamplingRate.Sampling48000;
private Channels _inputChannels = Channels.Stereo;
public SamplingRate InputSamplingRate
{
get
{
return _inputSamplingRate;
}
}
public Channels InputChannels
{
get
{
return _inputChannels;
}
}
private readonly byte[] writePacket = new byte[RecommendedMaxPacketSize];
private static readonly ArraySegment<byte> EmptyBuffer = new ArraySegment<byte>(new byte[] { });
private Delay _encoderDelay = Delay.Delay20ms;
/// <summary>
/// Using a duration of less than 10 ms will prevent the encoder from using the LPC or hybrid modes.
/// </summary>
public Delay EncoderDelay
{
set
{
_encoderDelay = value;
_frameSizePerChannel = (int)((((int)_inputSamplingRate) / 1000) * ((decimal)_encoderDelay) / 2);
}
get
{
return _encoderDelay;
}
}
public int FrameSizePerChannel
{
get
{
return _frameSizePerChannel;
}
}
public int Bitrate
{
get
{
return Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.Bitrate);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.Bitrate, value);
}
}
public Bandwidth MaxBandwidth
{
get
{
return (Bandwidth)Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.MaxBandwidth);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.MaxBandwidth, (int)value);
}
}
public Complexity Complexity
{
get
{
return (Complexity)Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.Complexity);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.Complexity, (int)value);
}
}
public int ExpectedPacketLossPercentage
{
get
{
return Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.PacketLossPercentage);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.PacketLossPercentage, value);
}
}
public SignalHint SignalHint
{
get
{
return (SignalHint)Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.Signal);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.Signal, (int)value);
}
}
public ForceChannels ForceChannels
{
get
{
return (ForceChannels)Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.ForceChannels);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.ForceChannels, (int)value);
}
}
public bool UseInbandFEC
{
get
{
return Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.InbandFec) == 1;
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.InbandFec, value ? 1 : 0);
}
}
public int PacketLossPercentage
{
get
{
return Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.PacketLossPercentage);
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.PacketLossPercentage, value);
}
}
public bool UseUnconstrainedVBR
{
get
{
return Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.VBRConstraint) == 0;
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.VBRConstraint, value ? 0 : 1);
}
}
public bool DtxEnabled
{
get
{
return Wrapper.get_opus_encoder_ctl(_handle, OpusCtlGetRequest.Dtx) == 1;
}
set
{
Wrapper.set_opus_encoder_ctl(_handle, OpusCtlSetRequest.Dtx, value ? 1 : 0);
}
}
//public OpusEncoder(SamplingRate inputSamplingRateHz, Channels numChannels)
// : this(inputSamplingRateHz, numChannels, 120000, OpusApplicationType.Audio, Delay.Delay20ms)
//{ }
//public OpusEncoder(SamplingRate inputSamplingRateHz, Channels numChannels, int bitrate)
// : this(inputSamplingRateHz, numChannels, bitrate, OpusApplicationType.Audio, Delay.Delay20ms)
//{ }
//public OpusEncoder(SamplingRate inputSamplingRateHz, Channels numChannels, int bitrate, OpusApplicationType applicationType)
// : this(inputSamplingRateHz, numChannels, bitrate, applicationType, Delay.Delay20ms)
//{ }
public OpusEncoder(SamplingRate inputSamplingRateHz, Channels numChannels, int bitrate, OpusApplicationType applicationType, Delay encoderDelay)
{
if ((inputSamplingRateHz != SamplingRate.Sampling08000)
&& (inputSamplingRateHz != SamplingRate.Sampling12000)
&& (inputSamplingRateHz != SamplingRate.Sampling16000)
&& (inputSamplingRateHz != SamplingRate.Sampling24000)
&& (inputSamplingRateHz != SamplingRate.Sampling48000))
{
throw new ArgumentOutOfRangeException("inputSamplingRateHz", "Must use one of the pre-defined sampling rates(" + inputSamplingRateHz + ")");
}
if ((numChannels != Channels.Mono)
&& (numChannels != Channels.Stereo))
{
throw new ArgumentOutOfRangeException("numChannels", "Must be Mono or Stereo");
}
if ((applicationType != OpusApplicationType.Audio)
&& (applicationType != OpusApplicationType.RestrictedLowDelay)
&& (applicationType != OpusApplicationType.Voip))
{
throw new ArgumentOutOfRangeException("applicationType", "Must use one of the pre-defined application types (" + applicationType + ")");
}
if ((encoderDelay != Delay.Delay10ms)
&& (encoderDelay != Delay.Delay20ms)
&& (encoderDelay != Delay.Delay2dot5ms)
&& (encoderDelay != Delay.Delay40ms)
&& (encoderDelay != Delay.Delay5ms)
&& (encoderDelay != Delay.Delay60ms))
{
throw new ArgumentOutOfRangeException("encoderDelay", "Must use one of the pre-defined delay values (" + encoderDelay + ")"); ;
}
_inputSamplingRate = inputSamplingRateHz;
_inputChannels = numChannels;
_handle = Wrapper.opus_encoder_create(inputSamplingRateHz, numChannels, applicationType);
if (_handle == IntPtr.Zero)
{
throw new OpusException(OpusStatusCode.AllocFail, "Memory was not allocated for the encoder");
}
EncoderDelay = encoderDelay;
Bitrate = bitrate;
UseInbandFEC = true;
PacketLossPercentage = 30;
}
public ArraySegment<byte> Encode(float[] pcmSamples)
{
int size = Wrapper.opus_encode(_handle, pcmSamples, _frameSizePerChannel, writePacket);
if (size <= 1) //DTX. Negative already handled at this point
return EmptyBuffer;
else
return new ArraySegment<byte>(writePacket, 0, size);
}
public ArraySegment<byte> Encode(short[] pcmSamples)
{
int size = Wrapper.opus_encode(_handle, pcmSamples, _frameSizePerChannel, writePacket);
if (size <= 1) //DTX. Negative already handled at this point
return EmptyBuffer;
else
return new ArraySegment<byte>(writePacket, 0, size);
}
public void Dispose()
{
if (_handle != IntPtr.Zero)
{
Wrapper.opus_encoder_destroy(_handle);
_handle = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 487631ffee9000c42b81291343b86446
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using POpusCodec.Enums;
namespace POpusCodec
{
public class OpusException : Exception
{
private OpusStatusCode _statusCode = OpusStatusCode.OK;
public OpusStatusCode StatusCode
{
get
{
return _statusCode;
}
}
public OpusException(OpusStatusCode statusCode, string message)
: base(message + " (" + statusCode + ")")
{
_statusCode = statusCode;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6a76e6ebcab0b9344837c3cbd4124687
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,298 @@
#if ((UNITY_IOS || UNITY_SWITCH) && !UNITY_EDITOR) || __IOS__
#define DLL_IMPORT_INTERNAL
#endif
#if NONE //UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN || UNITY_WSA
// opus.* lib built from original opus repo
#else
#define OPUS_EGPV // opus_egpv.* lib with interop helpers (we still may use such libs for the platforms where helpers are not required)
#endif
// Interop helpers required for iOS ARM64 IL2CPP (and maybe in other cases) because of variadic functions PInvoke calling issue:
// https://stackoverflow.com/questions/35536515/variable-argument-function-bad-access-with-va-arg-at-ios-arm64
// use statically linked interop helpers defined outside of opus.lib
#if (UNITY_IOS && !UNITY_EDITOR) || __IOS__
#define OPUS_EGPV_INTEROP_HELPER_EXTERNAL
#endif
// Interop helpers required also for Apple Silicon (ARM64)
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
// use interop helpers built into opus_egpv.* lib (works for any platform but requires opus lib compiled from customized sources)
#define OPUS_EGPV_INTEROP_HELPER_BUILTIN
#define OPUS_EGPV
#endif
#if UNITY_WEBGL && !UNITY_EDITOR
#define DLL_IMPORT_INTERNAL
#define OPUS_EGPV_INTEROP_HELPER_BUILTIN
#endif
using System;
using System.Runtime.InteropServices;
using POpusCodec.Enums;
using Photon.Voice;
namespace POpusCodec
{
internal class Wrapper
{
#if DLL_IMPORT_INTERNAL
const string lib_name = "__Internal";
#else
#if OPUS_EGPV
const string lib_name = "opus_egpv";
#else
const string lib_name = "opus";
#endif
#endif
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int opus_encoder_get_size(Channels channels);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern OpusStatusCode opus_encoder_init(IntPtr st, SamplingRate Fs, Channels channels, OpusApplicationType application);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern IntPtr opus_get_version_string();
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int opus_encode(IntPtr st, short[] pcm, int frame_size, byte[] data, int max_data_bytes);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int opus_encode_float(IntPtr st, float[] pcm, int frame_size, byte[] data, int max_data_bytes);
#if OPUS_EGPV_INTEROP_HELPER_BUILTIN
const string ctl_entry_point_set = "_set";
const string ctl_entry_point_get = "_get";
#elif OPUS_EGPV_INTEROP_HELPER_EXTERNAL
const string ctl_entry_point_set = "_set_ext";
const string ctl_entry_point_get = "_get_ext";
#else
const string ctl_entry_point_set = "";
const string ctl_entry_point_get = "";
#endif
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "opus_encoder_ctl" + ctl_entry_point_set)]
private static extern int opus_encoder_ctl_set(IntPtr st, OpusCtlSetRequest request, int value);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "opus_encoder_ctl" + ctl_entry_point_get)]
private static extern int opus_encoder_ctl_get(IntPtr st, OpusCtlGetRequest request, ref int value);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "opus_decoder_ctl" + ctl_entry_point_set)]
private static extern int opus_decoder_ctl_set(IntPtr st, OpusCtlSetRequest request, int value);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, EntryPoint = "opus_decoder_ctl" + ctl_entry_point_get)]
private static extern int opus_decoder_ctl_get(IntPtr st, OpusCtlGetRequest request, ref int value);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int opus_decoder_get_size(Channels channels);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern OpusStatusCode opus_decoder_init(IntPtr st, SamplingRate Fs, Channels channels);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int opus_decode(IntPtr st, IntPtr data, int len, short[] pcm, int frame_size, int decode_fec);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int opus_decode_float(IntPtr st, IntPtr data, int len, float[] pcm, int frame_size, int decode_fec);
// [DllImport(import_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
// private static extern int opus_decode(IntPtr st, IntPtr data, int len, short[] pcm, int frame_size, int decode_fec);
// [DllImport(import_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
// private static extern int opus_decode_float(IntPtr st, IntPtr data, int len, float[] pcm, int frame_size, int decode_fec);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int opus_packet_get_bandwidth(IntPtr data);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int opus_packet_get_nb_channels(byte[] data);
[DllImport(lib_name, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern IntPtr opus_strerror(OpusStatusCode error);
public static IntPtr opus_encoder_create(SamplingRate Fs, Channels channels, OpusApplicationType application)
{
int size = Wrapper.opus_encoder_get_size(channels);
IntPtr ptr = Marshal.AllocHGlobal(size);
OpusStatusCode statusCode = Wrapper.opus_encoder_init(ptr, Fs, channels, application);
try
{
HandleStatusCode(statusCode, "opus_encoder_create/opus_encoder_init", Fs, channels, application);
}
catch (Exception ex)
{
if (ptr != IntPtr.Zero)
{
Wrapper.opus_encoder_destroy(ptr);
ptr = IntPtr.Zero;
}
throw ex;
}
return ptr;
}
public static int opus_encode(IntPtr st, short[] pcm, int frame_size, byte[] data)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusEncoder");
int payloadLength = opus_encode(st, pcm, frame_size, data, data.Length);
if (payloadLength <= 0)
{
HandleStatusCode((OpusStatusCode)payloadLength, "opus_encode/short", frame_size, data.Length);
}
return payloadLength;
}
public static int opus_encode(IntPtr st, float[] pcm, int frame_size, byte[] data)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusEncoder");
int payloadLength = opus_encode_float(st, pcm, frame_size, data, data.Length);
if (payloadLength <= 0)
{
HandleStatusCode((OpusStatusCode)payloadLength, "opus_encode/float", frame_size, data.Length);
}
return payloadLength;
}
public static void opus_encoder_destroy(IntPtr st)
{
Marshal.FreeHGlobal(st);
}
public static int get_opus_encoder_ctl(IntPtr st, OpusCtlGetRequest request)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusEncoder");
int value = 0;
OpusStatusCode statusCode = (OpusStatusCode)opus_encoder_ctl_get(st, request, ref value);
HandleStatusCode(statusCode, "opus_encoder_ctl_get", request);
return value;
}
public static void set_opus_encoder_ctl(IntPtr st, OpusCtlSetRequest request, int value)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusEncoder");
OpusStatusCode statusCode = (OpusStatusCode)opus_encoder_ctl_set(st, request, value);
HandleStatusCode(statusCode, "opus_encoder_ctl_set", request, value);
}
public static int get_opus_decoder_ctl(IntPtr st, OpusCtlGetRequest request)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusDcoder");
int value = 0;
OpusStatusCode statusCode = (OpusStatusCode)opus_decoder_ctl_get(st, request, ref value);
HandleStatusCode(statusCode, "get_opus_decoder_ctl", request, value);
return value;
}
public static void set_opus_decoder_ctl(IntPtr st, OpusCtlSetRequest request, int value)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusDecoder");
OpusStatusCode statusCode = (OpusStatusCode)opus_decoder_ctl_set(st, request, value);
HandleStatusCode(statusCode, "set_opus_decoder_ctl", request, value);
}
public static IntPtr opus_decoder_create(SamplingRate Fs, Channels channels)
{
int size = Wrapper.opus_decoder_get_size(channels);
IntPtr ptr = Marshal.AllocHGlobal(size);
OpusStatusCode statusCode = Wrapper.opus_decoder_init(ptr, Fs, channels);
try
{
HandleStatusCode(statusCode, "opus_decoder_create", Fs, channels);
}
catch (Exception ex)
{
if (ptr != IntPtr.Zero)
{
Wrapper.opus_decoder_destroy(ptr);
ptr = IntPtr.Zero;
}
throw ex;
}
return ptr;
}
public static void opus_decoder_destroy(IntPtr st)
{
Marshal.FreeHGlobal(st);
}
public static int opus_decode(IntPtr st, FrameBuffer data, short[] pcm, int decode_fec, int channels)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusDecoder");
int numSamplesDecoded = opus_decode(st, data.Ptr, data.Length, pcm, pcm.Length / channels, decode_fec);
if (numSamplesDecoded == (int)OpusStatusCode.InvalidPacket)
return 0;
if (numSamplesDecoded <= 0)
{
HandleStatusCode((OpusStatusCode)numSamplesDecoded, "opus_decode/short", data.Length, pcm.Length, decode_fec, channels);
}
return numSamplesDecoded;
}
public static int opus_decode(IntPtr st, FrameBuffer data, float[] pcm, int decode_fec, int channels)
{
if (st == IntPtr.Zero)
throw new ObjectDisposedException("OpusDecoder");
int numSamplesDecoded = opus_decode_float(st, data.Ptr, data.Length, pcm, pcm.Length / channels, decode_fec);
if (numSamplesDecoded == (int)OpusStatusCode.InvalidPacket)
return 0;
if (numSamplesDecoded <= 0)
{
HandleStatusCode((OpusStatusCode)numSamplesDecoded, "opus_decode/float", data.Length, pcm.Length, decode_fec, channels);
}
return numSamplesDecoded;
}
private static void HandleStatusCode(OpusStatusCode statusCode, params object[] info)
{
if (statusCode != OpusStatusCode.OK)
{
var infoMsg = "";
foreach (var i in info) infoMsg += i.ToString() + ":";
throw new OpusException(statusCode, infoMsg + Marshal.PtrToStringAnsi(opus_strerror(statusCode)));
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f928aa994e3035c4089dd9f8e839a0a1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: