1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <jni.h>
18 
19 #include <android/log.h>
20 
21 #include <cstdlib>
22 
23 #include "opus.h"  // NOLINT
24 #include "opus_multistream.h"  // NOLINT
25 
26 #define LOG_TAG "opus_jni"
27 #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
28                                              __VA_ARGS__))
29 
30 #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
31   extern "C" { \
32   JNIEXPORT RETURN_TYPE \
33     Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_ ## NAME \
34       (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
35   } \
36   JNIEXPORT RETURN_TYPE \
37     Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_ ## NAME \
38       (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
39 
40 #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
41   extern "C" { \
42   JNIEXPORT RETURN_TYPE \
43     Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_ ## NAME \
44       (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
45   } \
46   JNIEXPORT RETURN_TYPE \
47     Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_ ## NAME \
48       (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
49 
50 // JNI references for SimpleOutputBuffer class.
51 static jmethodID outputBufferInit;
52 
JNI_OnLoad(JavaVM * vm,void * reserved)53 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
54   JNIEnv* env;
55   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
56     return -1;
57   }
58   return JNI_VERSION_1_6;
59 }
60 
61 static const int kBytesPerSample = 2;  // opus fixed point uses 16 bit samples.
62 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
63 static int channelCount;
64 static int errorCode;
65 
DECODER_FUNC(jlong,opusInit,jint sampleRate,jint channelCount,jint numStreams,jint numCoupled,jint gain,jbyteArray jStreamMap)66 DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
67      jint numStreams, jint numCoupled, jint gain, jbyteArray jStreamMap) {
68   int status = OPUS_INVALID_STATE;
69   ::channelCount = channelCount;
70   errorCode = 0;
71   jbyte* streamMapBytes = env->GetByteArrayElements(jStreamMap, 0);
72   uint8_t* streamMap = reinterpret_cast<uint8_t*>(streamMapBytes);
73   OpusMSDecoder* decoder = opus_multistream_decoder_create(
74       sampleRate, channelCount, numStreams, numCoupled, streamMap, &status);
75   env->ReleaseByteArrayElements(jStreamMap, streamMapBytes, 0);
76   if (!decoder || status != OPUS_OK) {
77     LOGE("Failed to create Opus Decoder; status=%s", opus_strerror(status));
78     return 0;
79   }
80   status = opus_multistream_decoder_ctl(decoder, OPUS_SET_GAIN(gain));
81   if (status != OPUS_OK) {
82     LOGE("Failed to set Opus header gain; status=%s", opus_strerror(status));
83     return 0;
84   }
85 
86   // Populate JNI References.
87   const jclass outputBufferClass = env->FindClass(
88       "com/google/android/exoplayer2/decoder/SimpleOutputBuffer");
89   outputBufferInit = env->GetMethodID(outputBufferClass, "init",
90       "(JI)Ljava/nio/ByteBuffer;");
91 
92   return reinterpret_cast<intptr_t>(decoder);
93 }
94 
DECODER_FUNC(jint,opusDecode,jlong jDecoder,jlong jTimeUs,jobject jInputBuffer,jint inputSize,jobject jOutputBuffer)95 DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
96      jobject jInputBuffer, jint inputSize, jobject jOutputBuffer) {
97   OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
98   const uint8_t* inputBuffer =
99       reinterpret_cast<const uint8_t*>(
100           env->GetDirectBufferAddress(jInputBuffer));
101 
102   const jint outputSize =
103       kMaxOpusOutputPacketSizeSamples * kBytesPerSample * channelCount;
104 
105   env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
106   if (env->ExceptionCheck()) {
107     // Exception is thrown in Java when returning from the native call.
108     return -1;
109   }
110   const jobject jOutputBufferData = env->CallObjectMethod(jOutputBuffer,
111       outputBufferInit, jTimeUs, outputSize);
112   if (env->ExceptionCheck()) {
113     // Exception is thrown in Java when returning from the native call.
114     return -1;
115   }
116 
117   int16_t* outputBufferData = reinterpret_cast<int16_t*>(
118       env->GetDirectBufferAddress(jOutputBufferData));
119   int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize,
120       outputBufferData, kMaxOpusOutputPacketSizeSamples, 0);
121   // record error code
122   errorCode = (sampleCount < 0) ? sampleCount : 0;
123   return (sampleCount < 0) ? sampleCount
124       : sampleCount * kBytesPerSample * channelCount;
125 }
126 
DECODER_FUNC(jint,opusSecureDecode,jlong jDecoder,jlong jTimeUs,jobject jInputBuffer,jint inputSize,jobject jOutputBuffer,jint sampleRate,jobject mediaCrypto,jint inputMode,jbyteArray key,jbyteArray javaIv,jint inputNumSubSamples,jintArray numBytesOfClearData,jintArray numBytesOfEncryptedData)127 DECODER_FUNC(jint, opusSecureDecode, jlong jDecoder, jlong jTimeUs,
128      jobject jInputBuffer, jint inputSize, jobject jOutputBuffer,
129      jint sampleRate, jobject mediaCrypto, jint inputMode, jbyteArray key,
130      jbyteArray javaIv, jint inputNumSubSamples, jintArray numBytesOfClearData,
131      jintArray numBytesOfEncryptedData) {
132   // Doesn't support
133   // Java client should have checked vpxSupportSecureDecode
134   // and avoid calling this
135   // return -2 (DRM Error)
136   return -2;
137 }
138 
DECODER_FUNC(void,opusClose,jlong jDecoder)139 DECODER_FUNC(void, opusClose, jlong jDecoder) {
140   OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
141   opus_multistream_decoder_destroy(decoder);
142 }
143 
DECODER_FUNC(void,opusReset,jlong jDecoder)144 DECODER_FUNC(void, opusReset, jlong jDecoder) {
145   OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
146   opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE);
147 }
148 
DECODER_FUNC(jstring,opusGetErrorMessage,jlong jContext)149 DECODER_FUNC(jstring, opusGetErrorMessage, jlong jContext) {
150   return env->NewStringUTF(opus_strerror(errorCode));
151 }
152 
DECODER_FUNC(jint,opusGetErrorCode,jlong jContext)153 DECODER_FUNC(jint, opusGetErrorCode, jlong jContext) {
154   return errorCode;
155 }
156 
LIBRARY_FUNC(jstring,opusIsSecureDecodeSupported)157 LIBRARY_FUNC(jstring, opusIsSecureDecodeSupported) {
158   // Doesn't support
159   return 0;
160 }
161 
LIBRARY_FUNC(jstring,opusGetVersion)162 LIBRARY_FUNC(jstring, opusGetVersion) {
163   return env->NewStringUTF(opus_get_version_string());
164 }
165