Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Comminos <andrewcomminos@gmail.com>2013-11-09 04:55:32 +0400
committerAndrew Comminos <andrewcomminos@gmail.com>2013-11-09 04:55:32 +0400
commitfde2187b916986e36322e1843fde82e9df56d4c6 (patch)
tree9cb7950c04b700e54a5e2ccf62ab3aa3a0ae4cf1 /src/main/java
parent58e6f022f7256a27dada42c0ceb664815a6538fb (diff)
Implemented CELT Alpha and Beta output, much better Opus input, Speex
resampling.
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/morlunk/jumble/Constants.java35
-rw-r--r--src/main/java/com/morlunk/jumble/JumbleService.java5
-rw-r--r--src/main/java/com/morlunk/jumble/audio/AudioInput.java39
-rw-r--r--src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java78
-rw-r--r--src/main/java/com/morlunk/jumble/audio/javacpp/CELT11.java34
-rw-r--r--src/main/java/com/morlunk/jumble/audio/javacpp/CELT7.java27
-rw-r--r--src/main/java/com/morlunk/jumble/audio/javacpp/Opus.java10
-rw-r--r--src/main/java/com/morlunk/jumble/audio/javacpp/Speex.java26
8 files changed, 161 insertions, 93 deletions
diff --git a/src/main/java/com/morlunk/jumble/Constants.java b/src/main/java/com/morlunk/jumble/Constants.java
index 67dcaa6..b2190ab 100644
--- a/src/main/java/com/morlunk/jumble/Constants.java
+++ b/src/main/java/com/morlunk/jumble/Constants.java
@@ -16,31 +16,34 @@
package com.morlunk.jumble;
+import com.googlecode.javacpp.IntPointer;
+import com.googlecode.javacpp.Loader;
+import com.googlecode.javacpp.Pointer;
import com.morlunk.jumble.audio.Audio;
+import com.morlunk.jumble.audio.javacpp.CELT11;
+import com.morlunk.jumble.audio.javacpp.CELT7;
public class Constants {
-
/** Set dynamically by JNI calls. */
public static int CELT_11_VERSION ;
/** Set dynamically by JNI calls. */
public static int CELT_7_VERSION;
static {
- // Load CELT bitstream versions from JNI. TODO clean me with renamed types for version
-// int[] error = new int[1];
-// com.morlunk.jumble.audio.celt11.SWIGTYPE_p_CELTMode celt11Mode = CELT11.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, error);
-// com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTMode celt7Mode = CELT7.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, error);
-//
-// int[] celt11Version = new int[1];
-// int[] celt7Version = new int[1];
-//
-// CELT11.celt_mode_info(celt11Mode, CELT11Constants.CELT_GET_BITSTREAM_VERSION, celt11Version);
-// CELT7.celt_mode_info(celt7Mode, CELT7Constants.CELT_GET_BITSTREAM_VERSION, celt7Version);
-// CELT11.celt_mode_destroy(celt11Mode);
-// CELT7.celt_mode_destroy(celt7Mode);
-//
-// CELT_11_VERSION = celt11Version[0];
-// CELT_7_VERSION = celt7Version[0];
+ // Load CELT bitstream versions from JNI.
+ Pointer celt11Mode = CELT11.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, null);
+ Pointer celt7Mode = CELT7.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, null);
+
+ IntPointer celt11Version = new IntPointer();
+ IntPointer celt7Version = new IntPointer();
+
+ CELT11.celt_mode_info(celt11Mode, CELT11.CELT_GET_BITSTREAM_VERSION, celt11Version);
+ CELT7.celt_mode_info(celt7Mode, CELT7.CELT_GET_BITSTREAM_VERSION, celt7Version);
+ CELT11.celt_mode_destroy(celt11Mode);
+ CELT7.celt_mode_destroy(celt7Mode);
+
+ CELT_11_VERSION = celt11Version.get();
+ CELT_7_VERSION = celt7Version.get();
}
public static final int PROTOCOL_MAJOR = 1;
diff --git a/src/main/java/com/morlunk/jumble/JumbleService.java b/src/main/java/com/morlunk/jumble/JumbleService.java
index aba134e..16e867b 100644
--- a/src/main/java/com/morlunk/jumble/JumbleService.java
+++ b/src/main/java/com/morlunk/jumble/JumbleService.java
@@ -243,12 +243,12 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
@Override
public void requestBanList() throws RemoteException {
-
+ // TODO
}
@Override
public void requestUserList() throws RemoteException {
-
+ // TODO
}
@Override
@@ -605,7 +605,6 @@ public class JumbleService extends Service implements JumbleConnection.JumbleCon
runnable.run(mObservers.getBroadcastItem(i));
} catch (RemoteException e) {
e.printStackTrace();
- // TODO handle this error
}
}
mObservers.finishBroadcast();
diff --git a/src/main/java/com/morlunk/jumble/audio/AudioInput.java b/src/main/java/com/morlunk/jumble/audio/AudioInput.java
index e9be7fb..d9aaebb 100644
--- a/src/main/java/com/morlunk/jumble/audio/AudioInput.java
+++ b/src/main/java/com/morlunk/jumble/audio/AudioInput.java
@@ -18,6 +18,7 @@ package com.morlunk.jumble.audio;
import android.media.AudioFormat;
import android.media.AudioRecord;
+import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.util.Log;
@@ -47,6 +48,8 @@ public class AudioInput extends JumbleMessageHandler.Stub implements Runnable {
public void onFrameEncoded(byte[] data, int length, JumbleUDPMessageType messageType);
}
+ public static final int[] SAMPLE_RATES = { 48000, 44100, 22050, 160000, 11025, 8000 };
+ public static final int SPEEX_RESAMPLE_QUALITY = 3;
public static final int OPUS_MAX_BYTES = 512; // Opus specifies 4000 bytes as a recommended value for encoding, but the official mumble project uses 512.
private Pointer mOpusEncoder;;
@@ -54,15 +57,17 @@ public class AudioInput extends JumbleMessageHandler.Stub implements Runnable {
// private com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTMode mCELTAlphaMode;
// private com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTEncoder mCELTAlphaEncoder;
private Speex.SpeexPreprocessState mPreprocessState;
+ private Speex.SpeexResampler mResampler;
private AudioInputListener mListener;
private int mTransmitMode = Constants.TRANSMIT_PUSH_TO_TALK;
private AudioRecord mAudioRecord;
private int mMinBufferSize;
- private int mInputSampleRate = 48000; //44100; FIXME
+ private int mInputSampleRate = -1;
private int mFrameSize = Audio.FRAME_SIZE;
- private int mFramesPerPacket = 2;
+ private int mMicFrameSize = Audio.FRAME_SIZE;
+ private int mFramesPerPacket = 6;
// Temporary encoder state
private final short[] mOpusBuffer = new short[mFrameSize*mFramesPerPacket];
@@ -88,8 +93,24 @@ public class AudioInput extends JumbleMessageHandler.Stub implements Runnable {
switchCodec(codec);
configurePreprocessState();
- // TODO support input resampling. We can't expect 48000hz on all android devices.
- int reportedMinBufferSize = AudioRecord.getMinBufferSize(Audio.SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
+ // Use the highest sample rate we can get. TODO make this an option in settings.
+ for(int rate : SAMPLE_RATES) {
+ if(AudioRecord.getMinBufferSize(rate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT) > 0) {
+ mInputSampleRate = rate;
+ break;
+ }
+ }
+ if(mInputSampleRate != -1) {
+ Log.d(Constants.TAG, "Initialized AudioInput with sample rate "+mInputSampleRate);
+ if(mInputSampleRate != Audio.SAMPLE_RATE) {
+ mResampler = new Speex.SpeexResampler(1, mInputSampleRate, Audio.SAMPLE_RATE, SPEEX_RESAMPLE_QUALITY);
+ mMicFrameSize = (mFrameSize * mInputSampleRate)/Audio.SAMPLE_RATE;
+ }
+ } else {
+ throw new RuntimeException("Device does not support any compatible input sampling rates!");
+ }
+
+ int reportedMinBufferSize = AudioRecord.getMinBufferSize(mInputSampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
mMinBufferSize = Math.max(reportedMinBufferSize, mFrameSize);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, mInputSampleRate, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mMinBufferSize);
}
@@ -205,16 +226,22 @@ public class AudioInput extends JumbleMessageHandler.Stub implements Runnable {
if(mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED)
return;
+
final short[] audioData = new short[mFrameSize];
+ final short[] resampleBuffer = new short[mMicFrameSize];
// We loop when the 'recording' instance var is true instead of checking audio record state because we want to always cleanly shutdown.
while(mRecording) {
- int shortsRead = mAudioRecord.read(audioData, 0, mFrameSize);
+ int shortsRead = mAudioRecord.read(mResampler != null ? resampleBuffer : audioData, 0, mResampler != null ? mMicFrameSize : mFrameSize);
if(shortsRead > 0) {
int len;
boolean encoded = false;
mFrameCounter++;
+ // Resample if necessary
+ if(mResampler != null)
+ mResampler.resample(resampleBuffer, audioData);
+
boolean talking = true;
if(mTransmitMode == Constants.TRANSMIT_VOICE_ACTIVITY) {
@@ -310,6 +337,8 @@ public class AudioInput extends JumbleMessageHandler.Stub implements Runnable {
Opus.opus_encoder_destroy(mOpusEncoder);
if(mPreprocessState != null)
mPreprocessState.destroy();
+ if(mResampler != null)
+ mResampler.destroy();
}
@Override
diff --git a/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java b/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java
index 107ef7b..5d2c85e 100644
--- a/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java
+++ b/src/main/java/com/morlunk/jumble/audio/AudioOutputSpeech.java
@@ -21,6 +21,8 @@ import com.googlecode.javacpp.FloatPointer;
import com.googlecode.javacpp.IntPointer;
import com.googlecode.javacpp.Loader;
import com.googlecode.javacpp.Pointer;
+import com.morlunk.jumble.audio.javacpp.CELT11;
+import com.morlunk.jumble.audio.javacpp.CELT7;
import com.morlunk.jumble.audio.javacpp.Opus;
import com.morlunk.jumble.audio.javacpp.Speex;
import com.morlunk.jumble.model.User;
@@ -40,14 +42,10 @@ public class AudioOutputSpeech {
public void onTalkStateUpdated(int session, User.TalkState state);
}
- // Native audio pointers
-// private com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTDecoder mCELTAlphaDecoder;
-// private com.morlunk.jumble.audio.celt7.SWIGTYPE_p_CELTMode mCELTAlphaMode;
-// private com.morlunk.jumble.audio.celt11.SWIGTYPE_p_CELTDecoder mCELTBetaDecoder;
-// private SWIGTYPE_p_void mSpeexDecoder;
-// private SpeexBits mSpeexBits;
-
private Pointer mOpusDecoder;
+ private Pointer mCELTBetaDecoder;
+ private Pointer mCELTAlphaMode;
+ private Pointer mCELTAlphaDecoder;
private Speex.JitterBuffer mJitterBuffer;
private int mSession;
@@ -58,11 +56,10 @@ public class AudioOutputSpeech {
private float[] mBuffer;
private Queue<BytePointer> mFrames = new ConcurrentLinkedQueue<BytePointer>();
private int mMissCount = 0;
- private int mMissedFrames = 0;
private float mAverageAvailable = 0;
private boolean mHasTerminator = false;
private boolean mLastAlive = true;
- private int mBufferOffset, mBufferFilled, mLastConsume = 0;
+ private int mBufferFilled, mLastConsume = 0;
private int ucFlags;
private TalkStateListener mTalkStateListener;
@@ -83,16 +80,16 @@ public class AudioOutputSpeech {
// mSpeexDecoder = Speex.speex_decoder_init(Speex.getSpeex_uwb_mode());
// Speex.speex_decoder_ctl(mSpeexDecoder, SpeexConstants.SPEEX_SET_ENH, new int[] { 1 });
// break;
-// case UDPVoiceCELTBeta:
-// mCELTBetaDecoder = CELT11.celt_decoder_create(Audio.SAMPLE_RATE, 1, error);
-// break;
-// case UDPVoiceCELTAlpha:
-// mCELTAlphaMode = CELT7.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, error);
-// mCELTAlphaDecoder = CELT7.celt_decoder_create(mCELTAlphaMode, 1, error);
-// break;
+ case UDPVoiceCELTBeta:
+ mCELTBetaDecoder = CELT11.celt_decoder_create(Audio.SAMPLE_RATE, 1, null);
+ break;
+ case UDPVoiceCELTAlpha:
+ mCELTAlphaMode = CELT7.celt_mode_create(Audio.SAMPLE_RATE, Audio.FRAME_SIZE, null);
+ mCELTAlphaDecoder = CELT7.celt_decoder_create(mCELTAlphaMode, 1, null);
+ break;
}
- mBuffer = new float[mAudioBufferSize*2]; // Leave room for an extra frame in the buffer- TODO fix.
+ mBuffer = new float[mAudioBufferSize*2]; // Leave room for an extra frame in the buffer, this saves buffer resize operations at runtime normally.
mJitterBuffer = new Speex.JitterBuffer(Audio.FRAME_SIZE);
IntPointer margin = new IntPointer(1);
margin.put(10 * Audio.FRAME_SIZE);
@@ -152,7 +149,7 @@ public class AudioOutputSpeech {
while(mBufferFilled < num) {
int decodedSamples = Audio.FRAME_SIZE;
- //resizeBuffer(mBufferFilled + mAudioBufferSize); TODO reimplement resize
+ resizeBuffer(mBufferFilled + mAudioBufferSize);
if(!mLastAlive)
out.fill(0);
@@ -236,16 +233,16 @@ public class AudioOutputSpeech {
BytePointer data = mFrames.poll();
if(mCodec == JumbleUDPMessageType.UDPVoiceCELTAlpha) {
-// CELT7.celt_decode_float(mCELTAlphaDecoder,
-// data,
-// data.length,
-// out);
+ CELT7.celt_decode_float(mCELTAlphaDecoder,
+ data,
+ data.capacity(),
+ out);
} else if(mCodec == JumbleUDPMessageType.UDPVoiceCELTBeta) {
-// CELT11.celt_decode_float(mCELTBetaDecoder,
-// data,
-// data.length,
-// out,
-// Audio.FRAME_SIZE);
+ CELT11.celt_decode_float(mCELTBetaDecoder,
+ data,
+ data.capacity(),
+ out,
+ Audio.FRAME_SIZE);
} else if(mCodec == JumbleUDPMessageType.UDPVoiceOpus) {
decodedSamples = Opus.opus_decode_float(mOpusDecoder,
data,
@@ -275,11 +272,11 @@ public class AudioOutputSpeech {
if(mFrames.isEmpty() && mHasTerminator)
nextAlive = false;
} else {
-// if(mCodec == JumbleUDPMessageType.UDPVoiceCELTAlpha)
-// CELT7.celt_decode_float(mCELTAlphaDecoder, null, 0, out);
-// else if(mCodec == JumbleUDPMessageType.UDPVoiceCELTBeta)
-// CELT11.celt_decode_float(mCELTBetaDecoder, null, 0, out, Audio.FRAME_SIZE);
- /*else*/ if(mCodec == JumbleUDPMessageType.UDPVoiceOpus)
+ if(mCodec == JumbleUDPMessageType.UDPVoiceCELTAlpha)
+ CELT7.celt_decode_float(mCELTAlphaDecoder, null, 0, out);
+ else if(mCodec == JumbleUDPMessageType.UDPVoiceCELTBeta)
+ CELT11.celt_decode_float(mCELTBetaDecoder, null, 0, out, Audio.FRAME_SIZE);
+ else if(mCodec == JumbleUDPMessageType.UDPVoiceOpus)
decodedSamples = Opus.opus_decode_float(mOpusDecoder, null, 0, out, Audio.FRAME_SIZE, 0);
// else {
// Speex.speex_decode(mSpeexDecoder, null, out);
@@ -329,9 +326,8 @@ public class AudioOutputSpeech {
if(newSize > mBuffer.length) {
float[] n = new float[newSize];
if(mBuffer != null)
- System.arraycopy(mBuffer, 0, n, 0, mAudioBufferSize);
+ System.arraycopy(mBuffer, 0, n, 0, mBuffer.length);
mBuffer = n;
- mAudioBufferSize = newSize;
}
}
@@ -354,18 +350,16 @@ public class AudioOutputSpeech {
public void destroy() {
if(mOpusDecoder != null)
Opus.opus_decoder_destroy(mOpusDecoder);
-// if(mCELTBetaDecoder != null)
-// CELT11.celt_decoder_destroy(mCELTBetaDecoder);
-// if(mCELTAlphaMode != null)
-// CELT7.celt_mode_destroy(mCELTAlphaMode);
-// if(mCELTAlphaDecoder != null)
-// CELT7.celt_decoder_destroy(mCELTAlphaDecoder);
+ if(mCELTBetaDecoder != null)
+ CELT11.celt_decoder_destroy(mCELTBetaDecoder);
+ if(mCELTAlphaMode != null)
+ CELT7.celt_mode_destroy(mCELTAlphaMode);
+ if(mCELTAlphaDecoder != null)
+ CELT7.celt_decoder_destroy(mCELTAlphaDecoder);
// if(mSpeexBits != null)
// Speex.speex_bits_destroy(mSpeexBits);
// if(mSpeexDecoder != null)
// Speex.speex_decoder_destroy(mSpeexDecoder);
-// if(mJitterBuffer != null)
-// Speex.jitter_buffer_destroy(mJitterBuffer);
mJitterBuffer.destroy();
}
}
diff --git a/src/main/java/com/morlunk/jumble/audio/javacpp/CELT11.java b/src/main/java/com/morlunk/jumble/audio/javacpp/CELT11.java
index bab4cee..c5753ed 100644
--- a/src/main/java/com/morlunk/jumble/audio/javacpp/CELT11.java
+++ b/src/main/java/com/morlunk/jumble/audio/javacpp/CELT11.java
@@ -16,8 +16,14 @@
package com.morlunk.jumble.audio.javacpp;
+import com.googlecode.javacpp.BytePointer;
+import com.googlecode.javacpp.FloatPointer;
import com.googlecode.javacpp.IntPointer;
+import com.googlecode.javacpp.Loader;
import com.googlecode.javacpp.Pointer;
+import com.googlecode.javacpp.ShortPointer;
+import com.googlecode.javacpp.annotation.Cast;
+import com.googlecode.javacpp.annotation.NoDeallocator;
import com.googlecode.javacpp.annotation.Platform;
/**
@@ -26,21 +32,19 @@ import com.googlecode.javacpp.annotation.Platform;
@Platform(library="celt11", cinclude={"<celt.h>","<celt_types.h>"})
public class CELT11 {
- public static class Decoder {
+ public static final int CELT_GET_BITSTREAM_VERSION = 2000;
- private Pointer mNativeDecoder;
- private int mError;
-
- public Decoder(int sampleRate, int channels) {
- IntPointer error = new IntPointer(1);
- mNativeDecoder = celt_decoder_init(sampleRate, channels, error);
- mError = error.get();
- }
-
- public int getError() {
- return mError;
- }
+ static {
+ Loader.load();
}
- private static native Pointer celt_decoder_init(int sampleRate, int channels, IntPointer error);
-}
+ public static native @NoDeallocator Pointer celt_mode_create(int sampleRate, int frameSize, IntPointer error);
+ public static native int celt_mode_info(@Cast("const CELTMode*") Pointer mode, int request, IntPointer value);
+ public static native void celt_mode_destroy(@Cast("CELTMode*") Pointer mode);
+
+ public static native @NoDeallocator Pointer celt_decoder_create(int sampleRate, int channels, IntPointer error);
+ public static native int celt_decode(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") BytePointer data, int len, ShortPointer pcm, int frameSize);
+ public static native int celt_decode_float(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") BytePointer data, int len, FloatPointer pcm, int frameSize);
+ public static native int celt_decoder_ctl(@Cast("CELTDecoder*") Pointer st, int request, Pointer val);
+ public static native void celt_decoder_destroy(@Cast("CELTDecoder*") Pointer st);
+} \ No newline at end of file
diff --git a/src/main/java/com/morlunk/jumble/audio/javacpp/CELT7.java b/src/main/java/com/morlunk/jumble/audio/javacpp/CELT7.java
index 7032cf8..383e4df 100644
--- a/src/main/java/com/morlunk/jumble/audio/javacpp/CELT7.java
+++ b/src/main/java/com/morlunk/jumble/audio/javacpp/CELT7.java
@@ -16,8 +16,35 @@
package com.morlunk.jumble.audio.javacpp;
+import com.googlecode.javacpp.BytePointer;
+import com.googlecode.javacpp.FloatPointer;
+import com.googlecode.javacpp.IntPointer;
+import com.googlecode.javacpp.Loader;
+import com.googlecode.javacpp.Pointer;
+import com.googlecode.javacpp.ShortPointer;
+import com.googlecode.javacpp.annotation.Cast;
+import com.googlecode.javacpp.annotation.NoDeallocator;
+import com.googlecode.javacpp.annotation.Platform;
+
/**
* Created by andrew on 20/10/13.
*/
+@Platform(library="celt7", cinclude={"<celt.h>","<celt_types.h>"})
public class CELT7 {
+
+ public static final int CELT_GET_BITSTREAM_VERSION = 2000;
+
+ static {
+ Loader.load();
+ }
+
+ public static native @NoDeallocator Pointer celt_mode_create(int sampleRate, int frameSize, IntPointer error);
+ public static native int celt_mode_info(@Cast("const CELTMode*") Pointer mode, int request, IntPointer value);
+ public static native void celt_mode_destroy(@Cast("CELTMode*") Pointer mode);
+
+ public static native @NoDeallocator Pointer celt_decoder_create(@Cast("CELTMode*") Pointer mode, int channels, IntPointer error);
+ public static native int celt_decode(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") BytePointer data, int len, ShortPointer pcm);
+ public static native int celt_decode_float(@Cast("CELTDecoder*") Pointer st, @Cast("const unsigned char*") BytePointer data, int len, FloatPointer pcm);
+ public static native int celt_decoder_ctl(@Cast("CELTDecoder*") Pointer st, int request, Pointer val);
+ public static native void celt_decoder_destroy(@Cast("CELTDecoder*") Pointer st);
}
diff --git a/src/main/java/com/morlunk/jumble/audio/javacpp/Opus.java b/src/main/java/com/morlunk/jumble/audio/javacpp/Opus.java
index b71bddd..72d284e 100644
--- a/src/main/java/com/morlunk/jumble/audio/javacpp/Opus.java
+++ b/src/main/java/com/morlunk/jumble/audio/javacpp/Opus.java
@@ -43,16 +43,6 @@ public class Opus {
Loader.load();
}
-// TODO work on an oo decoder wrapper
-// public static class Decoder {
-// private Pointer mNativeDecoder;
-//
-// public Decoder(int frameSize, int channels) {
-// IntPointer error = new IntPointer(1);
-// mNativeDecoder = opus_decoder_create(frameSize, channels, error);
-// }
-// }
-
public static native int opus_decoder_get_size(int channels);
public static native @NoDeallocator Pointer opus_decoder_create(int fs, int channels, IntPointer error);
public static native int opus_decoder_init(@Cast("OpusDecoder*") Pointer st, int fs, int channels);
diff --git a/src/main/java/com/morlunk/jumble/audio/javacpp/Speex.java b/src/main/java/com/morlunk/jumble/audio/javacpp/Speex.java
index 05936f2..3ba0018 100644
--- a/src/main/java/com/morlunk/jumble/audio/javacpp/Speex.java
+++ b/src/main/java/com/morlunk/jumble/audio/javacpp/Speex.java
@@ -32,7 +32,7 @@ import com.googlecode.javacpp.annotation.Platform;
* JavaCPP interface for Speex JNI.
* Created by andrew on 18/10/13.
*/
-@Platform(library="speex", link="speex", cinclude={"<speex/speex.h>","<speex/speex_types.h>","<speex/speex_jitter.h>", "<speex/speex_preprocess.h>"})
+@Platform(library="speex", link="speex", cinclude={"<speex/speex.h>","<speex/speex_types.h>","<speex/speex_jitter.h>", "<speex/speex_preprocess.h>", "<speex/speex_resampler.h>"})
public class Speex {
static {
@@ -125,7 +125,7 @@ public class Speex {
}
- public static class SpeexPreprocessState extends Pointer {
+ public static class SpeexPreprocessState {
public static final int SPEEX_PREPROCESS_SET_DENOISE = 0;
public static final int SPEEX_PREPROCESS_GET_DENOISE = 1;
@@ -189,6 +189,28 @@ public class Speex {
}
+ public static class SpeexResampler {
+ private Pointer mNativeState;
+
+ public SpeexResampler(int channels, int inSampleRate, int outSampleRate, int quality) {
+ mNativeState = speex_resampler_init(channels, inSampleRate, outSampleRate, quality, null);
+ }
+
+ public void resample(short[] in, short[] out) {
+ speex_resampler_process_int(mNativeState, 0, in, new int[] { in.length }, out, new int[] { out.length });
+ }
+
+ public void destroy() {
+ speex_resampler_destroy(mNativeState);
+ }
+
+ }
+
+ // Resampler
+ private static native Pointer speex_resampler_init(int channels, int inSampleRate, int outSampleRate, int quality, IntPointer error);
+ private static native int speex_resampler_process_int(@Cast("SpeexResamplerState*") Pointer state, int channelIndex, @Cast("short*") short[] in, @Cast("unsigned int*") int[] inLen, @Cast("short*") short[] out, @Cast("unsigned int*") int[] outLen);
+ private static native void speex_resampler_destroy(@Cast("SpeexResamplerState*") Pointer state);
+
// Jitter buffer
private static native Pointer jitter_buffer_init(int tick);
private static native void jitter_buffer_reset(@Cast("JitterBuffer*") Pointer jitterBuffer);