• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef __ANDROID__
18 #include <android/log.h>
19 #endif
20 #include <jni.h>
21 
22 #include <cstdint>
23 #include <cstdlib>
24 
25 #include "opus.h"              // NOLINT
26 #include "opus_multistream.h"  // NOLINT
27 
28 #ifdef __ANDROID__
29 #define LOG_TAG "opus_jni"
30 #define LOGE(...) \
31   ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
32 #else  //  __ANDROID__
33 #define LOGE(...) \
34   do {            \
35   } while (0)
36 #endif  //  __ANDROID__
37 
38 #define DECODER_FUNC(RETURN_TYPE, NAME, ...)                          \
39   extern "C" {                                                        \
40   JNIEXPORT RETURN_TYPE                                               \
41       Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_##NAME( \
42           JNIEnv* env, jobject thiz, ##__VA_ARGS__);                  \
43   }                                                                   \
44   JNIEXPORT RETURN_TYPE                                               \
45       Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_##NAME( \
46           JNIEnv* env, jobject thiz, ##__VA_ARGS__)
47 
48 #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...)                          \
49   extern "C" {                                                        \
50   JNIEXPORT RETURN_TYPE                                               \
51       Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_##NAME( \
52           JNIEnv* env, jobject thiz, ##__VA_ARGS__);                  \
53   }                                                                   \
54   JNIEXPORT RETURN_TYPE                                               \
55       Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_##NAME( \
56           JNIEnv* env, jobject thiz, ##__VA_ARGS__)
57 
58 // JNI references for SimpleOutputBuffer class.
59 static jmethodID outputBufferInit;
60 
JNI_OnLoad(JavaVM * vm,void * reserved)61 jint JNI_OnLoad(JavaVM* vm, void* reserved) {
62   JNIEnv* env;
63   if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
64     return -1;
65   }
66   return JNI_VERSION_1_6;
67 }
68 
69 static const int kBytesPerIntPcmSample = 2;
70 static const int kBytesPerFloatSample = 4;
71 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
72 static int channelCount;
73 static int errorCode;
74 static bool outputFloat = false;
75 
DECODER_FUNC(jlong,opusInit,jint sampleRate,jint channelCount,jint numStreams,jint numCoupled,jint gain,jbyteArray jStreamMap)76 DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
77              jint numStreams, jint numCoupled, jint gain,
78              jbyteArray jStreamMap) {
79   int status = OPUS_INVALID_STATE;
80   ::channelCount = channelCount;
81   errorCode = 0;
82   jbyte* streamMapBytes = env->GetByteArrayElements(jStreamMap, 0);
83   uint8_t* streamMap = reinterpret_cast<uint8_t*>(streamMapBytes);
84   OpusMSDecoder* decoder = opus_multistream_decoder_create(
85       sampleRate, channelCount, numStreams, numCoupled, streamMap, &status);
86   env->ReleaseByteArrayElements(jStreamMap, streamMapBytes, 0);
87   if (!decoder || status != OPUS_OK) {
88     LOGE("Failed to create Opus Decoder; status=%s", opus_strerror(status));
89     return 0;
90   }
91   status = opus_multistream_decoder_ctl(decoder, OPUS_SET_GAIN(gain));
92   if (status != OPUS_OK) {
93     LOGE("Failed to set Opus header gain; status=%s", opus_strerror(status));
94     return 0;
95   }
96 
97   // Populate JNI References.
98   const jclass outputBufferClass = env->FindClass(
99       "com/google/android/exoplayer2/decoder/SimpleDecoderOutputBuffer");
100   outputBufferInit =
101       env->GetMethodID(outputBufferClass, "init", "(JI)Ljava/nio/ByteBuffer;");
102 
103   return reinterpret_cast<intptr_t>(decoder);
104 }
105 
DECODER_FUNC(jint,opusDecode,jlong jDecoder,jlong jTimeUs,jobject jInputBuffer,jint inputSize,jobject jOutputBuffer)106 DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
107              jobject jInputBuffer, jint inputSize, jobject jOutputBuffer) {
108   OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
109   const uint8_t* inputBuffer = reinterpret_cast<const uint8_t*>(
110       env->GetDirectBufferAddress(jInputBuffer));
111 
112   const int byteSizePerSample =
113       outputFloat ? kBytesPerFloatSample : kBytesPerIntPcmSample;
114   const jint outputSize =
115       kMaxOpusOutputPacketSizeSamples * byteSizePerSample * channelCount;
116 
117   env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
118   if (env->ExceptionCheck()) {
119     // Exception is thrown in Java when returning from the native call.
120     return -1;
121   }
122   const jobject jOutputBufferData = env->CallObjectMethod(
123       jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
124   if (env->ExceptionCheck()) {
125     // Exception is thrown in Java when returning from the native call.
126     return -1;
127   }
128 
129   int sampleCount;
130   if (outputFloat) {
131     float* outputBufferData = reinterpret_cast<float*>(
132         env->GetDirectBufferAddress(jOutputBufferData));
133     sampleCount = opus_multistream_decode_float(
134         decoder, inputBuffer, inputSize, outputBufferData,
135         kMaxOpusOutputPacketSizeSamples, 0);
136   } else {
137     int16_t* outputBufferData = reinterpret_cast<int16_t*>(
138         env->GetDirectBufferAddress(jOutputBufferData));
139     sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize,
140                                           outputBufferData,
141                                           kMaxOpusOutputPacketSizeSamples, 0);
142   }
143 
144   // record error code
145   errorCode = (sampleCount < 0) ? sampleCount : 0;
146   return (sampleCount < 0) ? sampleCount
147                            : sampleCount * byteSizePerSample * channelCount;
148 }
149 
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)150 DECODER_FUNC(jint, opusSecureDecode, jlong jDecoder, jlong jTimeUs,
151              jobject jInputBuffer, jint inputSize, jobject jOutputBuffer,
152              jint sampleRate, jobject mediaCrypto, jint inputMode,
153              jbyteArray key, jbyteArray javaIv, jint inputNumSubSamples,
154              jintArray numBytesOfClearData, jintArray numBytesOfEncryptedData) {
155   // Doesn't support
156   // Java client should have checked vpxSupportSecureDecode
157   // and avoid calling this
158   // return -2 (DRM Error)
159   return -2;
160 }
161 
DECODER_FUNC(void,opusClose,jlong jDecoder)162 DECODER_FUNC(void, opusClose, jlong jDecoder) {
163   OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
164   opus_multistream_decoder_destroy(decoder);
165 }
166 
DECODER_FUNC(void,opusReset,jlong jDecoder)167 DECODER_FUNC(void, opusReset, jlong jDecoder) {
168   OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
169   opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE);
170 }
171 
DECODER_FUNC(jstring,opusGetErrorMessage,jlong jContext)172 DECODER_FUNC(jstring, opusGetErrorMessage, jlong jContext) {
173   return env->NewStringUTF(opus_strerror(errorCode));
174 }
175 
DECODER_FUNC(jint,opusGetErrorCode,jlong jContext)176 DECODER_FUNC(jint, opusGetErrorCode, jlong jContext) { return errorCode; }
177 
DECODER_FUNC(void,opusSetFloatOutput)178 DECODER_FUNC(void, opusSetFloatOutput) { outputFloat = true; }
179 
LIBRARY_FUNC(jstring,opusIsSecureDecodeSupported)180 LIBRARY_FUNC(jstring, opusIsSecureDecodeSupported) {
181   // Doesn't support
182   return 0;
183 }
184 
LIBRARY_FUNC(jstring,opusGetVersion)185 LIBRARY_FUNC(jstring, opusGetVersion) {
186   return env->NewStringUTF(opus_get_version_string());
187 }
188