opus_jni.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. #include <jni.h>
  17. #include <android/log.h>
  18. #include <cstdlib>
  19. #include "opus.h" // NOLINT
  20. #include "opus_multistream.h" // NOLINT
  21. #define LOG_TAG "opus_jni"
  22. #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \
  23. __VA_ARGS__))
  24. #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
  25. extern "C" { \
  26. JNIEXPORT RETURN_TYPE \
  27. Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_ ## NAME \
  28. (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
  29. } \
  30. JNIEXPORT RETURN_TYPE \
  31. Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_ ## NAME \
  32. (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
  33. #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
  34. extern "C" { \
  35. JNIEXPORT RETURN_TYPE \
  36. Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_ ## NAME \
  37. (JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
  38. } \
  39. JNIEXPORT RETURN_TYPE \
  40. Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_ ## NAME \
  41. (JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
  42. // JNI references for SimpleOutputBuffer class.
  43. static jmethodID outputBufferInit;
  44. static const int kBytesPerSample = 2; // opus fixed point uses 16 bit samples.
  45. static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
  46. static int channelCount;
  47. static int errorCode;
  48. DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
  49. jint numStreams, jint numCoupled, jint gain, jbyteArray jStreamMap) {
  50. int status = OPUS_INVALID_STATE;
  51. ::channelCount = channelCount;
  52. errorCode = 0;
  53. jbyte* streamMapBytes = env->GetByteArrayElements(jStreamMap, 0);
  54. uint8_t* streamMap = reinterpret_cast<uint8_t*>(streamMapBytes);
  55. OpusMSDecoder* decoder = opus_multistream_decoder_create(
  56. sampleRate, channelCount, numStreams, numCoupled, streamMap, &status);
  57. env->ReleaseByteArrayElements(jStreamMap, streamMapBytes, 0);
  58. if (!decoder || status != OPUS_OK) {
  59. LOGE("Failed to create Opus Decoder; status=%s", opus_strerror(status));
  60. return 0;
  61. }
  62. status = opus_multistream_decoder_ctl(decoder, OPUS_SET_GAIN(gain));
  63. if (status != OPUS_OK) {
  64. LOGE("Failed to set Opus header gain; status=%s", opus_strerror(status));
  65. return 0;
  66. }
  67. // Populate JNI References.
  68. const jclass outputBufferClass = env->FindClass(
  69. "com/google/android/exoplayer2/decoder/SimpleOutputBuffer");
  70. outputBufferInit = env->GetMethodID(outputBufferClass, "init",
  71. "(JI)Ljava/nio/ByteBuffer;");
  72. return reinterpret_cast<intptr_t>(decoder);
  73. }
  74. DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
  75. jobject jInputBuffer, jint inputSize, jobject jOutputBuffer) {
  76. OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
  77. const uint8_t* inputBuffer =
  78. reinterpret_cast<const uint8_t*>(
  79. env->GetDirectBufferAddress(jInputBuffer));
  80. const jint outputSize =
  81. kMaxOpusOutputPacketSizeSamples * kBytesPerSample * channelCount;
  82. env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
  83. if (env->ExceptionCheck()) {
  84. // Exception is thrown in Java when returning from the native call.
  85. return -1;
  86. }
  87. const jobject jOutputBufferData = env->CallObjectMethod(jOutputBuffer,
  88. outputBufferInit, jTimeUs, outputSize);
  89. if (env->ExceptionCheck()) {
  90. // Exception is thrown in Java when returning from the native call.
  91. return -1;
  92. }
  93. int16_t* outputBufferData = reinterpret_cast<int16_t*>(
  94. env->GetDirectBufferAddress(jOutputBufferData));
  95. int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize,
  96. outputBufferData, kMaxOpusOutputPacketSizeSamples, 0);
  97. // record error code
  98. errorCode = (sampleCount < 0) ? sampleCount : 0;
  99. return (sampleCount < 0) ? sampleCount
  100. : sampleCount * kBytesPerSample * channelCount;
  101. }
  102. DECODER_FUNC(jint, opusSecureDecode, jlong jDecoder, jlong jTimeUs,
  103. jobject jInputBuffer, jint inputSize, jobject jOutputBuffer,
  104. jint sampleRate, jobject mediaCrypto, jint inputMode, jbyteArray key,
  105. jbyteArray javaIv, jint inputNumSubSamples, jintArray numBytesOfClearData,
  106. jintArray numBytesOfEncryptedData) {
  107. // Doesn't support
  108. // Java client should have checked vpxSupportSecureDecode
  109. // and avoid calling this
  110. // return -2 (DRM Error)
  111. return -2;
  112. }
  113. DECODER_FUNC(void, opusClose, jlong jDecoder) {
  114. OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
  115. opus_multistream_decoder_destroy(decoder);
  116. }
  117. DECODER_FUNC(void, opusReset, jlong jDecoder) {
  118. OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
  119. opus_multistream_decoder_ctl(decoder, OPUS_RESET_STATE);
  120. }
  121. DECODER_FUNC(jstring, opusGetErrorMessage, jlong jContext) {
  122. return env->NewStringUTF(opus_strerror(errorCode));
  123. }
  124. DECODER_FUNC(jint, opusGetErrorCode, jlong jContext) {
  125. return errorCode;
  126. }
  127. LIBRARY_FUNC(jstring, opusIsSecureDecodeSupported) {
  128. // Doesn't support
  129. return 0;
  130. }
  131. LIBRARY_FUNC(jstring, opusGetVersion) {
  132. return env->NewStringUTF(opus_get_version_string());
  133. }