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

Commit 62cab4de authored by Dichen Zhang's avatar Dichen Zhang Committed by Android (Google) Code Review
Browse files

Merge "Enable JAudioTrack."

parents 02290295 f8726915
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -26,8 +26,7 @@ class JAudioAttributes {
public:
    /* Creates a Java AudioAttributes object. */
    static jobject createAudioAttributesObj(JNIEnv *env,
                                            const audio_attributes_t* pAttributes,
                                            audio_stream_type_t streamType) {
                                            const audio_attributes_t* pAttributes) {

        jclass jBuilderCls = env->FindClass("android/media/AudioAttributes$Builder");
        jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
@@ -58,11 +57,6 @@ public:
            // TODO: Handle the 'tags' (char[] to HashSet<String>).
            // How to parse the char[]? Is there any example of it?
            // Also, the addTags() method is hidden.
        } else {
            // Call AudioAttributes.Builder.setLegacyStreamType().build()
            jmethodID jSetLegacyStreamType = env->GetMethodID(jBuilderCls, "setLegacyStreamType",
                    "(I)Landroid/media/AudioAttributes$Builder;");
            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetLegacyStreamType, streamType);
        }

        jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ cc_library_static {
        "libstagefright_player2",
        "libstagefright_rtsp",
        "libstagefright_timedtext2",
        "libmedia2_jni_core",
    ],

    export_include_dirs: [
+132 −23
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ namespace android {
// TODO: Store Java class/methodID as a member variable in the class.
// TODO: Add NULL && Exception checks after every JNI call.
JAudioTrack::JAudioTrack(                             // < Usages of the arguments are below >
        audio_stream_type_t streamType,               // AudioAudioAttributes
        uint32_t sampleRate,                          // AudioFormat && bufferSizeInBytes
        audio_format_t format,                        // AudioFormat && bufferSizeInBytes
        audio_channel_mask_t channelMask,             // AudioFormat && bufferSizeInBytes
@@ -40,8 +39,10 @@ JAudioTrack::JAudioTrack( // < Usages of the argumen
        float maxRequiredSpeed) {                     // bufferSizeInBytes

    JNIEnv *env = JavaVMHelper::getJNIEnv();

    jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
    mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
    mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
    env->DeleteLocalRef(jAudioTrackCls);

    maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);

@@ -64,10 +65,13 @@ JAudioTrack::JAudioTrack( // < Usages of the argumen
    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);

    jobject jAudioAttributesObj = JAudioAttributes::createAudioAttributesObj(env, pAttributes);
    mAudioAttributesObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioAttributesObj));
    env->DeleteLocalRef(jAudioAttributesObj);

    jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
            "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes,
            JAudioAttributes::createAudioAttributesObj(env, pAttributes, streamType));
    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes, mAudioAttributesObj);

    jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
            "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
@@ -100,7 +104,9 @@ JAudioTrack::JAudioTrack( // < Usages of the argumen
    }

    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
    mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
    jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
    mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
    env->DeleteLocalRef(jBuilderObj);

    if (cbf != NULL) {
        // Set offload mode callback
@@ -118,6 +124,8 @@ JAudioTrack::JAudioTrack( // < Usages of the argumen
JAudioTrack::~JAudioTrack() {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    env->DeleteGlobalRef(mAudioTrackCls);
    env->DeleteGlobalRef(mAudioTrackObj);
    env->DeleteGlobalRef(mAudioAttributesObj);
}

size_t JAudioTrack::frameCount() {
@@ -151,21 +159,21 @@ status_t JAudioTrack::getPosition(uint32_t *position) {
    return NO_ERROR;
}

bool JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();

    jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
    jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);

    jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "L");
    jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "L");
    jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
    jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");

    jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
            "getTimestamp", "(Landroid/media/AudioTimestamp)B");
            "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
    bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);

    if (!success) {
        return false;
        return NO_INIT;
    }

    long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
@@ -178,7 +186,7 @@ bool JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
    timestamp.mTime = ts;
    timestamp.mPosition = (uint32_t) framePosition;

    return true;
    return NO_ERROR;
}

status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
@@ -423,6 +431,35 @@ audio_format_t JAudioTrack::format() {
    return audioFormatToNative(javaFormat);
}

size_t JAudioTrack::frameSize() {
    JNIEnv *env = JavaVMHelper::getJNIEnv();

    // TODO: Calculated here implementing the logic in AudioTrack.java
    // wait for AudioTrack.java exposing this parameter (i.e. getFrameSizeInBtytes())
    jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
    int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);

    jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
    jmethodID jIsEncodingLinearFrames = env->GetStaticMethodID(
            jAudioFormatCls, "isEncodingLinearFrames", "(I)Z");
    jboolean javaIsEncodingLinearFrames = env->CallStaticBooleanMethod(
            jAudioFormatCls, jIsEncodingLinearFrames, javaFormat);

    if (javaIsEncodingLinearFrames == false) {
        return 1;
    }

    jmethodID jGetBytesPerSample = env->GetStaticMethodID(jAudioFormatCls,
            "getBytesPerSample", "(I)I");
    int javaBytesPerSample = env->CallStaticIntMethod(jAudioFormatCls,
            jGetBytesPerSample, javaFormat);

    jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
    int javaChannelCount = env->CallIntMethod(mAudioTrackObj, jGetChannelCount);

    return javaChannelCount * javaBytesPerSample;
}

status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
{
    String8 result;
@@ -432,10 +469,6 @@ status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
    // TODO: Remove logs that includes unavailable information from below.
//    result.appendFormat("  status(%d), state(%d), session Id(%d), flags(%#x)\n",
//                        mStatus, mState, mSessionId, mFlags);
//    result.appendFormat("  stream type(%d), left - right volume(%f, %f)\n",
//                        (mStreamType == AUDIO_STREAM_DEFAULT) ?
//                                audio_attributes_to_stream_type(&mAttributes) : mStreamType,
//                        mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
//    result.appendFormat("  format(%#x), channel mask(%#x), channel count(%u)\n",
//                  format(), mChannelMask, channelCount());
//    result.appendFormat("  sample rate(%u), original sample rate(%u), speed(%f)\n",
@@ -462,7 +495,7 @@ audio_port_handle_t JAudioTrack::getRoutedDeviceId() {
        return AUDIO_PORT_HANDLE_NONE;
    }

    jclass jAudioDeviceInfoCls = env->FindClass("Landroid/media/AudioDeviceInfo");
    jclass jAudioDeviceInfoCls = env->FindClass("android/media/AudioDeviceInfo");
    jmethodID jGetId = env->GetMethodID(jAudioDeviceInfoCls, "getId", "()I");
    jint routedDeviceId = env->CallIntMethod(jAudioDeviceInfoObj, jGetId);
    return routedDeviceId;
@@ -478,13 +511,22 @@ audio_session_t JAudioTrack::getAudioSessionId() {
status_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
    jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
    jmethodID jSetAudioOutputDeviceById = env->GetStaticMethodID(
            jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
    jboolean result = env->CallStaticBooleanMethod(
            jMP2ImplCls, jSetAudioOutputDeviceById, mAudioTrackObj, deviceId);
    return result == true ? NO_ERROR : BAD_VALUE;
}

audio_stream_type_t JAudioTrack::getAudioStreamType() {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
    jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
                                        "getVolumeControlStream", "()I");
    int javaAudioStreamType = env->CallIntMethod(mAudioAttributesObj, jGetVolumeControlStream);
    return (audio_stream_type_t)javaAudioStreamType;
}

status_t JAudioTrack::pendingDuration(int32_t *msec) {
    if (msec == nullptr) {
        return BAD_VALUE;
@@ -526,18 +568,85 @@ status_t JAudioTrack::pendingDuration(int32_t *msec) {
    return NO_ERROR;
}

status_t JAudioTrack::addAudioDeviceCallback(
        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
    // TODO: Implement this after appropriate Java AudioTrack method is available.
status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
            "addOnRoutingChangedListener",
            "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
    env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
    return NO_ERROR;
}

status_t JAudioTrack::removeAudioDeviceCallback(
        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
    // TODO: Implement this after appropriate Java AudioTrack method is available.
status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
            "removeOnRoutingChangedListener",
            "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
    env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
    return NO_ERROR;
}

void JAudioTrack::registerRoutingDelegates(
        std::vector<std::pair<jobject, jobject>>& routingDelegates) {
    for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
            it != routingDelegates.end(); it++) {
        addAudioDeviceCallback(it->second, getHandler(it->second));
    }
}

/////////////////////////////////////////////////////////////
///                Static methods begin                   ///
/////////////////////////////////////////////////////////////
jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
    jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
            "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
    return env->CallObjectMethod(routingDelegateObj, jGetListener);
}

jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
    jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
        "getHandler", "()Landroid/os/Handler;");
    return env->CallObjectMethod(routingDelegateObj, jGetHandler);
}

jobject JAudioTrack::addGlobalRef(const jobject obj) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
}

status_t JAudioTrack::removeGlobalRef(const jobject obj) {
    if (obj == NULL) {
        return BAD_VALUE;
    }
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    env->DeleteGlobalRef(obj);
    return NO_ERROR;
}

jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
        if (env->IsSameObject(it->first, key)) {
            return it->second;
        }
    }
    return nullptr;
}

void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
    JNIEnv *env = JavaVMHelper::getJNIEnv();
    for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
        if (env->IsSameObject(it->first, key)) {
            mp.erase(it);
            return;
        }
    }
}

/////////////////////////////////////////////////////////////
///                Private method begins                  ///
/////////////////////////////////////////////////////////////
+174 −195

File changed.

Preview size limit exceeded, changes collapsed.

+69 −17
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
#ifndef ANDROID_JAUDIOTRACK_H
#define ANDROID_JAUDIOTRACK_H

#include <vector>
#include <utility>
#include <jni.h>
#include <media/AudioResamplerPublic.h>
#include <media/AudioSystem.h>
@@ -29,7 +31,7 @@

namespace android {

class JAudioTrack {
class JAudioTrack : public RefBase {
public:

    /* Events used by AudioTrack callback function (callback_t).
@@ -37,6 +39,8 @@ public:
     */
    enum event_type {
        EVENT_MORE_DATA = 0,        // Request to write more data to buffer.
        EVENT_UNDERRUN = 1,         // Buffer underrun occurred. This will not occur for
                                    // static tracks.
        EVENT_NEW_IAUDIOTRACK = 6,  // IAudioTrack was re-created, either due to re-routing and
                                    // voluntary invalidation by mediaserver, or mediaserver crash.
        EVENT_STREAM_END = 7,       // Sent after all the buffers queued in AF and HW are played
@@ -104,8 +108,7 @@ public:
     *
     * TODO: Revive removed arguments after offload mode is supported.
     */
    JAudioTrack(audio_stream_type_t streamType,
                uint32_t sampleRate,
    JAudioTrack(uint32_t sampleRate,
                audio_format_t format,
                audio_channel_mask_t channelMask,
                callback_t cbf,
@@ -158,10 +161,10 @@ public:
     * Caution: calling this method too often may be inefficient;
     * if you need a high resolution mapping between frame position and presentation time,
     * consider implementing that at application level, based on the low resolution timestamps.
     * Returns true if timestamp is valid.
     * The timestamp parameter is undefined on return, if false is returned.
     * Returns NO_ERROR if timestamp is valid.
     *         NO_INIT if finds error, and timestamp parameter will be undefined on return.
     */
    bool getTimestamp(AudioTimestamp& timestamp);
    status_t getTimestamp(AudioTimestamp& timestamp);

    // TODO: This doc is just copied from AudioTrack.h. Revise it after implemenation.
    /* Return the extended timestamp, with additional timebase info and improved drain behavior.
@@ -324,6 +327,8 @@ public:

    audio_format_t format();

    size_t frameSize();

    /*
     * Dumps the state of an audio track.
     * Not a general-purpose API; intended only for use by media player service to dump its tracks.
@@ -355,6 +360,11 @@ public:
    /* Returns the flags */
    audio_output_flags_t getFlags() const { return mFlags; }

    /* We don't keep stream type here,
     * instead, we keep attributes and call getVolumeControlStream() to get stream type
     */
    audio_stream_type_t getAudioStreamType();

    /* Obtain the pending duration in milliseconds for playback of pure PCM data remaining in
     * AudioTrack.
     *
@@ -369,33 +379,75 @@ public:
     * Replaces any previously installed callback.
     *
     * Parameters:
     *
     * callback: The callback interface
     * Listener: the listener to receive notification of rerouting events.
     * Handler: the handler to handler the rerouting events.
     *
     * Returns NO_ERROR if successful.
     *         INVALID_OPERATION if the same callback is already installed.
     *         NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
     *         BAD_VALUE if the callback is NULL
     *         (TODO) INVALID_OPERATION if the same callback is already installed.
     *         (TODO) NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
     *         (TODO) BAD_VALUE if the callback is NULL
     */
    status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
    status_t addAudioDeviceCallback(jobject listener, jobject rd);

    /* Removes an AudioDeviceCallback.
     *
     * Parameters:
     *
     * callback: The callback interface
     * Listener: the listener to receive notification of rerouting events.
     *
     * Returns NO_ERROR if successful.
     *         INVALID_OPERATION if the callback is not installed
     *         BAD_VALUE if the callback is NULL
     *         (TODO) INVALID_OPERATION if the callback is not installed
     *         (TODO) BAD_VALUE if the callback is NULL
     */
    status_t removeAudioDeviceCallback(jobject listener);

    /* Register all backed-up routing delegates.
     *
     * Parameters:
     * routingDelegates: backed-up routing delegates
     *
     */
    void registerRoutingDelegates(std::vector<std::pair<jobject, jobject>>& routingDelegates);

    /* get listener from RoutingDelegate object
     */
    static jobject getListener(const jobject routingDelegateObj);

    /* get handler from RoutingDelegate object
     */
    static jobject getHandler(const jobject routingDelegateObj);

    /* convert local reference to global reference.
     */
    static jobject addGlobalRef(const jobject obj);

    /* erase global reference.
     *
     * Returns NO_ERROR if succeeds
     *         BAD_VALUE if obj is NULL
     */
    static status_t removeGlobalRef(const jobject obj);

    /*
     * Parameters:
     * map and key
     *
     * Returns value if key is in the map
     *         nullptr if key is not in the map
     */
    static jobject findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);

    /*
     * Parameters:
     * map and key
     */
    status_t removeAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
    static void eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key);

private:
    audio_output_flags_t mFlags;

    jclass mAudioTrackCls;
    jobject mAudioTrackObj;
    jobject mAudioAttributesObj;

    /* Creates a Java VolumeShaper.Configuration object from VolumeShaper::Configuration */
    jobject createVolumeShaperConfigurationObj(
Loading