Create constructor of JAudioTrack class

Bug: 70363744
Test: Built successfully (mmm libmedia -j48)
Change-Id: I51e0510039fca2e84d1ced103fea62156cd1e5c2
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 0b4fd25..59703b7 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -306,6 +306,7 @@
 
     srcs: [
         "AudioParameter.cpp",
+        "JAudioTrack.cpp",
         "MediaPlayer2Factory.cpp",
         "MediaPlayer2Manager.cpp",
         "TestPlayerStub.cpp",
@@ -314,6 +315,7 @@
     ],
 
     shared_libs: [
+        "libandroid_runtime",
         "libaudioclient",
         "libbinder",
         "libcutils",
diff --git a/media/libmedia/JAudioTrack.cpp b/media/libmedia/JAudioTrack.cpp
new file mode 100644
index 0000000..4ba9425
--- /dev/null
+++ b/media/libmedia/JAudioTrack.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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
diff --git a/media/libmedia/include/media/JAudioAttributes.h b/media/libmedia/include/media/JAudioAttributes.h
new file mode 100644
index 0000000..fb11435
--- /dev/null
+++ b/media/libmedia/include/media/JAudioAttributes.h
@@ -0,0 +1,77 @@
+/*
+ * 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
diff --git a/media/libmedia/include/media/JAudioFormat.h b/media/libmedia/include/media/JAudioFormat.h
new file mode 100644
index 0000000..00abdff
--- /dev/null
+++ b/media/libmedia/include/media/JAudioFormat.h
@@ -0,0 +1,66 @@
+/*
+ * 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
diff --git a/media/libmedia/include/media/JAudioTrack.h b/media/libmedia/include/media/JAudioTrack.h
new file mode 100644
index 0000000..fb29c24
--- /dev/null
+++ b/media/libmedia/include/media/JAudioTrack.h
@@ -0,0 +1,105 @@
+/*
+ * 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