mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-20 11:33:06 +00:00
Transition to Opus Multistream Decoder API
This commit is contained in:
parent
c025f9f02b
commit
c9014da186
@ -9,14 +9,13 @@ import com.limelight.nvstream.av.audio.AudioRenderer;
|
|||||||
|
|
||||||
public class AndroidAudioRenderer implements AudioRenderer {
|
public class AndroidAudioRenderer implements AudioRenderer {
|
||||||
|
|
||||||
private static final int FRAME_SIZE = 960;
|
|
||||||
|
|
||||||
private AudioTrack track;
|
private AudioTrack track;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean streamInitialized(int channelCount, int sampleRate) {
|
public boolean streamInitialized(int channelCount, int channelMask, int samplesPerFrame, int sampleRate) {
|
||||||
int channelConfig;
|
int channelConfig;
|
||||||
int bufferSize;
|
int bufferSize;
|
||||||
|
int bytesPerFrame = (samplesPerFrame * 2);
|
||||||
|
|
||||||
switch (channelCount)
|
switch (channelCount)
|
||||||
{
|
{
|
||||||
@ -26,6 +25,12 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
case 2:
|
case 2:
|
||||||
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
|
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
channelConfig = AudioFormat.CHANNEL_OUT_QUAD;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LimeLog.severe("Decoder returned unhandled channel count");
|
LimeLog.severe("Decoder returned unhandled channel count");
|
||||||
return false;
|
return false;
|
||||||
@ -38,7 +43,7 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
// use the recommended larger buffer size.
|
// use the recommended larger buffer size.
|
||||||
try {
|
try {
|
||||||
// Buffer two frames of audio if possible
|
// Buffer two frames of audio if possible
|
||||||
bufferSize = FRAME_SIZE * 2;
|
bufferSize = bytesPerFrame * 2;
|
||||||
|
|
||||||
track = new AudioTrack(AudioManager.STREAM_MUSIC,
|
track = new AudioTrack(AudioManager.STREAM_MUSIC,
|
||||||
sampleRate,
|
sampleRate,
|
||||||
@ -59,10 +64,10 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
|||||||
bufferSize = Math.max(AudioTrack.getMinBufferSize(sampleRate,
|
bufferSize = Math.max(AudioTrack.getMinBufferSize(sampleRate,
|
||||||
channelConfig,
|
channelConfig,
|
||||||
AudioFormat.ENCODING_PCM_16BIT),
|
AudioFormat.ENCODING_PCM_16BIT),
|
||||||
FRAME_SIZE * 2);
|
bytesPerFrame * 2);
|
||||||
|
|
||||||
// Round to next frame
|
// 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,
|
track = new AudioTrack(AudioManager.STREAM_MUSIC,
|
||||||
sampleRate,
|
sampleRate,
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <opus.h>
|
#include <opus_multistream.h>
|
||||||
#include "nv_opus_dec.h"
|
#include "nv_opus_dec.h"
|
||||||
|
|
||||||
OpusDecoder* decoder;
|
OpusMSDecoder* decoder;
|
||||||
|
|
||||||
// This function must be called before
|
// This function must be called before
|
||||||
// any other decoding functions
|
// 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;
|
int err;
|
||||||
decoder = opus_decoder_create(
|
decoder = opus_multistream_decoder_create(
|
||||||
nv_opus_get_sample_rate(),
|
sampleRate,
|
||||||
nv_opus_get_channel_count(),
|
channelCount,
|
||||||
&err);
|
streams,
|
||||||
|
coupledStreams,
|
||||||
|
mapping,
|
||||||
|
&err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,36 +23,20 @@ int nv_opus_init(void) {
|
|||||||
// decoding is finished
|
// decoding is finished
|
||||||
void nv_opus_destroy(void) {
|
void nv_opus_destroy(void) {
|
||||||
if (decoder != NULL) {
|
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
|
// packets must be decoded in order
|
||||||
// a packet loss must call this function with NULL indata and 0 inlen
|
// a packet loss must call this function with NULL indata and 0 inlen
|
||||||
// returns the number of decoded samples
|
// 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;
|
int err;
|
||||||
|
|
||||||
// Decoding to 16-bit PCM with FEC off
|
// Decoding to 16-bit PCM with FEC off
|
||||||
// Maximum length assuming 48KHz sample rate
|
// Maximum length assuming 48KHz sample rate
|
||||||
err = opus_decode(decoder, indata, inlen,
|
err = opus_multistream_decode(decoder, indata, inlen,
|
||||||
outpcmdata, 512, 0);
|
outpcmdata, framesize, 0);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
void nv_opus_destroy(void);
|
||||||
int nv_opus_get_channel_count(void);
|
int nv_opus_decode(unsigned char* indata, int inlen, short* outpcmdata, int framesize);
|
||||||
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);
|
|
||||||
|
@ -6,8 +6,19 @@
|
|||||||
// This function must be called before
|
// This function must be called before
|
||||||
// any other decoding functions
|
// any other decoding functions
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_com_limelight_nvstream_av_audio_OpusDecoder_init(JNIEnv *env, jobject this) {
|
Java_com_limelight_nvstream_av_audio_OpusDecoder_init(JNIEnv *env, jobject this,
|
||||||
return nv_opus_init();
|
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
|
// 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();
|
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
|
// packets must be decoded in order
|
||||||
// a packet loss must call this function with NULL indata and 0 inlen
|
// a packet loss must call this function with NULL indata and 0 inlen
|
||||||
// returns the number of decoded samples
|
// returns the number of decoded samples
|
||||||
@ -53,13 +45,14 @@ Java_com_limelight_nvstream_av_audio_OpusDecoder_decode(
|
|||||||
if (indata != NULL) {
|
if (indata != NULL) {
|
||||||
jni_input_data = (*env)->GetByteArrayElements(env, indata, 0);
|
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
|
// The input data isn't changed so it can be safely aborted
|
||||||
(*env)->ReleaseByteArrayElements(env, indata, jni_input_data, JNI_ABORT);
|
(*env)->ReleaseByteArrayElements(env, indata, jni_input_data, JNI_ABORT);
|
||||||
}
|
}
|
||||||
else {
|
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);
|
(*env)->ReleaseByteArrayElements(env, outpcmdata, jni_pcm_data, 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user