From b4d391c3ec347cedc0a549ef1ecc756165c02f29 Mon Sep 17 00:00:00 2001 From: Lyubomir Marinov <lyubomir.marinov@jitsi.org> Date: Tue, 29 Jan 2013 11:40:35 +0000 Subject: [PATCH] Does not allow the FMJ encoder and decoder classes of Opus to register with FMJ/the application unless the jnopus JNI library is loaded and appears functional. Otherwise, the Opus codec will be considered supported and advertised as such while the JNI library may not be available at all (e.g. Android). --- .../neomedia/codec/audio/opus/JNIDecoder.java | 12 +- .../neomedia/codec/audio/opus/JNIEncoder.java | 133 ++++---- .../impl/neomedia/codec/audio/opus/Opus.java | 318 +++++++++--------- 3 files changed, 244 insertions(+), 219 deletions(-) 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 6b5a3e79..aa3642b5 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 75827e6b..1aca3db3 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 4115d208..eabbfdc5 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"); - } - } -- GitLab