1 /* 2 * Copyright (C) 2020 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 //#define LOG_NDEBUG 0 18 19 #define LOG_TAG "AudioTrackCallback-JNI" 20 21 #include <algorithm> 22 23 #include <nativehelper/JNIHelp.h> 24 #include <utils/Errors.h> 25 #include <utils/Log.h> 26 27 #include "android_media_AudioTrackCallback.h" 28 #include "core_jni_helpers.h" 29 30 using namespace android; 31 32 #define BYTE_BUFFER_NAME "java/nio/ByteBuffer" 33 #define BYTE_BUFFER_ALLOCATE_DIRECT_NAME "allocateDirect" 34 35 JNIAudioTrackCallback::JNIAudioTrackCallback(JNIEnv* env, jobject thiz, jobject weak_thiz, 36 jmethodID postEventFromNative) { 37 // Hold onto the AudioTrack class for use in calling the static method 38 // that posts events to the application thread. 39 jclass clazz = env->GetObjectClass(thiz); 40 if (clazz == nullptr) { 41 return; 42 } 43 mClass = (jclass)env->NewGlobalRef(clazz); 44 45 // We use a weak reference so the AudioTrack object can be garbage collected. 46 // The reference is only used as a proxy for callbacks. 47 mObject = env->NewGlobalRef(weak_thiz); 48 49 mPostEventFromNative = postEventFromNative; 50 51 jclass byteBufferClass = FindClassOrDie(env, BYTE_BUFFER_NAME); 52 mByteBufferClass = (jclass)env->NewGlobalRef(byteBufferClass); 53 mAllocateDirectMethod = 54 GetStaticMethodIDOrDie(env, mByteBufferClass, BYTE_BUFFER_ALLOCATE_DIRECT_NAME, 55 "(I)Ljava/nio/ByteBuffer;"); 56 } 57 58 JNIAudioTrackCallback::~JNIAudioTrackCallback() { 59 // remove global references 60 JNIEnv* env = AndroidRuntime::getJNIEnv(); 61 if (env == nullptr) { 62 return; 63 } 64 env->DeleteGlobalRef(mObject); 65 env->DeleteGlobalRef(mClass); 66 env->DeleteGlobalRef(mByteBufferClass); 67 } 68 69 binder::Status JNIAudioTrackCallback::onCodecFormatChanged( 70 const std::vector<uint8_t>& audioMetadata) { 71 JNIEnv* env = AndroidRuntime::getJNIEnv(); 72 if (env == nullptr) { 73 return binder::Status::ok(); 74 } 75 76 jobject byteBuffer = env->CallStaticObjectMethod(mByteBufferClass, mAllocateDirectMethod, 77 (jint)audioMetadata.size()); 78 if (env->ExceptionCheck()) { 79 ALOGW("An exception occurred while allocating direct buffer"); 80 env->ExceptionDescribe(); 81 env->ExceptionClear(); 82 } 83 if (byteBuffer == nullptr) { 84 ALOGE("Failed allocating a direct ByteBuffer"); 85 return binder::Status::fromStatusT(NO_MEMORY); 86 } 87 88 uint8_t* byteBufferAddr = (uint8_t*)env->GetDirectBufferAddress(byteBuffer); 89 std::copy(audioMetadata.begin(), audioMetadata.end(), byteBufferAddr); 90 env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject, 91 AUDIO_NATIVE_EVENT_CODEC_FORMAT_CHANGE, 0, 0, byteBuffer); 92 if (env->ExceptionCheck()) { 93 ALOGW("An exception occurred while notifying codec format changed."); 94 env->ExceptionDescribe(); 95 env->ExceptionClear(); 96 } 97 98 return binder::Status::ok(); 99 } 100