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