non-vr lobby, version fix
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df603a30659a4c048b9c3fb7aa38b85d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c527233af8a7c54fab631659436832c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4866c479545570d41abaff5f6a604676
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5eb43bf1b9e449b438cbea885607ad3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7fa617b20b39d3488d2d9fbc1abae43
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41001579e394e2d4ea08c136c82de9f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0875bbb79a90bc1448ebc2142d1699bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb806501c083df349acf30e98483b1b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2685c657fd2eeb04caf2917098b69215
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baf95840af423aa4d8afbbf5ccb17f1f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecca42cdd5ba70a44b9eada7e82d172a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 740a25c5418bd1b449fc254e53be34b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 111ab6962d87d294394acc522d2570a3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 487631ffee9000c42b81291343b86446
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a76e6ebcab0b9344837c3cbd4124687
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f928aa994e3035c4089dd9f8e839a0a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user