示例#1
0
            public void Reset()
            {
                //Reset takes no args, returns no values, and cannot fail. So we're passing in nothing, outputting nothing, and ignoring the return code
                int _;

                OpusNativeMethods.opus_decoder_ctl(_decoder, Ctl.ResetState, out _);
            }
示例#2
0
            /// <summary>
            /// Creates a new Opus encoder.
            /// </summary>
            /// <param name="srcSamplingRate">The sampling rate of the input stream.</param>
            /// <param name="srcChannelCount">The number of channels in the input stream.</param>
            public OpusEncoder(int srcSamplingRate, int srcChannelCount)
            {
                if (srcSamplingRate != 8000 && srcSamplingRate != 12000 && srcSamplingRate != 16000 && srcSamplingRate != 24000 && srcSamplingRate != 48000)
                {
                    throw new ArgumentOutOfRangeException("srcSamplingRate", Log.PossibleBugMessage("sample rate must be one of the valid values", "3F2C6D2D-338E-495E-8970-42A3C98243A5"));
                }
                if (srcChannelCount != 1 && srcChannelCount != 2)
                {
                    throw new ArgumentOutOfRangeException("srcChannelCount", Log.PossibleBugMessage("channel count must be 1 or 2", "8FE1EC0F-09E0-4CE6-AFD7-04199202D45D"));
                }

                int error;
                var encoder = OpusNativeMethods.opus_encoder_create(srcSamplingRate, srcChannelCount, (int)Application.Voip, out error);

                if ((OpusErrors)error != OpusErrors.Ok)
                {
                    throw new OpusException(Log.PossibleBugMessage(string.Format("Exception occured while creating encoder: {0}", (OpusErrors)error), "D77ECA73-413F-40D1-8427-CFD8A59CD5F6"));
                }
                _encoder = new LockedValue <IntPtr>(encoder);

                PermittedFrameSizes = new int[PermittedFrameSizesMs.Length];
                for (var i = 0; i < PermittedFrameSizesMs.Length; i++)
                {
                    PermittedFrameSizes[i] = (int)(srcSamplingRate / 1000f * PermittedFrameSizesMs[i]);
                }
            }
示例#3
0
            /// <summary>
            /// Encode audio samples.
            /// </summary>
            /// <returns>The total number of bytes written to dstOutputBuffer.</returns>
            public int EncodeFloats(ArraySegment <float> sourcePcm, ArraySegment <byte> dstEncoded)
            {
                if (sourcePcm.Array == null)
                {
                    throw new ArgumentNullException("sourcePcm", Log.PossibleBugMessage("source pcm must not be null", "58AE3110-8F9A-4C36-9520-B7F3383096EC"));
                }

                if (dstEncoded.Array == null)
                {
                    throw new ArgumentNullException("dstEncoded", Log.PossibleBugMessage("destination must not be null", "36C327BB-A128-400D-AFB3-FF760A1562C1"));
                }

                int encodedLen;

                using (var encoder = _encoder.Lock())
                {
                    if (encoder.Value == IntPtr.Zero)
                    {
                        throw new DissonanceException(Log.PossibleBugMessage("Attempted to access a null Opus encoder", "647001C3-39BB-418D-99EF-1D66B8EA633C"));
                    }

                    using (var srcHandle = sourcePcm.Pin())
                        using (var dstHandle = dstEncoded.Pin())
                        {
                            encodedLen = OpusNativeMethods.opus_encode_float(encoder.Value, srcHandle.Ptr, sourcePcm.Count, dstHandle.Ptr, dstEncoded.Count);
                        }
                }

                if (encodedLen < 0)
                {
                    throw new OpusException(Log.PossibleBugMessage(string.Format("Encoding failed: {0}", (OpusErrors)encodedLen), "9C923F57-146B-47CB-8EEE-5BF129FA3124"));
                }

                return(encodedLen);
            }
示例#4
0
            /// <summary>
            /// Encode audio samples.
            /// </summary>
            /// <returns>The total number of bytes written to dstOutputBuffer.</returns>
            public int EncodeFloats(ArraySegment <float> sourcePcm, ArraySegment <byte> dstEncoded)
            {
                if (sourcePcm.Array == null)
                {
                    throw new ArgumentNullException("sourcePcm", Log.PossibleBugMessage("source pcm must not be null", "58AE3110-8F9A-4C36-9520-B7F3383096EC"));
                }
                if (dstEncoded.Array == null)
                {
                    throw new ArgumentNullException("dstEncoded", Log.PossibleBugMessage("destination must not be null", "36C327BB-A128-400D-AFB3-FF760A1562C1"));
                }
                if (Array.IndexOf(PermittedFrameSizes, sourcePcm.Count) == -1)
                {
                    throw new ArgumentException(Log.PossibleBugMessage(string.Format("Incorrect frame size '{0}'", sourcePcm.Count), "6AFD9ADF-1D15-4197-99E9-5A19ECB8CD20"), "sourcePcm");
                }

                int encodedLen;

                using (var srcHandle = sourcePcm.Pin())
                    using (var dstHandle = dstEncoded.Pin())
                    {
                        encodedLen = OpusNativeMethods.opus_encode_float(_encoder, srcHandle.Ptr, sourcePcm.Count, dstHandle.Ptr, dstEncoded.Count);
                    }

                if (encodedLen < 0)
                {
                    throw new OpusException(Log.PossibleBugMessage(string.Format("Encoding failed: {0}", (OpusErrors)encodedLen), "9C923F57-146B-47CB-8EEE-5BF129FA3124"));
                }
                return(encodedLen);
            }
示例#5
0
 public void Reset()
 {
     using (var decoder = _decoder.Lock())
     {
         //Reset takes no args, returns no values, and cannot fail. So we're passing in nothing, outputting nothing, and ignoring the return code
         OpusNativeMethods.dissonance_opus_decoder_ctl_in(decoder.Value, Ctl.ResetState, 0);
     }
 }
示例#6
0
            public void Clip(ArraySegment <float> samples)
            {
#if !NCRUNCH
                using (var handle = samples.Pin())
                {
                    OpusNativeMethods.opus_pcm_soft_clip(
                        handle.Ptr,
                        samples.Count / _memory.Length,
                        _memory.Length,
                        _memory
                        );
                }
#endif
            }
示例#7
0
            public void Reset()
            {
                using (var encoder = _encoder.Lock())
                {
                    if (encoder.Value == IntPtr.Zero)
                    {
                        throw Log.CreatePossibleBugException("Attempted to access a null Opus encoder", "A86D13A5-FC58-446C-9522-DDD9D199DFA6");
                    }

                    //Wtf is going on here?
                    //Reset takes no args, returns no values, and cannot fail. So we're passing in nothing, outputting nothing, and ignoring the return code
                    OpusNativeMethods.dissonance_opus_encoder_ctl_in(encoder.Value, Ctl.ResetState, 0);
                }
            }
示例#8
0
            /// <summary>
            /// Decodes audio samples.
            /// </summary>
            /// <param name="srcEncodedBuffer">Encoded data (or null, to reconstruct a missing frame)</param>
            /// <param name="dstBuffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values starting at offset replaced with audio samples.</param>
            /// <returns>The number of floats decoded and written to dstBuffer.</returns>
            /// <remarks>Set srcEncodedBuffer to null to instruct the decoder that a packet was dropped.</remarks>
            public int DecodeFloats(ArraySegment <byte>?srcEncodedBuffer, ArraySegment <float> dstBuffer)
            {
                int length;

                using (var dstHandle = dstBuffer.Pin())
                {
                    if (srcEncodedBuffer.HasValue)
                    {
                        using (var srcHandle = srcEncodedBuffer.Value.Pin())
                        {
                            length = OpusNativeMethods.opus_decode_float(
                                _decoder,
                                srcHandle.Ptr, srcEncodedBuffer.Value.Count,
                                dstHandle.Ptr, dstBuffer.Count,
                                false
                                );
                        }
                    }
                    else
                    {
                        //Call decoder with null pointer and zero length to inform it of packet loss
                        length = OpusNativeMethods.opus_decode_float(
                            _decoder,
                            IntPtr.Zero, 0,
                            dstHandle.Ptr, dstBuffer.Count,
                            EnableForwardErrorCorrection
                            );
                    }
                }

                if (length < 0)
                {
                    if (length == (int)OpusErrors.InvalidPacket)
                    {
                        if (!srcEncodedBuffer.HasValue)
                        {
                            throw new OpusException(Log.PossibleBugMessage("Decoding failed: InvalidPacket. 'null' ", "03BE7561-3BCC-4F41-A7CB-C80F03981267"));
                        }
                        else
                        {
                            throw new OpusException(Log.PossibleBugMessage(string.Format("Decoding failed: InvalidPacket. '{0}'", Convert.ToBase64String(srcEncodedBuffer.Value.Array, srcEncodedBuffer.Value.Offset, srcEncodedBuffer.Value.Count)), "EF4BC24C-491E-45D9-974C-FE5CB61BD54E"));
                        }
                    }
                    else
                    {
                        throw new OpusException(Log.PossibleBugMessage(string.Format("Decoding failed: {0} ", (OpusErrors)length), "A9C8EF2C-7830-4D8E-9D6E-EF0B9827E0A8"));
                    }
                }
                return(length);
            }
示例#9
0
            public void Dispose()
            {
                if (_disposed)
                {
                    return;
                }

                GC.SuppressFinalize(this);

                if (_decoder != IntPtr.Zero)
                {
                    OpusNativeMethods.opus_decoder_destroy(_decoder);
                    _decoder = IntPtr.Zero;
                }

                _disposed = true;
            }
示例#10
0
            public OpusDecoder(int outputSampleRate, int outputChannelCount)
            {
                if (outputSampleRate != 8000 && outputSampleRate != 12000 && outputSampleRate != 16000 && outputSampleRate != 24000 && outputSampleRate != 48000)
                {
                    throw new ArgumentOutOfRangeException("outputSampleRate", Log.PossibleBugMessage("sample rate must be one of the valid values", "548757DF-DC64-40C9-BEAD-9826B8245A7D"));
                }
                if (outputChannelCount != 1 && outputChannelCount != 2)
                {
                    throw new ArgumentOutOfRangeException("outputChannelCount", Log.PossibleBugMessage("channel count must be 1 or 2", "BA56610F-1FA3-4D68-9507-7B0DFA0E28AB"));
                }

                int error;

                _decoder = new LockedValue <IntPtr>(OpusNativeMethods.opus_decoder_create(outputSampleRate, outputChannelCount, out error));
                if ((OpusErrors)error != OpusErrors.Ok)
                {
                    throw new OpusException(Log.PossibleBugMessage(string.Format("Exception occured while creating decoder: {0}", (OpusErrors)error), "6E09F275-99A1-4CD6-A36A-FA093B146B29"));
                }
            }
示例#11
0
            public OpusSoftClip(int channels = 1)
            {
                if (channels <= 0)
                {
                    throw new ArgumentOutOfRangeException("channels", "Channels must be > 0");
                }

                //Try to access opus, if it fails to load the DLL then disable the soft clipper
                try
                {
                    OpusNativeMethods.opus_pcm_soft_clip(IntPtr.Zero, 0, 0, null);
                }
                catch (DllNotFoundException)
                {
                    _disabled = true;
                }

                _memory = new float[channels];
            }
示例#12
0
            public void Dispose()
            {
                if (_disposed)
                {
                    return;
                }

                GC.SuppressFinalize(this);

                using (var decoder = _decoder.Lock())
                {
                    if (decoder.Value != IntPtr.Zero)
                    {
                        OpusNativeMethods.opus_decoder_destroy(decoder.Value);
                        decoder.Value = IntPtr.Zero;
                    }
                }

                _disposed = true;
            }
示例#13
0
            private int OpusCtlOut(Ctl ctl, out int value)
            {
                int ret;

                using (var encoder = _encoder.Lock())
                {
                    if (encoder.Value == IntPtr.Zero)
                    {
                        throw new ObjectDisposedException("OpusEncoder", Log.PossibleBugMessage("trying to use decoder after is has been disposed", "10A3BFFB-EC3B-4664-B06C-D5D42F75FE42"));
                    }

                    ret = OpusNativeMethods.dissonance_opus_encoder_ctl_out(encoder.Value, ctl, out value);
                }

                if (ret < 0)
                {
                    throw new Exception(Log.PossibleBugMessage(string.Format("Encoder error (Ctl {0}): {1}", ctl, (OpusErrors)ret), "4AAA9AA6-8429-4346-B939-D113206FFBA8"));
                }

                return(ret);
            }
示例#14
0
            /// <summary>
            /// Decodes audio samples.
            /// </summary>
            /// <param name="srcEncodedBuffer">Encoded data (or null, to reconstruct a missing frame)</param>
            /// <param name="dstBuffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values starting at offset replaced with audio samples.</param>
            /// <returns>The number of floats decoded and written to dstBuffer.</returns>
            /// <remarks>Set srcEncodedBuffer to null to instruct the decoder that a packet was dropped.</remarks>
            public int DecodeFloats(EncodedBuffer srcEncodedBuffer, ArraySegment <float> dstBuffer)
            {
                int length;

                using (var decoder = _decoder.Lock())
                {
                    if (decoder.Value == IntPtr.Zero)
                    {
                        throw new DissonanceException(Log.PossibleBugMessage("Attempted to access a null Opus decoder", "16261551-968B-44A8-80A1-E8DFB0109469"));
                    }

                    //Decode some data into the dstBuffer
                    // - We have the packet => run decode
                    // - We have a packet but lost flag is set => run FEC (if allowed)
                    // - We have no packet => Run PLC
                    using (var dstHandle = dstBuffer.Pin())
                    {
                        if (!srcEncodedBuffer.Encoded.HasValue || (srcEncodedBuffer.PacketLost && !EnableForwardErrorCorrection))
                        {
                            Log.Trace("Lost packet, but not applying FEC (srcEncodedBuffer.Encoded.HasValue:{0}, EnableForwardErrorCorrection:{1}", srcEncodedBuffer.Encoded.HasValue, EnableForwardErrorCorrection);

                            // We've lost a packet but cannot apply FEC because either we don't know what the next packet is (required for FEC) or FEC is explicitly disabled.
                            // Call decoder with null pointer and zero length to invoke basic packet loss concealment
                            length = OpusNativeMethods.opus_decode_float(
                                decoder.Value,
                                IntPtr.Zero,
                                0,
                                dstHandle.Ptr,
                                dstBuffer.Count,
                                false
                                );
                        }
                        else
                        {
                            // Either we have a packet, or FEC is enabled and we have the _next_ packet
                            using (var srcHandle = srcEncodedBuffer.Encoded.Value.Pin())
                            {
                                length = OpusNativeMethods.opus_decode_float(
                                    decoder.Value,
                                    srcHandle.Ptr,
                                    srcEncodedBuffer.Encoded.Value.Count,
                                    dstHandle.Ptr,
                                    dstBuffer.Count,
                                    srcEncodedBuffer.PacketLost
                                    );
                            }
                        }
                    }
                }

                if (length < 0)
                {
                    if (length == (int)OpusErrors.InvalidPacket)
                    {
                        if (!srcEncodedBuffer.Encoded.HasValue)
                        {
                            throw new OpusException(Log.PossibleBugMessage("Decoding failed: InvalidPacket. 'null' ", "03BE7561-3BCC-4F41-A7CB-C80F03981267"));
                        }
                        else
                        {
                            var arr = srcEncodedBuffer.Encoded.Value;
                            // ReSharper disable once AssignNullToNotNullAttribute (Justification Array of the segment isn't null here)
                            throw new OpusException(Log.PossibleBugMessage(string.Format("Decoding failed: InvalidPacket. '{0}'", Convert.ToBase64String(arr.Array, arr.Offset, arr.Count)), "EF4BC24C-491E-45D9-974C-FE5CB61BD54E"));
                        }
                    }
                    else
                    {
                        throw new OpusException(Log.PossibleBugMessage(string.Format("Decoding failed: {0} ", (OpusErrors)length), "A9C8EF2C-7830-4D8E-9D6E-EF0B9827E0A8"));
                    }
                }
                return(length);
            }
示例#15
0
 [NotNull] public static string OpusVersion()
 {
     // ReSharper disable once AssignNullToNotNullAttribute
     return(Marshal.PtrToStringAnsi(OpusNativeMethods.opus_get_version_string()));
 }
示例#16
0
            /// <summary>
            /// Decodes audio samples.
            /// </summary>
            /// <param name="srcEncodedBuffer">Encoded data (or null, to reconstruct a missing frame)</param>
            /// <param name="dstBuffer">An array of bytes. When this method returns, the buffer contains the specified byte array with the values starting at offset replaced with audio samples.</param>
            /// <returns>The number of floats decoded and written to dstBuffer.</returns>
            /// <remarks>Set srcEncodedBuffer to null to instruct the decoder that a packet was dropped.</remarks>
            public int DecodeFloats(ArraySegment <byte>?srcEncodedBuffer, ArraySegment <float> dstBuffer)
            {
                int length;

                using (var decoder = _decoder.Lock())
                {
                    if (decoder.Value == IntPtr.Zero)
                    {
                        throw new DissonanceException(Log.PossibleBugMessage("Attempted to access a null Opus decoder", "16261551-968B-44A8-80A1-E8DFB0109469"));
                    }

                    using (var dstHandle = dstBuffer.Pin())
                    {
                        if (srcEncodedBuffer.HasValue)
                        {
                            using (var srcHandle = srcEncodedBuffer.Value.Pin())
                            {
                                length = OpusNativeMethods.opus_decode_float(
                                    decoder.Value,
                                    srcHandle.Ptr,
                                    srcEncodedBuffer.Value.Count,
                                    dstHandle.Ptr,
                                    dstBuffer.Count,
                                    false
                                    );
                            }
                        }
                        else
                        {
                            //Call decoder with null pointer and zero length to inform it of packet loss
                            length = OpusNativeMethods.opus_decode_float(
                                decoder.Value,
                                IntPtr.Zero,
                                0,
                                dstHandle.Ptr,
                                dstBuffer.Count,
                                EnableForwardErrorCorrection
                                );
                        }
                    }
                }

                if (length < 0)
                {
                    if (length == (int)OpusErrors.InvalidPacket)
                    {
                        if (!srcEncodedBuffer.HasValue)
                        {
                            throw new OpusException(Log.PossibleBugMessage("Decoding failed: InvalidPacket. 'null' ", "03BE7561-3BCC-4F41-A7CB-C80F03981267"));
                        }
                        else
                        {
                            // ReSharper disable once AssignNullToNotNullAttribute (Justification Array of the segment isn't null here)
                            throw new OpusException(Log.PossibleBugMessage(string.Format("Decoding failed: InvalidPacket. '{0}'", Convert.ToBase64String(srcEncodedBuffer.Value.Array, srcEncodedBuffer.Value.Offset, srcEncodedBuffer.Value.Count)), "EF4BC24C-491E-45D9-974C-FE5CB61BD54E"));
                        }
                    }
                    else
                    {
                        throw new OpusException(Log.PossibleBugMessage(string.Format("Decoding failed: {0} ", (OpusErrors)length), "A9C8EF2C-7830-4D8E-9D6E-EF0B9827E0A8"));
                    }
                }
                return(length);
            }