C++程序  |  399行  |  15.19 KB

/*
 * Copyright (C) 2010 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.
 */

/* AndroidConfiguration implementation */

#include <android/log.h>

#include "sles_allinclusive.h"
#include <SLES/OpenSLES_Android.h>

#include <android_runtime/AndroidRuntime.h>

static SLresult IAndroidConfiguration_SetConfiguration(SLAndroidConfigurationItf self,
        const SLchar *configKey,
        const void *pConfigValue,
        SLuint32 valueSize)
{
    SL_ENTER_INTERFACE

    // object-specific code will check that valueSize is large enough for the key
    if (NULL == configKey || NULL == pConfigValue || valueSize == 0) {
        result = SL_RESULT_PARAMETER_INVALID;

    } else {
        IAndroidConfiguration *thiz = (IAndroidConfiguration *) self;
        interface_lock_exclusive(thiz);

        // route configuration to the appropriate object
        switch (IObjectToObjectID((thiz)->mThis)) {
        case SL_OBJECTID_AUDIORECORDER:
            SL_LOGV("SetConfiguration issued for AudioRecorder key=%s valueSize=%u",
                    configKey, valueSize);
            result = android_audioRecorder_setConfig((CAudioRecorder *) thiz->mThis, configKey,
                    pConfigValue, valueSize);
            break;
        case SL_OBJECTID_AUDIOPLAYER:
            SL_LOGV("SetConfiguration issued for AudioPlayer key=%s valueSize=%u",
                    configKey, valueSize);
            result = android_audioPlayer_setConfig((CAudioPlayer *) thiz->mThis, configKey,
                    pConfigValue, valueSize);
            break;
        default:
            result = SL_RESULT_FEATURE_UNSUPPORTED;
            break;
        }

        interface_unlock_exclusive(thiz);
    }

    SL_LEAVE_INTERFACE
}


static SLresult IAndroidConfiguration_GetConfiguration(SLAndroidConfigurationItf self,
        const SLchar *configKey,
        SLuint32 *pValueSize,
        void *pConfigValue)
{
    SL_ENTER_INTERFACE

    // non-NULL pValueSize is required, but a NULL pConfigValue is allowed, so
    // that we can report the actual value size without returning the value itself
    if (NULL == configKey || NULL == pValueSize) {
        result = SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidConfiguration *thiz = (IAndroidConfiguration *) self;
        interface_lock_exclusive(thiz);

        // route configuration request to the appropriate object
        switch (IObjectToObjectID((thiz)->mThis)) {
        case SL_OBJECTID_AUDIORECORDER:
            result = android_audioRecorder_getConfig((CAudioRecorder *) thiz->mThis, configKey,
                    pValueSize, pConfigValue);
            break;
        case SL_OBJECTID_AUDIOPLAYER:
            result = android_audioPlayer_getConfig((CAudioPlayer *) thiz->mThis, configKey,
                    pValueSize, pConfigValue);
        default:
            result = SL_RESULT_FEATURE_UNSUPPORTED;
            break;
        }

        interface_unlock_exclusive(thiz);
    }

    SL_LEAVE_INTERFACE
}

/*
 * Native Routing API
 */
static SLresult ValidatePlayerConfig(IAndroidConfiguration* iConfig) {
    SLresult result;

    if (iConfig->mRoutingProxy != NULL) {
        result = SL_RESULT_PRECONDITIONS_VIOLATED;
        SL_LOGE("Error creating player routing object - Routing Proxy Already Acquired.");
    }
    else {
        IObject* configObj = iConfig->mThis;                // get corresponding object
        CAudioPlayer* player = (CAudioPlayer*)configObj;    // get the native player

        switch (player->mAndroidObjType) {
            case AUDIOPLAYER_FROM_PCM_BUFFERQUEUE:
                //TODO remove these commented out lines when our comfort level is good
//                if (player->mObject.mState != SL_OBJECT_STATE_REALIZED) {
//                    // Make sure the player has been realized.
//                    result = SL_RESULT_PRECONDITIONS_VIOLATED;
//                    SL_LOGE("Error creating routing object - Player not realized.");
//                } else {
//                    android::AudioTrack* pAudioTrack = player->mAudioTrack.get();
//                    if (pAudioTrack == NULL) {
//                        result = SL_RESULT_INTERNAL_ERROR;
//                        SL_LOGE("Error creating routing object - Couldn't get AudioTrack.");
//                    } else {
                        result = SL_RESULT_SUCCESS;
//                    }
//                }
                break;

            default:
                result =  SL_RESULT_PARAMETER_INVALID;
                SL_LOGE("Error creating routing object - Player is not a buffer-queue player.");
                break;
        }
    }

    return result;
}

static SLresult AllocPlayerRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) {
    SLresult result;

    IObject* configObj = iConfig->mThis;                // get corresponding object
    android::AudioTrack* pAudioTrack = ((CAudioPlayer*)configObj)->mAudioTrack.get();

    JNIEnv* j_env = android::AndroidRuntime::getJNIEnv();

    // Get the constructor for (Java) AudioTrackRoutingProxy
    jclass clsAudioTrackRoutingProxy =
            j_env->FindClass("android/media/AudioTrackRoutingProxy");
    jmethodID midAudioTrackRoutingProxy_ctor =
        j_env->GetMethodID(clsAudioTrackRoutingProxy, "<init>", "(J)V");

    j_env->ExceptionClear();

    jobject localObjRef =
        j_env->NewObject(clsAudioTrackRoutingProxy,
                         midAudioTrackRoutingProxy_ctor,
                         (jlong)pAudioTrack /*audioTrackObjInLong*/);

    *proxyObj = j_env->NewGlobalRef(localObjRef);

    if (j_env->ExceptionCheck()) {
        SL_LOGE("Java exception creating player routing object.");
        result = SL_RESULT_INTERNAL_ERROR;
    } else {
        // stash it in the Interface object
        iConfig->mRoutingProxy = *proxyObj;
        result = SL_RESULT_SUCCESS;
    }

    return result;
}

static SLresult ValidateRecorderConfig(IAndroidConfiguration* iConfig) {
    SLresult result;

    if (iConfig->mRoutingProxy != NULL) {
        result = SL_RESULT_PRECONDITIONS_VIOLATED;
        SL_LOGE("Error creating record routing object - Routing Proxy Already Acquired.");
    } else {
        IObject* configObj = iConfig->mThis;                  // get corresponding object
        CAudioRecorder* recorder = (CAudioRecorder*)configObj;  // get the native recorder
        switch (recorder->mAndroidObjType) {
            case AUDIORECORDER_FROM_MIC_TO_PCM_BUFFERQUEUE:
                //TODO remove these commented out lines when our comfort level is good
//                if (recorder->mObject.mState != SL_OBJECT_STATE_REALIZED) {
//                    // Make sure the recorder has been realized.
//                    result = SL_RESULT_PRECONDITIONS_VIOLATED;
//                    SL_LOGE("Error creating routing object - Recorder not realized.");
//                } else {
//                    android::AudioRecord* pAudioRecord = recorder->mAudioRecord.get();
//                    if (pAudioRecord == NULL) {
//                        result = SL_RESULT_INTERNAL_ERROR;
//                        SL_LOGE("Error creating routing object - Couldn't get AudioRecord.");
//                    } else if (iConfig->mRoutingProxy != NULL) {
//                        result = SL_RESULT_PRECONDITIONS_VIOLATED;
//                        SL_LOGE("Error creating routing object - Routing Proxy Already Acquired.");
//                    } else {
                        result = SL_RESULT_SUCCESS;
//                    }
//                }
                break;

            default:
                result =  SL_RESULT_PARAMETER_INVALID;
                SL_LOGE("Error creating routing object - Recorder is not a buffer-queue recorder.");
                break;
        }
    }

    return result;
}

static SLresult AllocRecorderRoutingProxy(IAndroidConfiguration* iConfig, jobject* proxyObj) {
    SLresult result;

    IObject* configObj = iConfig->mThis;                  // get corresponding object
    android::AudioRecord* pAudioRecord = ((CAudioRecorder*)configObj)->mAudioRecord.get();

    JNIEnv* j_env = android::AndroidRuntime::getJNIEnv();

    // Get the constructor for (Java) AudioRecordRoutingProxy
    jclass clsAudioRecordRoutingProxy =
            j_env->FindClass("android/media/AudioRecordRoutingProxy");
    jmethodID midAudioRecordRoutingProxy_ctor =
        j_env->GetMethodID(clsAudioRecordRoutingProxy, "<init>", "(J)V");

    j_env->ExceptionClear();
    jobject localObjRef =
        j_env->NewObject(clsAudioRecordRoutingProxy,
                         midAudioRecordRoutingProxy_ctor,
                         (jlong)pAudioRecord /*audioRecordObjInLong*/);

    *proxyObj = j_env->NewGlobalRef(localObjRef);
    if (j_env->ExceptionCheck()) {
        SL_LOGE("Java exception creating recorder routing object.");
        result = SL_RESULT_INTERNAL_ERROR;
    } else {
        // stash it in the Interface object
        iConfig->mRoutingProxy = *proxyObj;
        result = SL_RESULT_SUCCESS;
    }

    return result;
}

/*
 * Acquires a Java proxy object, such as AudioRouting object which can be used to control
 * aspects of the associated native player or recorder.
 * Parameters:
 *   self   An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer
 *          or AudioRecorder.
 *   j_env  The Java Environment pointer (passed in to the calling JNI function).
 *   proxyType Specifies the type of proxy desired. Currently only SL_ANDROID_JAVA_PROXY_ROUTING
 *          is supported.
 *   proxyObj
 *          Points to the jobject to receive the acquired Java proxy object (as a GlobalRef).
 * Returns SL_RESULT_SUCCESS is the proxy object is acquired, SL_RESULT_PARAMETER_INVALID if
 *   there is a problem with the arguments causing the function to fail,
 *   <working on this>
 *   SL_RESULT_PRECONDITIONS_VIOLATED it the AudioPlayer or AudioRecorder object associated
 *   with the ConfigurationItf has not been realized.
 */
static SLresult IAndroidConfiguration_AcquireJavaProxy(SLAndroidConfigurationItf self,
                                                       SLuint32 proxyType,
                                                       jobject* proxyObj)
{
    SL_ENTER_INTERFACE

    if (self == NULL || proxyObj == NULL || proxyType != SL_ANDROID_JAVA_PROXY_ROUTING) {
        result =  SL_RESULT_PARAMETER_INVALID;
    } else {
        IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self;

        int objID = IObjectToObjectID(InterfaceToIObject(iConfig));
        switch (objID) {
        case SL_OBJECTID_AUDIOPLAYER:
            result = ValidatePlayerConfig(iConfig);
            if (result == SL_RESULT_SUCCESS) {
                result = AllocPlayerRoutingProxy(iConfig, proxyObj);
            }
            break;

        case SL_OBJECTID_AUDIORECORDER:
            result = ValidateRecorderConfig(iConfig);
            if (result == SL_RESULT_SUCCESS) {
                result = AllocRecorderRoutingProxy(iConfig, proxyObj);
            }
            break;

        default:
            result = SL_RESULT_PARAMETER_INVALID;
            break;
        }
    }

    SL_LEAVE_INTERFACE
}

/*
 * Release a Java proxy object, such as AudioRouting object, (and any resources it is holding).
 * Parameters:
 *   self   An SLAndroidConfigurationItf obtained from either an OpenSL ES AudioPlayer
 *          or AudioRecorder.
 *   j_env  The Java Environment pointer (passed in to the calling JNI function).
 *   proxyType Specifies the type of proxy object. Currently only SL_ANDROID_JAVA_PROXY_ROUTING
 *          is supported.
 * Returns SL_RESULT_SUCCESS is the proxy object is release, SL_RESULT_PARAMETER_INVALID if
 *   there is a problem with the arguments causing the function to fail,
 */
static SLresult IAndroidConfiguration_ReleaseJavaProxy(SLAndroidConfigurationItf self,
                                                       SLuint32 proxyType) {
    SL_ENTER_INTERFACE

    IAndroidConfiguration* iConfig = (IAndroidConfiguration*)self;

    if (self == NULL ||
            proxyType != SL_ANDROID_JAVA_PROXY_ROUTING ||
            iConfig->mRoutingProxy == NULL) {
        result =  SL_RESULT_PARAMETER_INVALID;
    } else {
        int objID = IObjectToObjectID(InterfaceToIObject(iConfig));
        switch (objID) {
        case SL_OBJECTID_AUDIOPLAYER:
            {
                JNIEnv* j_env = android::AndroidRuntime::getJNIEnv();

                // Get the release method for (Java) AudioTrackRoutingProxy
                jclass clsAudioTrackRoutingProxy =
                        j_env->FindClass("android/media/AudioTrackRoutingProxy");
                jmethodID midAudioTrackRoutingProxy_release =
                    j_env->GetMethodID(clsAudioTrackRoutingProxy, "native_release", "()V");

                j_env->ExceptionClear();
                j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioTrackRoutingProxy_release);
                if (j_env->ExceptionCheck()) {
                    SL_LOGE("Java exception releasing recorder routing object.");
                    result = SL_RESULT_INTERNAL_ERROR;
                }
                j_env->DeleteGlobalRef(iConfig->mRoutingProxy);
                iConfig->mRoutingProxy = NULL;
            }
            break;

        case SL_OBJECTID_AUDIORECORDER:
            {
                JNIEnv* j_env = android::AndroidRuntime::getJNIEnv();

                // Get the release method for (Java) AudioTrackRoutingProxy
                jclass clsAudioRecordRoutingProxy =
                        j_env->FindClass("android/media/AudioRecordRoutingProxy");
                jmethodID midAudioRecordRoutingProxy_release =
                    j_env->GetMethodID(clsAudioRecordRoutingProxy, "native_release", "()V");

                j_env->ExceptionClear();
                j_env->CallVoidMethod(iConfig->mRoutingProxy, midAudioRecordRoutingProxy_release);
                if (j_env->ExceptionCheck()) {
                    SL_LOGE("Java exception releasing recorder routing object.");
                    result = SL_RESULT_INTERNAL_ERROR;
                }
                j_env->DeleteGlobalRef(iConfig->mRoutingProxy);
                iConfig->mRoutingProxy = NULL;
            }
            break;
        }

        result = SL_RESULT_SUCCESS;
    }

    SL_LEAVE_INTERFACE
}

static const struct SLAndroidConfigurationItf_ IAndroidConfiguration_Itf = {
    IAndroidConfiguration_SetConfiguration,
    IAndroidConfiguration_GetConfiguration,
    IAndroidConfiguration_AcquireJavaProxy,
    IAndroidConfiguration_ReleaseJavaProxy
};

void IAndroidConfiguration_init(void *self)
{
    IAndroidConfiguration *thiz = (IAndroidConfiguration *) self;
    thiz->mItf = &IAndroidConfiguration_Itf;
}

void IAndroidConfiguration_deinit(void *self)
{
    IAndroidConfiguration *thiz = (IAndroidConfiguration *) self;
    if (thiz->mRoutingProxy != NULL) {
        thiz->mItf->ReleaseJavaProxy(&thiz->mItf, SL_ANDROID_JAVA_PROXY_ROUTING);
    }
}