diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java index 6b5a3e79daecefd8a5898d593e661ccf932012da..aa3642b5b37172886273fc297181e4bd9bafe7ce 100644 --- a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java +++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIDecoder.java @@ -29,7 +29,8 @@ public class JNIDecoder * The list of <tt>Format</tt>s of audio data supported as input by * <tt>JNIDecoder</tt> instances. */ - private static final Format[] SUPPORTED_INPUT_FORMATS; + private static final Format[] SUPPORTED_INPUT_FORMATS + = new Format[] { new AudioFormat(Constants.OPUS_RTP) }; /** * The list of <tt>Format</tt>s of audio data supported as output by @@ -52,8 +53,13 @@ public class JNIDecoder static { - SUPPORTED_INPUT_FORMATS - = new Format[] {new AudioFormat(Constants.OPUS_RTP)}; + /* + * If the Opus class or its supporting JNI library are not functional, + * it is too late to discover the fact in #doOpen() because a JNIDecoder + * instance has already been initialized and it has already signaled + * that the Opus codec is supported. + */ + Opus.assertOpusIsFunctional(); } /** diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java index 75827e6b0d539f94033cec71428a21c5e6b656fc..1aca3db3c6766164bc31e6e35999418e62bcf974 100644 --- a/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java +++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/JNIEncoder.java @@ -43,7 +43,6 @@ public class JNIEncoder */ static final double[] SUPPORTED_INPUT_SAMPLE_RATES = new double[] { 48000 }; - //= new double[] { 8000, 12000, 16000, 24000, 48000 }; /** * The list of <tt>Format</tt>s of audio data supported as output by @@ -61,18 +60,19 @@ public class JNIEncoder Format.NOT_SPECIFIED, Format.byteArray) }; - /** - * The <tt>Logger</tt> used by this <tt>JNIEncoder</tt> instance - * for logging output. - */ - private final Logger logger - = Logger.getLogger(JNIEncoder.class); - /** * Set the supported input formats. */ static { + /* + * If the Opus class or its supporting JNI library are not functional, + * it is too late to discover the fact in #doOpen() because a JNIEncoder + * instance has already been initialized and it has already signaled + * that the Opus codec is supported. + */ + Opus.assertOpusIsFunctional(); + int supportedInputCount = SUPPORTED_INPUT_SAMPLE_RATES.length; SUPPORTED_INPUT_FORMATS = new Format[supportedInputCount*2]; @@ -107,28 +107,29 @@ public class JNIEncoder } /** - * The bytes from an input <tt>Buffer</tt> from a previous call to - * {@link #process(Buffer, Buffer)} that this <tt>Codec</tt> didn't process - * because the total number of bytes was less than {@link #inputFrameSize()} - * need to be prepended to a subsequent input <tt>Buffer</tt> in order to - * process a total of {@link #inputFrameSize()} bytes. + * Codec audio bandwidth, obtained from configuration. */ - private byte[] previousInput = null; + private int bandwidthConfig; /** - * The length of the audio data in {@link #previousInput}. + * Bitrate in bits per second setting, obtained from the configuration. */ - private int previousInputLength = 0; + private int bitrateConfig; /** - * The pointer to the native OpusEncoder structure + * Number of channels to use, default to 1. */ - private long encoder = 0; + private int channels = 1; /** - * Number of channels to use, default to 1. + * Complexity setting, obtained from configuration. */ - private int channels = 1; + private int complexityConfig; + + /** + * The pointer to the native OpusEncoder structure + */ + private long encoder = 0; /** * Frame size in ms (2.5, 5, 10, 20, 40 or 60). Default to 20 @@ -136,24 +137,30 @@ public class JNIEncoder private double frameSize = 20; /** - * The minimum expected packet loss percentage to set to the encoder. + * The <tt>Logger</tt> used by this <tt>JNIEncoder</tt> instance + * for logging output. */ - private int minPacketLoss = 0; + private final Logger logger + = Logger.getLogger(JNIEncoder.class); /** - * Bitrate in bits per second setting, obtained from the configuration. + * The minimum expected packet loss percentage to set to the encoder. */ - private int bitrateConfig; + private int minPacketLoss = 0; /** - * Whether to use FEC, obtained from configuration. + * The bytes from an input <tt>Buffer</tt> from a previous call to + * {@link #process(Buffer, Buffer)} that this <tt>Codec</tt> didn't process + * because the total number of bytes was less than {@link #inputFrameSize()} + * need to be prepended to a subsequent input <tt>Buffer</tt> in order to + * process a total of {@link #inputFrameSize()} bytes. */ - private boolean useFecConfig; + private byte[] previousInput = null; /** - * Complexity setting, obtained from configuration. + * The length of the audio data in {@link #previousInput}. */ - private int complexityConfig; + private int previousInputLength = 0; /** * Whether to use DTX, obtained from configuration. @@ -161,9 +168,9 @@ public class JNIEncoder private boolean useDtxConfig; /** - * Codec audio bandwidth, obtained from configuration. + * Whether to use FEC, obtained from configuration. */ - private int bandwidthConfig; + private boolean useFecConfig; /** @@ -180,27 +187,6 @@ public JNIEncoder() addControl(this); } - /** - * Returns the number of bytes that we need to read from the input buffer - * in order ot fill a frame of <tt>frameSize</tt>. Depends on the input - * sample frequency, the number of channels and <tt>frameSize</tt> - * - * @return the number of bytes that we need to read from the input buffer - * in order ot fill a frame of <tt>frameSize</tt>. Depends on the input - * sample frequency, the number of channels and <tt>frameSize</tt> - */ - private int inputFrameSize() - { - int fs = - (int) ( - 2 /* sizeof(short) */ - * channels - * ((AudioFormat)getInputFormat()).getSampleRate() /* samples in 1s */ - * frameSize /* milliseconds */ - ) / 1000; - - return fs; - } /** * @see AbstractCodecExt#doClose() */ @@ -211,7 +197,6 @@ protected void doClose() Opus.encoder_destroy(encoder); } } - /** * Opens this <tt>Codec</tt> and acquires the resources that it needs to * operate. A call to {@link PlugIn#open()} on this instance will result in @@ -417,6 +402,17 @@ else if (inputLength < inputBytesNeeded) return BUFFER_PROCESSED_OK | INPUT_BUFFER_NOT_CONSUMED; } + /** + * Stub. Only added in order to implement the + * <tt>Control</tt> interface. + * + * @return null + */ + public Component getControlComponent() + { + return null; + } + /** * Get the output format. * @@ -457,6 +453,28 @@ public long computeDuration(long length) return outputFormat; } + /** + * Returns the number of bytes that we need to read from the input buffer + * in order ot fill a frame of <tt>frameSize</tt>. Depends on the input + * sample frequency, the number of channels and <tt>frameSize</tt> + * + * @return the number of bytes that we need to read from the input buffer + * in order ot fill a frame of <tt>frameSize</tt>. Depends on the input + * sample frequency, the number of channels and <tt>frameSize</tt> + */ + private int inputFrameSize() + { + int fs = + (int) ( + 2 /* sizeof(short) */ + * channels + * ((AudioFormat)getInputFormat()).getSampleRate() /* samples in 1s */ + * frameSize /* milliseconds */ + ) / 1000; + + return fs; + } + /** * Updates the encoder's expected packet loss percentage to the bigger of * <tt>percentage</tt> and <tt>this.minPacketLoss</tt>. @@ -474,17 +492,6 @@ public void setExpectedPacketLoss(int percentage) + " (minimum " + minPacketLoss + ")"); } - /** - * Stub. Only added in order to implement the - * <tt>Control</tt> interface. - * - * @return null - */ - public Component getControlComponent() - { - return null; - } - /** * Sets the format parameters. * diff --git a/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java b/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java index 4115d208529126fd703a31dafe4f25772a53cdd5..eabbfdc5d9cb2ef986a815d14e34685b7e0e44b2 100644 --- a/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java +++ b/src/org/jitsi/impl/neomedia/codec/audio/opus/Opus.java @@ -7,16 +7,16 @@ package org.jitsi.impl.neomedia.codec.audio.opus; /** - * Implements an interface to the native opus library + * Implements an interface to the native opus library. * * @author Boris Grozev */ public class Opus { /** - * Opus narrowband constant + * Opus fullband constant */ - public static final int BANDWIDTH_NARROWBAND = 1101; + public static final int BANDWIDTH_FULLBAND = 1105; /** * Opus mediumband constant @@ -24,9 +24,9 @@ public class Opus public static final int BANDWIDTH_MEDIUMBAND = 1102; /** - * Opus wideband constant + * Opus narrowband constant */ - public static final int BANDWIDTH_WIDEBAND = 1103; + public static final int BANDWIDTH_NARROWBAND = 1101; /** * Opus superwideband constant @@ -34,14 +34,21 @@ public class Opus public static final int BANDWIDTH_SUPERWIDEBAND = 1104; /** - * Opus fullband constant + * Opus wideband constant */ - public static final int BANDWIDTH_FULLBAND = 1105; + public static final int BANDWIDTH_WIDEBAND = 1103; /** - * Constant usually indicating that no error occurred + * Opus constant for an invalid packet */ - public static final int OPUS_OK = 0; + public static final int INVALID_PACKET = -4; + + /** + * The maximum size of a packet we can create. Since we're only creating + * packets with a single frame, that's a 1 byte TOC + the maximum frame size. + * See http://tools.ietf.org/html/rfc6716#section-3.2 + */ + public static final int MAX_PACKET = 1+1275; /** * Constant used to set various settings to "automatic" @@ -49,27 +56,106 @@ public class Opus public static final int OPUS_AUTO = -1000; /** - * Opus constant for an invalid packet + * Constant usually indicating that no error occurred */ - public static final int INVALID_PACKET = -4; + public static final int OPUS_OK = 0; /** - * The maximum size of a packet we can create. Since we're only creating - * packets with a single frame, that's a 1 byte TOC + the maximum frame size. - * See http://tools.ietf.org/html/rfc6716#section-3.2 + * Load the native library. */ - public static final int MAX_PACKET = 1+1275; + static + { + System.loadLibrary("jnopus"); + } + /** + * Asserts that the <tt>Opus</tt> class and the JNI library which supports + * it are functional. The method is to be invoked early (e.g. static/class + * initializers) by classes which require it (i.e. they depend on it and + * they cannot function without it). + */ + public static void assertOpusIsFunctional() + { + int channels = 1; + decoder_get_size(channels); + encoder_get_size(channels); + } /** - * Returns the size in bytes required for an OpusEncoder structure. + * Decodes an opus packet from <tt>input</tt> into <tt>output</tt>. + * + * @param decoder The decoder to use + * @param input An array containing the opus packet. + * @param inputOffset The offset into <tt>input</tt> where the packets + * begins. + * @param inputSize Size of the packet in bytes. + * @param output Output buffer where the output will be stored. + * @param outputSize Size in bytes of the output buffer. + * @param decodeFEC 0 to decode the packet normally, 1 to decode the FEC + * data in the packet. + * + * @return Number of samples decoded + */ + public static native int decode(long decoder, byte[] input, int inputOffset, + int inputSize, byte[] output, + int outputSize, int decodeFEC); + + /** + * Creates an OpusDecoder structure, returns a pointer to it or 0 on error. + * + * @param Fs Sample rate to decode to + * @param channels number of channels to decode to(1/2) + * + * @return A pointer to the OpusDecoder structure created, 0 on error. + */ + public static native long decoder_create(int Fs, int channels); + + /** + * Destroys an OpusDecoder, freeing it's resources. + * + * @param decoder Address of the structure (as returned from decoder_create) + */ + public static native void decoder_destroy(long decoder); + + /** + * Returns the number of samples in an opus packet + + * @param decoder The decoder to use. + * @param packet Array holding the packet. + * @param offset Offset into packet where the actual packet begins. + * @param len Length of the packet. + * + * @return the number of samples in <tt>packet</tt> . + */ + public static native int decoder_get_nb_samples(long decoder, byte[] packet, int offset, int len); + + /** + * Returns the size in bytes required for an OpusDecoder structure. * * @param channels number of channels (1/2) * - * @return the size in bytes required for an OpusEncoder structure. + * @return the size in bytes required for an OpusDecoder structure. */ - public static native int encoder_get_size(int channels); + public static native int decoder_get_size(int channels); + + /** + * Encodes the input from <tt>input</tt> into an opus packet in + * <tt>output</tt>. + * + * @param encoder The encoder to use. + * @param input Array containing PCM encoded input. + * @param offset Offset to use into the <tt>input</tt> array + * @param frameSize The number of samples per channel in <tt>input</tt>. + * @param output Array where the encoded packet will be stored. + * @param outputSize The number of available bytes in <tt>output</tt>. + * + * @return The number of bytes written in <tt>output</tt>, or a negative + * on error. + */ + public static native int encode(long encoder, byte[] input, int offset, + int frameSize, byte[] output, + int outputSize); /** * Creates an OpusEncoder structure, returns a pointer to it casted to long. @@ -91,15 +177,14 @@ public class Opus public static native void encoder_destroy(long encoder); /** - * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder bitrate - * + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns the + * current encoder audio bandwidth + * . * @param encoder The encoder to use - * @param bitrate The bitrate to set * - * @return OPUS_OK on success + * @return the current encoder audio bandwidth */ - public static native int encoder_set_bitrate(long encoder, int bitrate); + public static native int encoder_get_bandwidth(long encoder); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns the @@ -112,39 +197,23 @@ public class Opus public static native int encoder_get_bitrate(long encoder); /** - * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder audio bandwidth. - * - * @param encoder The encoder to use - * @param bandwidth The bandwidth to set, should be one of - * <tt>BANDWIDTH_FULLBAND</tt>, <tt>BANDWIDTH_MEDIUMBAND</tt>, - * <tt>BANDWIDTH_NARROWBAND</tt>, <tt>BANDWIDTH_SUPERWIDEBAND</tt> or - * <tt>BANDWIDTH_WIDEBAND</tt>. + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns + * the current DTX setting of the encoder. * - * @return OPUS_OK on success - */ - public static native int encoder_set_bandwidth(long encoder, int bandwidth); - - /** - * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns the - * current encoder audio bandwidth - * . * @param encoder The encoder to use * - * @return the current encoder audio bandwidth + * @return the current DTX setting of the encoder. */ - public static native int encoder_get_bandwidth(long encoder); + public static native int encoder_get_dtx(long encoder); /** - * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder VBR setting + * Returns the size in bytes required for an OpusEncoder structure. * - * @param encoder The encoder to use - * @param use_vbr 0 to turn VBR off, non-zero to turn it on. + * @param channels number of channels (1/2) * - * @return OPUS_OK on success + * @return the size in bytes required for an OpusEncoder structure. */ - public static native int encoder_set_vbr(long encoder, int use_vbr); + public static native int encoder_get_size(int channels); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns the @@ -156,18 +225,6 @@ public class Opus */ public static native int encoder_get_vbr(long encoder); - /** - * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder VBR constraint setting - * - * @param encoder The encoder to use - * @param use_cvbr 0 to turn VBR constraint off, non-zero to turn it on. - * - * @return OPUS_OK on success - */ - public static native int encoder_set_vbr_constraint(long encoder, - int use_cvbr); - /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns * the current VBR constraint encoder setting. @@ -180,38 +237,40 @@ public static native int encoder_set_vbr_constraint(long encoder, /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder complexity setting. + * encoder audio bandwidth. * * @param encoder The encoder to use - * @param complexity The complexity level, from 1 to 10 + * @param bandwidth The bandwidth to set, should be one of + * <tt>BANDWIDTH_FULLBAND</tt>, <tt>BANDWIDTH_MEDIUMBAND</tt>, + * <tt>BANDWIDTH_NARROWBAND</tt>, <tt>BANDWIDTH_SUPERWIDEBAND</tt> or + * <tt>BANDWIDTH_WIDEBAND</tt>. * * @return OPUS_OK on success */ - public static native int encoder_set_complexity(long encoder, - int complexity); + public static native int encoder_set_bandwidth(long encoder, int bandwidth); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder FEC setting. + * encoder bitrate + * * @param encoder The encoder to use - * @param use_inband_fec 0 to turn FEC off, non-zero to turn it on. + * @param bitrate The bitrate to set * * @return OPUS_OK on success */ - public static native int encoder_set_inband_fec(long encoder, - int use_inband_fec); + public static native int encoder_set_bitrate(long encoder, int bitrate); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * force channels setting of the encoder. + * encoder complexity setting. * * @param encoder The encoder to use - * @param forcechannels Number of channels + * @param complexity The complexity level, from 1 to 10 * * @return OPUS_OK on success */ - public static native int encoder_set_force_channels(long encoder, - int forcechannels); + public static native int encoder_set_complexity(long encoder, + int complexity); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the @@ -224,27 +283,31 @@ public static native int encoder_set_force_channels(long encoder, */ public static native int encoder_set_dtx(long encoder, int use_dtx); + + + /** - * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Returns - * the current DTX setting of the encoder. + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * force channels setting of the encoder. * * @param encoder The encoder to use + * @param forcechannels Number of channels * - * @return the current DTX setting of the encoder. + * @return OPUS_OK on success */ - public static native int encoder_get_dtx(long encoder); + public static native int encoder_set_force_channels(long encoder, + int forcechannels); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the - * encoder's expected packet loss percentage. - * + * encoder FEC setting. * @param encoder The encoder to use - * @param percentage 0 to turn DTX off, non-zero to turn it on + * @param use_inband_fec 0 to turn FEC off, non-zero to turn it on. * - * @return OPUS_OK on success. + * @return OPUS_OK on success */ - public static native int encoder_set_packet_loss_perc(long encoder, - int percentage); + public static native int encoder_set_inband_fec(long encoder, + int use_inband_fec); /** * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the @@ -262,70 +325,39 @@ public static native int encoder_set_max_bandwidth(long encoder, int maxBandwidth); /** - * Encodes the input from <tt>input</tt> into an opus packet in - * <tt>output</tt>. - * - * @param encoder The encoder to use. - * @param input Array containing PCM encoded input. - * @param offset Offset to use into the <tt>input</tt> array - * @param frameSize The number of samples per channel in <tt>input</tt>. - * @param output Array where the encoded packet will be stored. - * @param outputSize The number of available bytes in <tt>output</tt>. - * - * @return The number of bytes written in <tt>output</tt>, or a negative - * on error. - */ - public static native int encode(long encoder, byte[] input, int offset, - int frameSize, byte[] output, - int outputSize); - - - - - /** - * Returns the size in bytes required for an OpusDecoder structure. + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder's expected packet loss percentage. * - * @param channels number of channels (1/2) + * @param encoder The encoder to use + * @param percentage 0 to turn DTX off, non-zero to turn it on * - * @return the size in bytes required for an OpusDecoder structure. + * @return OPUS_OK on success. */ - public static native int decoder_get_size(int channels); + public static native int encoder_set_packet_loss_perc(long encoder, + int percentage); /** - * Creates an OpusDecoder structure, returns a pointer to it or 0 on error. - * - * @param Fs Sample rate to decode to - * @param channels number of channels to decode to(1/2) + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder VBR setting * - * @return A pointer to the OpusDecoder structure created, 0 on error. - */ - public static native long decoder_create(int Fs, int channels); - - /** - * Destroys an OpusDecoder, freeing it's resources. + * @param encoder The encoder to use + * @param use_vbr 0 to turn VBR off, non-zero to turn it on. * - * @param decoder Address of the structure (as returned from decoder_create) + * @return OPUS_OK on success */ - public static native void decoder_destroy(long decoder); + public static native int encoder_set_vbr(long encoder, int use_vbr); /** - * Decodes an opus packet from <tt>input</tt> into <tt>output</tt>. + * Wrapper around the native <tt>opus_encoder_ctl</tt> function. Sets the + * encoder VBR constraint setting * - * @param decoder The decoder to use - * @param input An array containing the opus packet. - * @param inputOffset The offset into <tt>input</tt> where the packets - * begins. - * @param inputSize Size of the packet in bytes. - * @param output Output buffer where the output will be stored. - * @param outputSize Size in bytes of the output buffer. - * @param decodeFEC 0 to decode the packet normally, 1 to decode the FEC - * data in the packet. + * @param encoder The encoder to use + * @param use_cvbr 0 to turn VBR constraint off, non-zero to turn it on. * - * @return Number of samples decoded + * @return OPUS_OK on success */ - public static native int decode(long decoder, byte[] input, int inputOffset, - int inputSize, byte[] output, - int outputSize, int decodeFEC); + public static native int encoder_set_vbr_constraint(long encoder, + int use_cvbr); /** * Returns the audio bandwidth of an opus packet, one of @@ -365,24 +397,4 @@ public static native int decode(long decoder, byte[] input, int inputOffset, public static native int packet_get_nb_frames(byte[] packet, int offset, int len); - /** - * Returns the number of samples in an opus packet - - * @param decoder The decoder to use. - * @param packet Array holding the packet. - * @param offset Offset into packet where the actual packet begins. - * @param len Length of the packet. - * - * @return the number of samples in <tt>packet</tt> . - */ - public static native int decoder_get_nb_samples(long decoder, byte[] packet, int offset, int len); - - /** - * Load the native library. - */ - static - { - System.loadLibrary("jnopus"); - } - }