From c9014da186ca32f9cc6cccba72b73a3f0455e87b Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 17 Oct 2015 17:16:58 -0700 Subject: [PATCH] Transition to Opus Multistream Decoder API --- .../binding/audio/AndroidAudioRenderer.java | 17 +++++--- app/src/main/jni/nv_opus_dec/nv_opus_dec.c | 42 +++++++------------ app/src/main/jni/nv_opus_dec/nv_opus_dec.h | 8 ++-- .../main/jni/nv_opus_dec/nv_opus_dec_jni.c | 39 +++++++---------- 4 files changed, 45 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java b/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java index 9f849a9e..3b5621e2 100644 --- a/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java +++ b/app/src/main/java/com/limelight/binding/audio/AndroidAudioRenderer.java @@ -9,14 +9,13 @@ import com.limelight.nvstream.av.audio.AudioRenderer; public class AndroidAudioRenderer implements AudioRenderer { - private static final int FRAME_SIZE = 960; - private AudioTrack track; @Override - public boolean streamInitialized(int channelCount, int sampleRate) { + public boolean streamInitialized(int channelCount, int channelMask, int samplesPerFrame, int sampleRate) { int channelConfig; int bufferSize; + int bytesPerFrame = (samplesPerFrame * 2); switch (channelCount) { @@ -26,6 +25,12 @@ public class AndroidAudioRenderer implements AudioRenderer { case 2: channelConfig = AudioFormat.CHANNEL_OUT_STEREO; break; + case 4: + channelConfig = AudioFormat.CHANNEL_OUT_QUAD; + break; + case 6: + channelConfig = AudioFormat.CHANNEL_OUT_5POINT1; + break; default: LimeLog.severe("Decoder returned unhandled channel count"); return false; @@ -38,7 +43,7 @@ public class AndroidAudioRenderer implements AudioRenderer { // use the recommended larger buffer size. try { // Buffer two frames of audio if possible - bufferSize = FRAME_SIZE * 2; + bufferSize = bytesPerFrame * 2; track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, @@ -59,10 +64,10 @@ public class AndroidAudioRenderer implements AudioRenderer { bufferSize = Math.max(AudioTrack.getMinBufferSize(sampleRate, channelConfig, AudioFormat.ENCODING_PCM_16BIT), - FRAME_SIZE * 2); + bytesPerFrame * 2); // Round to next frame - bufferSize = (((bufferSize + (FRAME_SIZE - 1)) / FRAME_SIZE) * FRAME_SIZE); + bufferSize = (((bufferSize + (bytesPerFrame - 1)) / bytesPerFrame) * bytesPerFrame); track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, diff --git a/app/src/main/jni/nv_opus_dec/nv_opus_dec.c b/app/src/main/jni/nv_opus_dec/nv_opus_dec.c index 597b3b25..084f0022 100644 --- a/app/src/main/jni/nv_opus_dec/nv_opus_dec.c +++ b/app/src/main/jni/nv_opus_dec/nv_opus_dec.c @@ -1,17 +1,21 @@ #include -#include +#include #include "nv_opus_dec.h" -OpusDecoder* decoder; +OpusMSDecoder* decoder; // This function must be called before // any other decoding functions -int nv_opus_init(void) { +int nv_opus_init(int sampleRate, int channelCount, int streams, + int coupledStreams, const unsigned char *mapping) { int err; - decoder = opus_decoder_create( - nv_opus_get_sample_rate(), - nv_opus_get_channel_count(), - &err); + decoder = opus_multistream_decoder_create( + sampleRate, + channelCount, + streams, + coupledStreams, + mapping, + &err); return err; } @@ -19,36 +23,20 @@ int nv_opus_init(void) { // decoding is finished void nv_opus_destroy(void) { if (decoder != NULL) { - opus_decoder_destroy(decoder); + opus_multistream_decoder_destroy(decoder); } } -// The Opus stream is stereo -int nv_opus_get_channel_count(void) { - return 2; -} - -// This number assumes 16-bit samples at 48 KHz with 2.5 ms frames -int nv_opus_get_max_out_shorts(void) { - return 240*nv_opus_get_channel_count(); -} - -// The Opus stream is 48 KHz -int nv_opus_get_sample_rate(void) { - return 48000; -} - -// outpcmdata must be 5760*2 shorts in length // packets must be decoded in order // a packet loss must call this function with NULL indata and 0 inlen // returns the number of decoded samples -int nv_opus_decode(unsigned char* indata, int inlen, short* outpcmdata) { +int nv_opus_decode(unsigned char* indata, int inlen, short* outpcmdata, int framesize) { int err; // Decoding to 16-bit PCM with FEC off // Maximum length assuming 48KHz sample rate - err = opus_decode(decoder, indata, inlen, - outpcmdata, 512, 0); + err = opus_multistream_decode(decoder, indata, inlen, + outpcmdata, framesize, 0); return err; } diff --git a/app/src/main/jni/nv_opus_dec/nv_opus_dec.h b/app/src/main/jni/nv_opus_dec/nv_opus_dec.h index c5eb7f55..2ccb31c6 100644 --- a/app/src/main/jni/nv_opus_dec/nv_opus_dec.h +++ b/app/src/main/jni/nv_opus_dec/nv_opus_dec.h @@ -1,6 +1,4 @@ -int nv_opus_init(void); +int nv_opus_init(int sampleRate, int channelCount, int streams, + int coupledStreams, const unsigned char *mapping); void nv_opus_destroy(void); -int nv_opus_get_channel_count(void); -int nv_opus_get_max_out_shorts(void); -int nv_opus_get_sample_rate(void); -int nv_opus_decode(unsigned char* indata, int inlen, short* outpcmdata); +int nv_opus_decode(unsigned char* indata, int inlen, short* outpcmdata, int framesize); diff --git a/app/src/main/jni/nv_opus_dec/nv_opus_dec_jni.c b/app/src/main/jni/nv_opus_dec/nv_opus_dec_jni.c index 01d22791..4c44155c 100644 --- a/app/src/main/jni/nv_opus_dec/nv_opus_dec_jni.c +++ b/app/src/main/jni/nv_opus_dec/nv_opus_dec_jni.c @@ -6,8 +6,19 @@ // This function must be called before // any other decoding functions JNIEXPORT jint JNICALL -Java_com_limelight_nvstream_av_audio_OpusDecoder_init(JNIEnv *env, jobject this) { - return nv_opus_init(); +Java_com_limelight_nvstream_av_audio_OpusDecoder_init(JNIEnv *env, jobject this, + int sampleRate, int channelCount, int streams, + int coupledStreams, jbyteArray mapping) { + jbyte* jni_mapping_data; + jint ret; + + jni_mapping_data = (*env)->GetByteArrayElements(env, mapping, 0); + + ret = nv_opus_init(sampleRate, channelCount, streams, coupledStreams, jni_mapping_data); + + (*env)->ReleaseByteArrayElements(env, mapping, jni_mapping_data, JNI_ABORT); + + return ret; } // This function must be called after @@ -17,25 +28,6 @@ Java_com_limelight_nvstream_av_audio_OpusDecoder_destroy(JNIEnv *env, jobject th nv_opus_destroy(); } -// The Opus stream is stereo -JNIEXPORT jint JNICALL -Java_com_limelight_nvstream_av_audio_OpusDecoder_getChannelCount(JNIEnv *env, jobject this) { - return nv_opus_get_channel_count(); -} - -// This number assumes 2 channels at 48 KHz -JNIEXPORT jint JNICALL -Java_com_limelight_nvstream_av_audio_OpusDecoder_getMaxOutputShorts(JNIEnv *env, jobject this) { - return nv_opus_get_max_out_shorts(); -} - -// The Opus stream is 48 KHz -JNIEXPORT jint JNICALL -Java_com_limelight_nvstream_av_audio_OpusDecoder_getSampleRate(JNIEnv *env, jobject this) { - return nv_opus_get_sample_rate(); -} - -// outpcmdata must be 5760*2 shorts in length // packets must be decoded in order // a packet loss must call this function with NULL indata and 0 inlen // returns the number of decoded samples @@ -53,13 +45,14 @@ Java_com_limelight_nvstream_av_audio_OpusDecoder_decode( if (indata != NULL) { jni_input_data = (*env)->GetByteArrayElements(env, indata, 0); - ret = nv_opus_decode(&jni_input_data[inoff], inlen, (jshort*)jni_pcm_data); + ret = nv_opus_decode(&jni_input_data[inoff], inlen, (jshort*)jni_pcm_data, + (*env)->GetArrayLength(env, outpcmdata)/2); // The input data isn't changed so it can be safely aborted (*env)->ReleaseByteArrayElements(env, indata, jni_input_data, JNI_ABORT); } else { - ret = nv_opus_decode(NULL, 0, (jshort*)jni_pcm_data); + ret = nv_opus_decode(NULL, 0, (jshort*)jni_pcm_data, (*env)->GetArrayLength(env, outpcmdata)/2); } (*env)->ReleaseByteArrayElements(env, outpcmdata, jni_pcm_data, 0);