1660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon/*
2660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * Copyright 2018 The Android Open Source Project
3660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon *
4660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * Licensed under the Apache License, Version 2.0 (the "License");
5660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * you may not use this file except in compliance with the License.
6660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * You may obtain a copy of the License at
7660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon *
8660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon *      http://www.apache.org/licenses/LICENSE-2.0
9660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon *
10660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * Unless required by applicable law or agreed to in writing, software
11660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * distributed under the License is distributed on an "AS IS" BASIS,
12660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * See the License for the specific language governing permissions and
14660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon * limitations under the License.
15660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon */
16660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
17660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon#define LOG_TAG "JAudioTrack"
18660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
19660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon#include "media/JAudioAttributes.h"
20660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon#include "media/JAudioFormat.h"
2151b6956bc8e09eb2237a10a401baebb35096e6abWei Jia#include "mediaplayer2/JAudioTrack.h"
22660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
239b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon#include <android_media_AudioErrors.h>
24660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon#include <android_runtime/AndroidRuntime.h>
25660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
26660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moonnamespace android {
27660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
289b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon// TODO: Store Java class/methodID as a member variable in the class.
29660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon// TODO: Add NULL && Exception checks after every JNI call.
30660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo MoonJAudioTrack::JAudioTrack(                             // < Usages of the arguments are below >
31660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        audio_stream_type_t streamType,               // AudioAudioAttributes
32660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        uint32_t sampleRate,                          // AudioFormat && bufferSizeInBytes
33660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        audio_format_t format,                        // AudioFormat && bufferSizeInBytes
34660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        audio_channel_mask_t channelMask,             // AudioFormat && bufferSizeInBytes
3542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        callback_t cbf,                               // Offload
3642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        void* user,                                   // Offload
37660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        size_t frameCount,                            // bufferSizeInBytes
38660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        audio_session_t sessionId,                    // AudioTrack
39660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        const audio_attributes_t* pAttributes,        // AudioAttributes
40660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        float maxRequiredSpeed) {                     // bufferSizeInBytes
41660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
42660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
43660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
449b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    mAudioTrackCls = (jclass) env->NewGlobalRef(jAudioTrackCls);
45660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
46660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
47660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
48660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    int bufferSizeInBytes = 0;
49660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    if (sampleRate == 0 || frameCount > 0) {
50660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        // Manually calculate buffer size.
51660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
52660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon                * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
53660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    } else if (sampleRate > 0) {
54660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        // Call Java AudioTrack::getMinBufferSize().
55660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        jmethodID jGetMinBufferSize =
569b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon                env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
579b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
58660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon                sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
59660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    }
60660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
61660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
62660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    // Create a Java AudioTrack object through its Builder.
63660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
64660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
65660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
66660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
67660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
68660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
69660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioAttributes,
70660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            JAudioAttributes::createAudioAttributesObj(env, pAttributes, streamType));
71660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
72660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
73660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
74660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
75660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
76660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
77660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
78660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            "(I)Landroid/media/AudioTrack$Builder;");
79660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
80660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
81660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    // We only use streaming mode of Java AudioTrack.
829b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
839b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
84660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
85660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            "(I)Landroid/media/AudioTrack$Builder;");
86660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
87660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon            transferMode /* Java AudioTrack::MODE_STREAM */);
88660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
89660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    if (sessionId != 0) {
90660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
91660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon                "(I)Landroid/media/AudioTrack$Builder;");
92660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
93660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    }
94660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
9542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    if (cbf != NULL) {
9642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
9742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon                "(Z)Landroid/media/AudioTrack$Builder;");
9842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
9942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
10042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    }
10142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
102660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
103660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    mAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
10442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
10542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    if (cbf != NULL) {
10642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        // Set offload mode callback
10742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
10842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        jobject jExecutorObj = createCallbackExecutor();
10942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        jmethodID jSetStreamEventCallback = env->GetMethodID(
11042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon                jAudioTrackCls,
11142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon                "setStreamEventCallback",
11242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon                "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
11342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        env->CallVoidMethod(
11442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon                mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
11542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    }
116660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon}
117660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
1189b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo MoonJAudioTrack::~JAudioTrack() {
1199b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
1209b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    env->DeleteGlobalRef(mAudioTrackCls);
1219b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
1229b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
1239b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonsize_t JAudioTrack::frameCount() {
1249b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
1259b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jGetBufferSizeInFrames = env->GetMethodID(
1269b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon            mAudioTrackCls, "getBufferSizeInFrames", "()I");
1279b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
1289b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
1299b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
1309b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonsize_t JAudioTrack::channelCount() {
1319b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
1329b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
1339b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
1349b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
1359b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
136904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moonuint32_t JAudioTrack::latency() {
137904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    // TODO: Currently hard-coded as returning zero.
138904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    return 0;
139904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon}
140904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon
1419b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::getPosition(uint32_t *position) {
1429b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    if (position == NULL) {
1439b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return BAD_VALUE;
1449b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    }
1459b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
1469b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
1479b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
1489b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon            mAudioTrackCls, "getPlaybackHeadPosition", "()I");
1499b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
1509b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
1519b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return NO_ERROR;
1529b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
1539b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
154904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moonbool JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
155fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
156fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
157fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
158fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
159fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
160fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "L");
161fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "L");
162fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
163fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
164fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "getTimestamp", "(Landroid/media/AudioTimestamp)B");
165fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
166fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
167fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (!success) {
168fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return false;
169fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
170fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
171fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
172fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
173fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
174fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    struct timespec ts;
175fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    const long long secondToNano = 1000000000LL; // 1E9
176fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    ts.tv_sec = nanoTime / secondToNano;
177fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    ts.tv_nsec = nanoTime % secondToNano;
178fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    timestamp.mTime = ts;
179fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    timestamp.mPosition = (uint32_t) framePosition;
180fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
181fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return true;
182fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
183fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
18442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonstatus_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
18542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    // TODO: Implement this after appropriate Java AudioTrack method is available.
18642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return NO_ERROR;
18742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
18842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
189fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonstatus_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
190fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
191fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // Should we do the same thing?
192fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
193fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
194fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
195fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
196fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
197fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
198fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetAudioFallbackMode = env->GetMethodID(
199fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
200fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jPlaybackParamsObj = env->CallObjectMethod(
201fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
202fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
203fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetAudioStretchMode = env->GetMethodID(
204fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
205fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jPlaybackParamsObj = env->CallObjectMethod(
206fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
207fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
208fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetPitch = env->GetMethodID(
209fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
210fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
211fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
212fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetSpeed = env->GetMethodID(
213fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
214fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
215fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
216fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
217fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // Set this Java PlaybackParams object into Java AudioTrack.
218fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetPlaybackParams = env->GetMethodID(
219fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
220fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
221fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: Should we catch the Java IllegalArgumentException?
222fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
223fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return NO_ERROR;
224fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
225fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
226fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonconst AudioPlaybackRate JAudioTrack::getPlaybackRate() {
227fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
228fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
229fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetPlaybackParams = env->GetMethodID(
230fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
231fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
232fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
233fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    AudioPlaybackRate playbackRate;
234fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
235fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
236fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetAudioFallbackMode = env->GetMethodID(
237fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsCls, "getAudioFallbackMode", "()I");
238fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
239fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    //       The enum is internal only, so it is not defined in PlaybackParmas.java.
240fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: Is this right way to convert an int to an enum?
241fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
242fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
243fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
244fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetAudioStretchMode = env->GetMethodID(
245fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            jPlaybackParamsCls, "getAudioStretchMode", "()I");
246fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
247fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
248fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
249fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
250fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
251fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
252fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
253fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
254fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
255fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return playbackRate;
256fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
257fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
258fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonmedia::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
259fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        const sp<media::VolumeShaper::Configuration>& configuration,
260fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        const sp<media::VolumeShaper::Operation>& operation) {
261fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
262fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
263fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jOperationObj = createVolumeShaperOperationObj(operation);
264fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
265fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (jConfigurationObj == NULL || jOperationObj == NULL) {
266fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return media::VolumeShaper::Status(BAD_VALUE);
267fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
268fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
269fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
270fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
271fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
272fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
273fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jVolumeShaperObj = env->CallObjectMethod(
274fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
275fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
276fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
277fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
278fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "(Landroid/media/VolumeShaper$Operation;)V");
279fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
280fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
281fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return media::VolumeShaper::Status(NO_ERROR);
282fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
283fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
2849b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::setAuxEffectSendLevel(float level) {
2859b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
2869b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
2879b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon            mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
2889b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
2899b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return javaToNativeStatus(result);
2909b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
2919b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
2929b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::attachAuxEffect(int effectId) {
2939b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
2949b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
2959b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
2969b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return javaToNativeStatus(result);
2979b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
2989b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
2999b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::setVolume(float left, float right) {
3009b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3019b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // TODO: Java setStereoVolume is deprecated. Do we really need this method?
3029b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
3039b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
3049b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return javaToNativeStatus(result);
3059b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3069b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3079b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::setVolume(float volume) {
3089b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3099b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
3109b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
3119b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return javaToNativeStatus(result);
3129b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3139b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3149b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::start() {
3159b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3169b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
3179b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // TODO: Should we catch the Java IllegalStateException from play()?
3189b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    env->CallVoidMethod(mAudioTrackObj, jPlay);
3199b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return NO_ERROR;
3209b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3219b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
322fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
323fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (buffer == NULL) {
324fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return BAD_VALUE;
325fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
326fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
327fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
328fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jbyteArray jAudioData = env->NewByteArray(size);
329fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
330fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
331fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
332fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
333fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
334fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
335fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    int writeMode = 0;
336fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (blocking) {
337fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
338fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
339fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    } else {
340fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jfieldID jWriteNonBlocking = env->GetStaticFieldID(
341fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
342fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
343fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
344fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
345fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
346fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
347fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
348fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (result >= 0) {
349fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return result;
350fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    } else {
351fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return javaToNativeStatus(result);
352fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
353fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
354fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
355660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moonvoid JAudioTrack::stop() {
356660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3579b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
358660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon    env->CallVoidMethod(mAudioTrackObj, jStop);
3599b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // TODO: Should we catch IllegalStateException?
3609b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3619b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3629b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon// TODO: Is the right implementation?
3639b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonbool JAudioTrack::stopped() const {
3649b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return !isPlaying();
3659b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3669b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3679b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonvoid JAudioTrack::flush() {
3689b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3699b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
3709b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    env->CallVoidMethod(mAudioTrackObj, jFlush);
3719b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3729b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3739b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonvoid JAudioTrack::pause() {
3749b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3759b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
3769b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    env->CallVoidMethod(mAudioTrackObj, jPause);
3779b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // TODO: Should we catch IllegalStateException?
3789b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3799b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3809b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonbool JAudioTrack::isPlaying() const {
3819b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3829b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
3839b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
3849b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3859b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // TODO: In Java AudioTrack, there is no STOPPING state.
3869b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // This means while stopping, isPlaying() will return different value in two class.
3879b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    //  - in existing native AudioTrack: true
3889b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    //  - in JAudioTrack: false
3899b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    // If not okay, also modify the implementation of stopped().
3909b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
3919b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
3929b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return currentPlayState == statePlaying;
3939b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
3949b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
3959b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonuint32_t JAudioTrack::getSampleRate() {
3969b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
3979b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
3989b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
3999b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
4009b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
401fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonstatus_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
402fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (duration == nullptr) {
403fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return BAD_VALUE;
404fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
405fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
406fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
407fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jGetBufferSizeInFrames = env->GetMethodID(
408fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            mAudioTrackCls, "getBufferSizeInFrames", "()I");
409fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
410fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
411fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    const double secondToMicro = 1000000LL; // 1E6
412fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    int sampleRate = JAudioTrack::getSampleRate();
413fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    float speed = JAudioTrack::getPlaybackRate().mSpeed;
414fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
415fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
416fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return NO_ERROR;
417fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
418fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
4199b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonaudio_format_t JAudioTrack::format() {
4209b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
4219b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
4229b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
4239b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    return audioFormatToNative(javaFormat);
4249b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon}
4259b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon
426904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moonstatus_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
427904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon{
428904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    String8 result;
429904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon
430904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    result.append(" JAudioTrack::dump\n");
431904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon
432904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    // TODO: Remove logs that includes unavailable information from below.
433904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  status(%d), state(%d), session Id(%d), flags(%#x)\n",
434904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                        mStatus, mState, mSessionId, mFlags);
435904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  stream type(%d), left - right volume(%f, %f)\n",
436904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                        (mStreamType == AUDIO_STREAM_DEFAULT) ?
437904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                                audio_attributes_to_stream_type(&mAttributes) : mStreamType,
438904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                        mVolume[AUDIO_INTERLEAVE_LEFT], mVolume[AUDIO_INTERLEAVE_RIGHT]);
439904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  format(%#x), channel mask(%#x), channel count(%u)\n",
440904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                  format(), mChannelMask, channelCount());
441904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  sample rate(%u), original sample rate(%u), speed(%f)\n",
442904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//            getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
443904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  frame count(%zu), req. frame count(%zu)\n",
444904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                  frameCount(), mReqFrameCount);
445904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  notif. frame count(%u), req. notif. frame count(%u),"
446904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//            " req. notif. per buff(%u)\n",
447904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//             mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
448904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  latency (%d), selected device Id(%d), routed device Id(%d)\n",
449904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                        latency(), mSelectedDeviceId, getRoutedDeviceId());
450904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//    result.appendFormat("  output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
451904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon//                        mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
452904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    ::write(fd, result.string(), result.size());
453904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    return NO_ERROR;
454904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon}
455904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon
456904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moonaudio_port_handle_t JAudioTrack::getRoutedDeviceId() {
457904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
458904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
459904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon            "()Landroid/media/AudioDeviceInfo;");
460904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    jobject jAudioDeviceInfoObj = env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
461904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    if (env->IsSameObject(jAudioDeviceInfoObj, NULL)) {
462904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon        return AUDIO_PORT_HANDLE_NONE;
463904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    }
464904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon
465904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    jclass jAudioDeviceInfoCls = env->FindClass("Landroid/media/AudioDeviceInfo");
466904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    jmethodID jGetId = env->GetMethodID(jAudioDeviceInfoCls, "getId", "()I");
467904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    jint routedDeviceId = env->CallIntMethod(jAudioDeviceInfoObj, jGetId);
468904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon    return routedDeviceId;
469904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon}
470904183eeeeb8e9f7345c3e5f517719d6b5c93128Hyundo Moon
47142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonaudio_session_t JAudioTrack::getAudioSessionId() {
47242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
47342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
47442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
47542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return (audio_session_t) sessionId;
47642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
47742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
47842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonstatus_t JAudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
47942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
48042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jclass jMP2ImplCls = env->FindClass("android/media/MediaPlayer2Impl");
48142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jmethodID jSetAudioOutputDeviceById = env->GetMethodID(
48242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon            jMP2ImplCls, "setAudioOutputDeviceById", "(Landroid/media/AudioTrack;I)Z");
48342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jboolean result = env->CallStaticBooleanMethod(
48442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon            jMP2ImplCls, jSetAudioOutputDeviceById, mAudioTrackObj, deviceId);
48542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return result == true ? NO_ERROR : BAD_VALUE;
48642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
48742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
48842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonstatus_t JAudioTrack::pendingDuration(int32_t *msec) {
48942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    if (msec == nullptr) {
49042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        return BAD_VALUE;
49142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    }
49242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
49342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
49442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    if (!isPurePcmData) {
49542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        return INVALID_OPERATION;
49642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    }
49742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
49842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    // TODO: Need to know the difference btw. client and server time.
49942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
50042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    // (copied from AudioTrack.cpp)
50142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
50242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//    ExtendedTimestamp ets;
50342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//    ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
50442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//    if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
50542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//        int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
50642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//                - ets.mPosition[location];
50742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//        if (diff < 0) {
50842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            *msec = 0;
50942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//        } else {
51042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            // ms is the playback time by frames
51142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            int64_t ms = (int64_t)((double)diff * 1000 /
51242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//                    ((double)mSampleRate * mPlaybackRate.mSpeed));
51342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            // clockdiff is the timestamp age (negative)
51442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
51542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//                    ets.mTimeNs[location]
51642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//                    + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
51742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//                    - systemTime(SYSTEM_TIME_MONOTONIC);
51842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//
51942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            //ALOGV("ms: %lld  clockdiff: %lld", (long long)ms, (long long)clockdiff);
52042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            static const int NANOS_PER_MILLIS = 1000000;
52142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//            *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
52242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//        }
52342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//        return NO_ERROR;
52442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon//    }
52542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
52642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return NO_ERROR;
52742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
52842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
52942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonstatus_t JAudioTrack::addAudioDeviceCallback(
53042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
53142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    // TODO: Implement this after appropriate Java AudioTrack method is available.
53242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return NO_ERROR;
53342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
53442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
53542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonstatus_t JAudioTrack::removeAudioDeviceCallback(
53642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon        const sp<AudioSystem::AudioDeviceCallback>& callback __unused) {
53742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    // TODO: Implement this after appropriate Java AudioTrack method is available.
53842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return NO_ERROR;
53942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
54042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
54142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon/////////////////////////////////////////////////////////////
54242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon///                Private method begins                  ///
54342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon/////////////////////////////////////////////////////////////
54442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
545fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonjobject JAudioTrack::createVolumeShaperConfigurationObj(
546fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        const sp<media::VolumeShaper::Configuration>& config) {
547fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
548fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
549fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
550fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        return NULL;
551fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
552fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
553fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
554fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
555fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // Referenced "android_media_VolumeShaper.h".
556fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jfloatArray xarray = nullptr;
557fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jfloatArray yarray = nullptr;
558fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
559fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        // convert curve arrays
560fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        xarray = env->NewFloatArray(config->size());
561fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        yarray = env->NewFloatArray(config->size());
562fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
563fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
564fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        float *xptr = x, *yptr = y;
565fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        for (const auto &pt : *config.get()) {
566fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            *xptr++ = pt.first;
567fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            *yptr++ = pt.second;
568fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        }
569fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
570fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
571fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
572fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
573fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
574fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
575fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
576fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
577fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
578fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
579fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
580fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
581fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
582fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
583fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
584fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            config->getInterpolatorType());
585fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
586fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
587fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
588fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
589fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
590fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
591fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "()Landroid/media/VolumeShaper$Configuration;");
592fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return env->CallObjectMethod(jBuilderObj, jBuild);
593fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
594fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
595fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moonjobject JAudioTrack::createVolumeShaperOperationObj(
596fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        const sp<media::VolumeShaper::Operation>& operation) {
597fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
598fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
599fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
600fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
601fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
602fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
603fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
604fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // Set XOffset
605fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
606fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "(F)Landroid/media/VolumeShaper$Operation$Builder;");
607fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
608fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
609fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    int32_t flags = operation->getFlags();
610fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
611fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (operation->getReplaceId() >= 0) {
612fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
613fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
614fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
615fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
616fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
617fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
618fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
619fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
620fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                "()Landroid/media/VolumeShaper$Operation$Builder;");
621fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
622fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
623fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
624fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
625fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
626fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
627fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                "()Landroid/media/VolumeShaper$Operation$Builder;");
628fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
629fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
630fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
631fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
632fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
633fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                "()Landroid/media/VolumeShaper$Operation$Builder;");
634fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
635fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
636fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
637fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
638fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
639fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon                "()Landroid/media/VolumeShaper$Operation$Builder;");
640fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon        jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
641fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    }
642fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
643fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    // TODO: Handle error case (can it be NULL?)
644fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
645fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon            "()Landroid/media/VolumeShaper$Operation;");
646fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon    return env->CallObjectMethod(jBuilderObj, jBuild);
647fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon}
648fd328170d288e337cb779b2ef14f9e4c5e860c6aHyundo Moon
64942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonjobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
65042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
65142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
65242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
65342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
65442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return jCallbackObj;
65542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
65642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
65742a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moonjobject JAudioTrack::createCallbackExecutor() {
65842a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    JNIEnv *env = AndroidRuntime::getJNIEnv();
65942a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
66042a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
66142a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon            "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
66242a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    jobject jSingleThreadExecutorObj =
66342a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon            env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
66442a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon    return jSingleThreadExecutorObj;
66542a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon}
66642a6decdd6c173a36e51c19d44849e6654eb60f9Hyundo Moon
6679b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moonstatus_t JAudioTrack::javaToNativeStatus(int javaStatus) {
6689b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    switch (javaStatus) {
6699b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_SUCCESS:
6709b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return NO_ERROR;
6719b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_BAD_VALUE:
6729b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return BAD_VALUE;
6739b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_INVALID_OPERATION:
6749b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return INVALID_OPERATION;
6759b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_PERMISSION_DENIED:
6769b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return PERMISSION_DENIED;
6779b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_NO_INIT:
6789b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return NO_INIT;
6799b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_WOULD_BLOCK:
6809b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return WOULD_BLOCK;
6819b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    case AUDIO_JAVA_DEAD_OBJECT:
6829b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return DEAD_OBJECT;
6839b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    default:
6849b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon        return UNKNOWN_ERROR;
6859b26e9467a77e2ee03f1d19e1dbf9671c3770286Hyundo Moon    }
686660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon}
687660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon
688660a74ebf0a8b5b6c79f9a016b202ccfaf815d3bHyundo Moon} // namespace android
689