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

Commit 660a74eb authored by Hyundo Moon's avatar Hyundo Moon
Browse files

Create constructor of JAudioTrack class

Bug: 70363744
Test: Built successfully (mmm libmedia -j48)
Change-Id: I51e0510039fca2e84d1ced103fea62156cd1e5c2
parent fddc1453
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -306,6 +306,7 @@ cc_library_shared {

    srcs: [
        "AudioParameter.cpp",
        "JAudioTrack.cpp",
        "MediaPlayer2Factory.cpp",
        "MediaPlayer2Manager.cpp",
        "TestPlayerStub.cpp",
@@ -314,6 +315,7 @@ cc_library_shared {
    ],

    shared_libs: [
        "libandroid_runtime",
        "libaudioclient",
        "libbinder",
        "libcutils",
+102 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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_TAG "JAudioTrack"

#include "media/JAudioAttributes.h"
#include "media/JAudioFormat.h"
#include "media/JAudioTrack.h"

#include <android_runtime/AndroidRuntime.h>
#include <media/AudioResamplerPublic.h>

namespace android {

// 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
        size_t frameCount,                            // bufferSizeInBytes
        audio_session_t sessionId,                    // AudioTrack
        const audio_attributes_t* pAttributes,        // AudioAttributes
        float maxRequiredSpeed) {                     // bufferSizeInBytes

    JNIEnv *env = AndroidRuntime::getJNIEnv();
    jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");

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

    int bufferSizeInBytes = 0;
    if (sampleRate == 0 || frameCount > 0) {
        // Manually calculate buffer size.
        bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
                * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
    } else if (sampleRate > 0) {
        // Call Java AudioTrack::getMinBufferSize().
        jmethodID jGetMinBufferSize =
                env->GetStaticMethodID(jAudioTrackCls, "getMinBufferSize", "(III)I");
        bufferSizeInBytes = env->CallStaticIntMethod(jAudioTrackCls, jGetMinBufferSize,
                sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
    }
    bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);

    // Create a Java AudioTrack object through its Builder.
    jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);

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

    jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
            "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
            JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));

    jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
            "(I)Landroid/media/AudioTrack$Builder;");
    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);

    // We only use streaming mode of Java AudioTrack.
    jfieldID jModeStream = env->GetStaticFieldID(jAudioTrackCls, "MODE_STREAM", "I");
    jint transferMode = env->GetStaticIntField(jAudioTrackCls, jModeStream);
    jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
            "(I)Landroid/media/AudioTrack$Builder;");
    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
            transferMode /* Java AudioTrack::MODE_STREAM */);

    if (sessionId != 0) {
        jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
                "(I)Landroid/media/AudioTrack$Builder;");
        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
    }

    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
    mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
}

void JAudioTrack::stop() {
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
    jmethodID jStop = env->GetMethodID(jAudioTrackCls, "stop", "()V");
    env->CallVoidMethod(mAudioTrackObj, jStop);
}

} // namespace android
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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.
 */

#ifndef ANDROID_JAUDIOATTRIBUTES_H
#define ANDROID_JAUDIOATTRIBUTES_H

#include <jni.h>
#include <system/audio.h>

namespace android {

class JAudioAttributes {
public:
    /* Creates a Java AudioAttributes object. */
    static jobject createAudioAttributesObj(JNIEnv *env,
                                            const audio_attributes_t* pAttributes,
                                            audio_stream_type_t streamType) {

        jclass jBuilderCls = env->FindClass("android/media/AudioAttributes$Builder");
        jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
        jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);

        if (pAttributes != NULL) {
            // If pAttributes is not null, streamType is ignored.
            jmethodID jSetUsage = env->GetMethodID(
                    jBuilderCls, "setUsage", "(I)Landroid/media/AudioAttributes$Builder;");
            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetUsage, pAttributes->usage);

            jmethodID jSetContentType = env->GetMethodID(jBuilderCls, "setContentType",
                    "(I)Landroid/media/AudioAttributes$Builder;");
            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetContentType,
                    pAttributes->content_type);

            // TODO: Java AudioAttributes.Builder.setCapturePreset() is systemApi and hidden.
            // Can we use this method?
//            jmethodID jSetCapturePreset = env->GetMethodID(jBuilderCls, "setCapturePreset",
//                    "(I)Landroid/media/AudioAttributes$Builder;");
//            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetCapturePreset,
//                    pAttributes->source);

            jmethodID jSetFlags = env->GetMethodID(jBuilderCls, "setFlags",
                    "(I)Landroid/media/AudioAttributes$Builder;");
            jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetFlags, pAttributes->flags);

            // 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",
                "()Landroid/media/AudioAttributes;");
        return env->CallObjectMethod(jBuilderObj, jBuild);
    }

};

} // namespace android

#endif // ANDROID_JAUDIOATTRIBUTES_H
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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.
 */

#ifndef ANDROID_JAUDIOFORMAT_H
#define ANDROID_JAUDIOFORMAT_H

#include <android_media_AudioFormat.h>
#include <jni.h>

namespace android {

class JAudioFormat {
public:
    /* Creates a Java AudioFormat object. */
    static jobject createAudioFormatObj(JNIEnv *env,
                                        uint32_t sampleRate,
                                        audio_format_t format,
                                        audio_channel_mask_t channelMask) {

        jclass jBuilderCls = env->FindClass("android/media/AudioFormat$Builder");
        jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
        jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);

        if (sampleRate == 0) {
            jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
            jfieldID jSampleRateUnspecified =
                    env->GetStaticFieldID(jAudioFormatCls, "SAMPLE_RATE_UNSPECIFIED", "I");
            sampleRate = env->GetStaticIntField(jAudioFormatCls, jSampleRateUnspecified);
        }

        jmethodID jSetEncoding = env->GetMethodID(jBuilderCls, "setEncoding",
                "(I)Landroid/media/AudioFormat$Builder;");
        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetEncoding,
                audioFormatFromNative(format));

        jmethodID jSetSampleRate = env->GetMethodID(jBuilderCls, "setSampleRate",
                "(I)Landroid/media/AudioFormat$Builder;");
        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSampleRate, sampleRate);

        jmethodID jSetChannelMask = env->GetMethodID(jBuilderCls, "setChannelMask",
                "(I)Landroid/media/AudioFormat$Builder;");
        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetChannelMask,
                outChannelMaskFromNative(channelMask));

        jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioFormat;");
        return env->CallObjectMethod(jBuilderObj, jBuild);
    }

};

} // namespace android

#endif // ANDROID_JAUDIOFORMAT_H
+105 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 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.
 */

#ifndef ANDROID_JAUDIOTRACK_H
#define ANDROID_JAUDIOTRACK_H

#include <jni.h>
#include <system/audio.h>

namespace android {

class JAudioTrack {
public:

    /* Creates an JAudioTrack object for non-offload mode.
     * Once created, the track needs to be started before it can be used.
     * Unspecified values are set to appropriate default values.
     *
     * Parameters:
     *
     * streamType:         Select the type of audio stream this track is attached to
     *                     (e.g. AUDIO_STREAM_MUSIC).
     * sampleRate:         Data source sampling rate in Hz.  Zero means to use the sink sample rate.
     *                     A non-zero value must be specified if AUDIO_OUTPUT_FLAG_DIRECT is set.
     *                     0 will not work with current policy implementation for direct output
     *                     selection where an exact match is needed for sampling rate.
     *                     (TODO: Check direct output after flags can be used in Java AudioTrack.)
     * format:             Audio format. For mixed tracks, any PCM format supported by server is OK.
     *                     For direct and offloaded tracks, the possible format(s) depends on the
     *                     output sink.
     *                     (TODO: How can we check whether a format is supported?)
     * channelMask:        Channel mask, such that audio_is_output_channel(channelMask) is true.
     * frameCount:         Minimum size of track PCM buffer in frames. This defines the
     *                     application's contribution to the latency of the track.
     *                     The actual size selected by the JAudioTrack could be larger if the
     *                     requested size is not compatible with current audio HAL configuration.
     *                     Zero means to use a default value.
     * sessionId:          Specific session ID, or zero to use default.
     * pAttributes:        If not NULL, supersedes streamType for use case selection.
     * maxRequiredSpeed:   For PCM tracks, this creates an appropriate buffer size that will allow
     *                     maxRequiredSpeed playback. Values less than 1.0f and greater than
     *                     AUDIO_TIMESTRETCH_SPEED_MAX will be clamped.  For non-PCM tracks
     *                     and direct or offloaded tracks, this parameter is ignored.
     *                     (TODO: Handle this after offload / direct track is supported.)
     *
     * TODO: Revive removed arguments after offload mode is supported.
     */
    JAudioTrack(audio_stream_type_t streamType,
                uint32_t sampleRate,
                audio_format_t format,
                audio_channel_mask_t channelMask,
                size_t frameCount = 0,
                audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
                const audio_attributes_t* pAttributes = NULL,
                float maxRequiredSpeed = 1.0f);

    /*
       Temporarily removed constructor arguments:

       // Q. Values are in audio-base.h, but where can we find explanation for them?
       audio_output_flags_t flags,

       // Q. May be used in AudioTrack.setPreferredDevice(AudioDeviceInfo)?
       audio_port_handle_t selectedDeviceId,

       // Should be deleted, since we don't use Binder anymore.
       bool doNotReconnect,

       // Do we need UID and PID?
       uid_t uid,
       pid_t pid,

       // TODO: Uses these values when Java AudioTrack supports the offload mode.
       callback_t cbf,
       void* user,
       int32_t notificationFrames,
       const audio_offload_info_t *offloadInfo,

       // Fixed to false, but what is this?
       threadCanCallJava
    */

    void stop();

protected:
    jobject mAudioTrackObj;         // Java AudioTrack object

};

}; // namespace android

#endif // ANDROID_JAUDIOTRACK_H