Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b65cd17b authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "Implement audio routing callbacks" into mnc-dev

parents 6223ec12 4bcdba84
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -132,6 +132,7 @@ LOCAL_SRC_FILES:= \
    android_media_AudioRecord.cpp \
    android_media_AudioSystem.cpp \
    android_media_AudioTrack.cpp \
    android_media_DeviceCallback.cpp \
    android_media_JetPlayer.cpp \
    android_media_RemoteDisplay.cpp \
    android_media_ToneGenerator.cpp \
+92 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
#include "android_media_DeviceCallback.h"

// ----------------------------------------------------------------------------

@@ -44,6 +45,7 @@ struct audio_record_fields_t {
    jmethodID postNativeEventInJava; //... event post callback method
    jfieldID  nativeRecorderInJavaObj; // provides access to the C++ AudioRecord object
    jfieldID  nativeCallbackCookie;    // provides access to the AudioRecord callback data
    jfieldID  nativeDeviceCallback;    // provides access to the JNIDeviceCallback instance
};
struct audio_attributes_fields_t {
    jfieldID  fieldRecSource;    // AudioAttributes.mSource
@@ -120,6 +122,33 @@ static void recorderCallback(int event, void* user, void *info) {
    }
}

static sp<JNIDeviceCallback> getJniDeviceCallback(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    JNIDeviceCallback* const cb =
            (JNIDeviceCallback*)env->GetLongField(thiz,
                                                  javaAudioRecordFields.nativeDeviceCallback);
    return sp<JNIDeviceCallback>(cb);
}

static sp<JNIDeviceCallback> setJniDeviceCallback(JNIEnv* env,
                                                  jobject thiz,
                                                  const sp<JNIDeviceCallback>& cb)
{
    Mutex::Autolock l(sLock);
    sp<JNIDeviceCallback> old =
            (JNIDeviceCallback*)env->GetLongField(thiz,
                                                  javaAudioRecordFields.nativeDeviceCallback);
    if (cb.get()) {
        cb->incStrong((void*)setJniDeviceCallback);
    }
    if (old != 0) {
        old->decStrong((void*)setJniDeviceCallback);
    }
    env->SetLongField(thiz, javaAudioRecordFields.nativeDeviceCallback, (jlong)cb.get());
    return old;
}

// ----------------------------------------------------------------------------
static sp<AudioRecord> getAudioRecord(JNIEnv* env, jobject thiz)
{
@@ -593,9 +622,63 @@ static jboolean android_media_AudioRecord_setInputDevice(
        JNIEnv *env,  jobject thiz, jint device_id) {

    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    if (lpRecorder == 0) {
        return 0;
    }
    return lpRecorder->setInputDevice(device_id) == NO_ERROR;
}

static jint android_media_AudioRecord_getRoutedDeviceId(
                JNIEnv *env,  jobject thiz) {

    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    if (lpRecorder == 0) {
        return 0;
    }
    return (jint)lpRecorder->getRoutedDeviceId();
}

static void android_media_AudioRecord_enableDeviceCallback(
                JNIEnv *env,  jobject thiz) {

    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    if (lpRecorder == 0) {
        return;
    }
    sp<JNIDeviceCallback> cb = getJniDeviceCallback(env, thiz);
    if (cb != 0) {
        return;
    }
    audiorecord_callback_cookie *cookie =
            (audiorecord_callback_cookie *)env->GetLongField(thiz,
                                                     javaAudioRecordFields.nativeCallbackCookie);
    if (cookie == NULL) {
        return;
    }

    cb = new JNIDeviceCallback(env, thiz, cookie->audioRecord_ref,
                               javaAudioRecordFields.postNativeEventInJava);
    status_t status = lpRecorder->addAudioDeviceCallback(cb);
    if (status == NO_ERROR) {
        setJniDeviceCallback(env, thiz, cb);
    }
}

static void android_media_AudioRecord_disableDeviceCallback(
                JNIEnv *env,  jobject thiz) {

    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
    if (lpRecorder == 0) {
        return;
    }
    sp<JNIDeviceCallback> cb = setJniDeviceCallback(env, thiz, 0);
    if (cb != 0) {
        lpRecorder->removeAudioDeviceCallback(cb);
    }
}



// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -628,12 +711,17 @@ static JNINativeMethod gMethods[] = {
    {"native_get_min_buff_size",
                             "(III)I",   (void *)android_media_AudioRecord_get_min_buff_size},
    {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice},
    {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId},
    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
    {"native_disableDeviceCallback", "()V",
                                        (void *)android_media_AudioRecord_disableDeviceCallback},
};

// field names found in android/media/AudioRecord.java
#define JAVA_POSTEVENT_CALLBACK_NAME  "postEventFromNative"
#define JAVA_NATIVERECORDERINJAVAOBJ_FIELD_NAME  "mNativeRecorderInJavaObj"
#define JAVA_NATIVECALLBACKINFO_FIELD_NAME       "mNativeCallbackCookie"
#define JAVA_NATIVEDEVICECALLBACK_FIELD_NAME       "mNativeDeviceCallback"

// ----------------------------------------------------------------------------
int register_android_media_AudioRecord(JNIEnv *env)
@@ -641,6 +729,7 @@ int register_android_media_AudioRecord(JNIEnv *env)
    javaAudioRecordFields.postNativeEventInJava = NULL;
    javaAudioRecordFields.nativeRecorderInJavaObj = NULL;
    javaAudioRecordFields.nativeCallbackCookie = NULL;
    javaAudioRecordFields.nativeDeviceCallback = NULL;


    // Get the AudioRecord class
@@ -658,6 +747,9 @@ int register_android_media_AudioRecord(JNIEnv *env)
    javaAudioRecordFields.nativeCallbackCookie = GetFieldIDOrDie(env,
            audioRecordClass, JAVA_NATIVECALLBACKINFO_FIELD_NAME, "J");

    javaAudioRecordFields.nativeDeviceCallback = GetFieldIDOrDie(env,
            audioRecordClass, JAVA_NATIVEDEVICECALLBACK_FIELD_NAME, "J");

    // Get the AudioAttributes class and fields
    jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
    javaAudioAttrFields.fieldRecSource = GetFieldIDOrDie(env, audioAttrClass, "mSource", "I");
+3 −2
Original line number Diff line number Diff line
@@ -937,7 +937,8 @@ static jint convertAudioPortFromNative(JNIEnv *env,
    } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) {
        ALOGV("convertAudioPortFromNative is a mix");
        *jAudioPort = env->NewObject(gAudioMixPortClass, gAudioMixPortCstor,
                                     jHandle, nAudioPort->role, jDeviceName,
                                     jHandle, nAudioPort->ext.mix.handle,
                                     nAudioPort->role, jDeviceName,
                                     jSamplingRates, jChannelMasks,
                                     jFormats, jGains);
    } else {
@@ -1670,7 +1671,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
    jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort");
    gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass);
    gAudioMixPortCstor = GetMethodIDOrDie(env, audioMixPortClass, "<init>",
            "(Landroid/media/AudioHandle;ILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");
            "(Landroid/media/AudioHandle;IILjava/lang/String;[I[I[I[Landroid/media/AudioGain;)V");

    jclass audioGainClass = FindClassOrDie(env, "android/media/AudioGain");
    gAudioGainClass = MakeGlobalRefOrDie(env, audioGainClass);
+50 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include "android_media_AudioFormat.h"
#include "android_media_AudioErrors.h"
#include "android_media_PlaybackSettings.h"
#include "android_media_DeviceCallback.h"

// ----------------------------------------------------------------------------

@@ -79,6 +80,7 @@ class AudioTrackJniStorage {
        sp<MemoryHeapBase>         mMemHeap;
        sp<MemoryBase>             mMemBase;
        audiotrack_callback_cookie mCallbackData;
        sp<JNIDeviceCallback>      mDeviceCallback;

    AudioTrackJniStorage() {
        mCallbackData.audioTrack_class = 0;
@@ -977,6 +979,51 @@ static jboolean android_media_AudioTrack_setOutputDevice(
    return lpTrack->setOutputDevice(device_id) == NO_ERROR;
}

static jint android_media_AudioTrack_getRoutedDeviceId(
                JNIEnv *env,  jobject thiz) {

    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        return 0;
    }
    return (jint)lpTrack->getRoutedDeviceId();
}

static void android_media_AudioTrack_enableDeviceCallback(
                JNIEnv *env,  jobject thiz) {

    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        return;
    }
    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
        thiz, javaAudioTrackFields.jniData);
    if (pJniStorage == NULL || pJniStorage->mDeviceCallback != 0) {
        return;
    }
    pJniStorage->mDeviceCallback =
    new JNIDeviceCallback(env, thiz, pJniStorage->mCallbackData.audioTrack_ref,
                          javaAudioTrackFields.postNativeEventInJava);
    lpTrack->addAudioDeviceCallback(pJniStorage->mDeviceCallback);
}

static void android_media_AudioTrack_disableDeviceCallback(
                JNIEnv *env,  jobject thiz) {

    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        return;
    }
    AudioTrackJniStorage* pJniStorage = (AudioTrackJniStorage *)env->GetLongField(
        thiz, javaAudioTrackFields.jniData);
    if (pJniStorage == NULL || pJniStorage->mDeviceCallback == 0) {
        return;
    }
    lpTrack->removeAudioDeviceCallback(pJniStorage->mDeviceCallback);
    pJniStorage->mDeviceCallback.clear();
}


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
@@ -1030,6 +1077,9 @@ static JNINativeMethod gMethods[] = {
                             "(I)I",     (void *)android_media_AudioTrack_attachAuxEffect},
    {"native_setOutputDevice", "(I)Z",
                             (void *)android_media_AudioTrack_setOutputDevice},
    {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId},
    {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback},
    {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback},
};


+82 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0

#define LOG_TAG "AudioDeviceCallback-JNI"

#include <utils/Log.h>
#include <JNIHelp.h>
#include <JniConstants.h>
#include "core_jni_helpers.h"
#include <media/AudioSystem.h>

#include "android_media_DeviceCallback.h"


// ----------------------------------------------------------------------------

using namespace android;

JNIDeviceCallback::JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz,
                                     jmethodID postEventFromNative)
{

    // Hold onto the AudioTrack/AudioRecord class for use in calling the static method
    // that posts events to the application thread.
    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
        return;
    }
    mClass = (jclass)env->NewGlobalRef(clazz);

    // We use a weak reference so the AudioTrack/AudioRecord object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    mObject  = env->NewGlobalRef(weak_thiz);

    mPostEventFromNative = postEventFromNative;
}

JNIDeviceCallback::~JNIDeviceCallback()
{
    // remove global references
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        return;
    }
    env->DeleteGlobalRef(mObject);
    env->DeleteGlobalRef(mClass);
}

void JNIDeviceCallback::onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                            audio_port_handle_t deviceId)
{
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        return;
    }

    ALOGV("%s audioIo %d deviceId %d", __FUNCTION__, audioIo, deviceId);
    env->CallStaticVoidMethod(mClass,
                              mPostEventFromNative,
                              mObject,
                              AUDIO_NATIVE_EVENT_ROUTING_CHANGE, deviceId, 0, NULL);
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        env->ExceptionClear();
    }
}
Loading