blob: cb139c9be9f063d9137bb96e89b2b5dfe5de4c95 [file] [log] [blame]
Hyundo Moon660a74e2017-12-13 11:29:45 +09001/*
2 * Copyright 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "JAudioTrack"
18
19#include "media/JAudioAttributes.h"
20#include "media/JAudioFormat.h"
Wei Jia51b69562018-02-05 16:17:13 -080021#include "mediaplayer2/JAudioTrack.h"
Hyundo Moon660a74e2017-12-13 11:29:45 +090022
Hyundo Moon9b26e942017-12-14 10:46:54 +090023#include <android_media_AudioErrors.h>
Dongwon Kang8144aee2018-06-28 17:40:03 -070024#include <mediaplayer2/JavaVMHelper.h>
Hyundo Moon660a74e2017-12-13 11:29:45 +090025
26namespace android {
27
Hyundo Moon9b26e942017-12-14 10:46:54 +090028// TODO: Store Java class/methodID as a member variable in the class.
Hyundo Moon660a74e2017-12-13 11:29:45 +090029// TODO: Add NULL && Exception checks after every JNI call.
30JAudioTrack::JAudioTrack( // < Usages of the arguments are below >
Hyundo Moon660a74e2017-12-13 11:29:45 +090031 uint32_t sampleRate, // AudioFormat && bufferSizeInBytes
32 audio_format_t format, // AudioFormat && bufferSizeInBytes
33 audio_channel_mask_t channelMask, // AudioFormat && bufferSizeInBytes
Hyundo Moon42a6dec2018-01-22 19:26:47 +090034 callback_t cbf, // Offload
35 void* user, // Offload
Hyundo Moon660a74e2017-12-13 11:29:45 +090036 size_t frameCount, // bufferSizeInBytes
37 audio_session_t sessionId, // AudioTrack
Dichen Zhangc2465c52018-11-12 11:56:05 -080038 const jobject attributes, // AudioAttributes
Hyundo Moon660a74e2017-12-13 11:29:45 +090039 float maxRequiredSpeed) { // bufferSizeInBytes
40
Dongwon Kang8144aee2018-06-28 17:40:03 -070041 JNIEnv *env = JavaVMHelper::getJNIEnv();
Dichen Zhangf8726912018-10-17 13:31:26 -070042
Hyundo Moon660a74e2017-12-13 11:29:45 +090043 jclass jAudioTrackCls = env->FindClass("android/media/AudioTrack");
Dichen Zhangf8726912018-10-17 13:31:26 -070044 mAudioTrackCls = reinterpret_cast<jclass>(env->NewGlobalRef(jAudioTrackCls));
45 env->DeleteLocalRef(jAudioTrackCls);
Hyundo Moon660a74e2017-12-13 11:29:45 +090046
47 maxRequiredSpeed = std::min(std::max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
48
49 int bufferSizeInBytes = 0;
50 if (sampleRate == 0 || frameCount > 0) {
51 // Manually calculate buffer size.
52 bufferSizeInBytes = audio_channel_count_from_out_mask(channelMask)
53 * audio_bytes_per_sample(format) * (frameCount > 0 ? frameCount : 1);
54 } else if (sampleRate > 0) {
55 // Call Java AudioTrack::getMinBufferSize().
56 jmethodID jGetMinBufferSize =
Hyundo Moon9b26e942017-12-14 10:46:54 +090057 env->GetStaticMethodID(mAudioTrackCls, "getMinBufferSize", "(III)I");
58 bufferSizeInBytes = env->CallStaticIntMethod(mAudioTrackCls, jGetMinBufferSize,
Hyundo Moon660a74e2017-12-13 11:29:45 +090059 sampleRate, outChannelMaskFromNative(channelMask), audioFormatFromNative(format));
60 }
61 bufferSizeInBytes = (int) (bufferSizeInBytes * maxRequiredSpeed);
62
63 // Create a Java AudioTrack object through its Builder.
64 jclass jBuilderCls = env->FindClass("android/media/AudioTrack$Builder");
65 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
66 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
67
Dichen Zhangc2465c52018-11-12 11:56:05 -080068 if (attributes != NULL) {
69 mAudioAttributesObj = new JObjectHolder(attributes);
70 } else {
71 mAudioAttributesObj = new JObjectHolder(
72 JAudioAttributes::createAudioAttributesObj(env, NULL));
73 }
Dichen Zhangf8726912018-10-17 13:31:26 -070074
Hyundo Moon660a74e2017-12-13 11:29:45 +090075 jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
76 "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
Dichen Zhangc2465c52018-11-12 11:56:05 -080077 jBuilderObj = env->CallObjectMethod(jBuilderObj,
78 jSetAudioAttributes, mAudioAttributesObj->getJObject());
Hyundo Moon660a74e2017-12-13 11:29:45 +090079
80 jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
81 "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
82 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
83 JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
84
85 jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
86 "(I)Landroid/media/AudioTrack$Builder;");
87 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
88
89 // We only use streaming mode of Java AudioTrack.
Hyundo Moon9b26e942017-12-14 10:46:54 +090090 jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
91 jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
Hyundo Moon660a74e2017-12-13 11:29:45 +090092 jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
93 "(I)Landroid/media/AudioTrack$Builder;");
94 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
95 transferMode /* Java AudioTrack::MODE_STREAM */);
96
97 if (sessionId != 0) {
98 jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
99 "(I)Landroid/media/AudioTrack$Builder;");
100 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
101 }
102
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900103 if (cbf != NULL) {
104 jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
105 "(Z)Landroid/media/AudioTrack$Builder;");
106 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
107 mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
108 }
109
Hyundo Moon660a74e2017-12-13 11:29:45 +0900110 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
Dichen Zhangf8726912018-10-17 13:31:26 -0700111 jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
112 mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
113 env->DeleteLocalRef(jBuilderObj);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900114
115 if (cbf != NULL) {
116 // Set offload mode callback
117 jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
118 jobject jExecutorObj = createCallbackExecutor();
119 jmethodID jSetStreamEventCallback = env->GetMethodID(
120 jAudioTrackCls,
121 "setStreamEventCallback",
122 "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
123 env->CallVoidMethod(
124 mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
125 }
Hyundo Moon660a74e2017-12-13 11:29:45 +0900126}
127
Hyundo Moon9b26e942017-12-14 10:46:54 +0900128JAudioTrack::~JAudioTrack() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700129 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900130 env->DeleteGlobalRef(mAudioTrackCls);
Dichen Zhangf8726912018-10-17 13:31:26 -0700131 env->DeleteGlobalRef(mAudioTrackObj);
Hyundo Moon9b26e942017-12-14 10:46:54 +0900132}
133
134size_t JAudioTrack::frameCount() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700135 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900136 jmethodID jGetBufferSizeInFrames = env->GetMethodID(
137 mAudioTrackCls, "getBufferSizeInFrames", "()I");
138 return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
139}
140
141size_t JAudioTrack::channelCount() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700142 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900143 jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
144 return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
145}
146
Hyundo Moon904183e2018-01-21 20:43:41 +0900147uint32_t JAudioTrack::latency() {
148 // TODO: Currently hard-coded as returning zero.
149 return 0;
150}
151
Hyundo Moon9b26e942017-12-14 10:46:54 +0900152status_t JAudioTrack::getPosition(uint32_t *position) {
153 if (position == NULL) {
154 return BAD_VALUE;
155 }
156
Dongwon Kang8144aee2018-06-28 17:40:03 -0700157 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900158 jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
159 mAudioTrackCls, "getPlaybackHeadPosition", "()I");
160 *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
161
162 return NO_ERROR;
163}
164
Dichen Zhangf8726912018-10-17 13:31:26 -0700165status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700166 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900167
168 jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
169 jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
170
Dichen Zhangf8726912018-10-17 13:31:26 -0700171 jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
172 jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
Hyundo Moonfd328172017-12-14 10:46:54 +0900173
174 jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
Dichen Zhangf8726912018-10-17 13:31:26 -0700175 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
Hyundo Moonfd328172017-12-14 10:46:54 +0900176 bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
177
178 if (!success) {
Dichen Zhangf8726912018-10-17 13:31:26 -0700179 return NO_INIT;
Hyundo Moonfd328172017-12-14 10:46:54 +0900180 }
181
182 long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
183 long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
184
185 struct timespec ts;
186 const long long secondToNano = 1000000000LL; // 1E9
187 ts.tv_sec = nanoTime / secondToNano;
188 ts.tv_nsec = nanoTime % secondToNano;
189 timestamp.mTime = ts;
190 timestamp.mPosition = (uint32_t) framePosition;
191
Dichen Zhangf8726912018-10-17 13:31:26 -0700192 return NO_ERROR;
Hyundo Moonfd328172017-12-14 10:46:54 +0900193}
194
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900195status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
196 // TODO: Implement this after appropriate Java AudioTrack method is available.
197 return NO_ERROR;
198}
199
Hyundo Moonfd328172017-12-14 10:46:54 +0900200status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
201 // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
202 // Should we do the same thing?
Dongwon Kang8144aee2018-06-28 17:40:03 -0700203 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900204
205 jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
206 jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
207 jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
208
209 jmethodID jSetAudioFallbackMode = env->GetMethodID(
210 jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
211 jPlaybackParamsObj = env->CallObjectMethod(
212 jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
213
214 jmethodID jSetAudioStretchMode = env->GetMethodID(
215 jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
216 jPlaybackParamsObj = env->CallObjectMethod(
217 jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
218
219 jmethodID jSetPitch = env->GetMethodID(
220 jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
221 jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
222
223 jmethodID jSetSpeed = env->GetMethodID(
224 jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
225 jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
226
227
228 // Set this Java PlaybackParams object into Java AudioTrack.
229 jmethodID jSetPlaybackParams = env->GetMethodID(
230 mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
231 env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
232 // TODO: Should we catch the Java IllegalArgumentException?
233
234 return NO_ERROR;
235}
236
237const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700238 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900239
240 jmethodID jGetPlaybackParams = env->GetMethodID(
241 mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
242 jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
243
244 AudioPlaybackRate playbackRate;
245 jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
246
247 jmethodID jGetAudioFallbackMode = env->GetMethodID(
248 jPlaybackParamsCls, "getAudioFallbackMode", "()I");
249 // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
250 // The enum is internal only, so it is not defined in PlaybackParmas.java.
251 // TODO: Is this right way to convert an int to an enum?
252 playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
253 env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
254
255 jmethodID jGetAudioStretchMode = env->GetMethodID(
256 jPlaybackParamsCls, "getAudioStretchMode", "()I");
257 playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
258 env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
259
260 jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
261 playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
262
263 jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
264 playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
265
266 return playbackRate;
267}
268
269media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
270 const sp<media::VolumeShaper::Configuration>& configuration,
271 const sp<media::VolumeShaper::Operation>& operation) {
272
273 jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
274 jobject jOperationObj = createVolumeShaperOperationObj(operation);
275
276 if (jConfigurationObj == NULL || jOperationObj == NULL) {
277 return media::VolumeShaper::Status(BAD_VALUE);
278 }
279
Dongwon Kang8144aee2018-06-28 17:40:03 -0700280 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900281
282 jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
283 "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
284 jobject jVolumeShaperObj = env->CallObjectMethod(
285 mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
286
287 jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
288 jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
289 "(Landroid/media/VolumeShaper$Operation;)V");
290 env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
291
292 return media::VolumeShaper::Status(NO_ERROR);
293}
294
Hyundo Moon9b26e942017-12-14 10:46:54 +0900295status_t JAudioTrack::setAuxEffectSendLevel(float level) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700296 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900297 jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
298 mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
299 int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
300 return javaToNativeStatus(result);
301}
302
303status_t JAudioTrack::attachAuxEffect(int effectId) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700304 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900305 jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
306 int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
307 return javaToNativeStatus(result);
308}
309
310status_t JAudioTrack::setVolume(float left, float right) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700311 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900312 // TODO: Java setStereoVolume is deprecated. Do we really need this method?
313 jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
314 int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
315 return javaToNativeStatus(result);
316}
317
318status_t JAudioTrack::setVolume(float volume) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700319 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900320 jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
321 int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
322 return javaToNativeStatus(result);
323}
324
325status_t JAudioTrack::start() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700326 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900327 jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
328 // TODO: Should we catch the Java IllegalStateException from play()?
329 env->CallVoidMethod(mAudioTrackObj, jPlay);
330 return NO_ERROR;
331}
332
Hyundo Moonfd328172017-12-14 10:46:54 +0900333ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
334 if (buffer == NULL) {
335 return BAD_VALUE;
336 }
337
Dongwon Kang8144aee2018-06-28 17:40:03 -0700338 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900339 jbyteArray jAudioData = env->NewByteArray(size);
340 env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
341
342 jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
343 jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
344 jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
345
346 int writeMode = 0;
347 if (blocking) {
348 jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
349 writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
350 } else {
351 jfieldID jWriteNonBlocking = env->GetStaticFieldID(
352 mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
353 writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
354 }
355
356 jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
357 int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
358
359 if (result >= 0) {
360 return result;
361 } else {
362 return javaToNativeStatus(result);
363 }
364}
365
Hyundo Moon660a74e2017-12-13 11:29:45 +0900366void JAudioTrack::stop() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700367 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900368 jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
Hyundo Moon660a74e2017-12-13 11:29:45 +0900369 env->CallVoidMethod(mAudioTrackObj, jStop);
Hyundo Moon9b26e942017-12-14 10:46:54 +0900370 // TODO: Should we catch IllegalStateException?
371}
372
373// TODO: Is the right implementation?
374bool JAudioTrack::stopped() const {
375 return !isPlaying();
376}
377
378void JAudioTrack::flush() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700379 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900380 jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
381 env->CallVoidMethod(mAudioTrackObj, jFlush);
382}
383
384void JAudioTrack::pause() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700385 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900386 jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
387 env->CallVoidMethod(mAudioTrackObj, jPause);
388 // TODO: Should we catch IllegalStateException?
389}
390
391bool JAudioTrack::isPlaying() const {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700392 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900393 jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
394 int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
395
396 // TODO: In Java AudioTrack, there is no STOPPING state.
397 // This means while stopping, isPlaying() will return different value in two class.
398 // - in existing native AudioTrack: true
399 // - in JAudioTrack: false
400 // If not okay, also modify the implementation of stopped().
401 jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
402 int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
403 return currentPlayState == statePlaying;
404}
405
406uint32_t JAudioTrack::getSampleRate() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700407 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900408 jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
409 return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
410}
411
Hyundo Moonfd328172017-12-14 10:46:54 +0900412status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
413 if (duration == nullptr) {
414 return BAD_VALUE;
415 }
416
Dongwon Kang8144aee2018-06-28 17:40:03 -0700417 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900418 jmethodID jGetBufferSizeInFrames = env->GetMethodID(
419 mAudioTrackCls, "getBufferSizeInFrames", "()I");
420 int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
421
422 const double secondToMicro = 1000000LL; // 1E6
423 int sampleRate = JAudioTrack::getSampleRate();
424 float speed = JAudioTrack::getPlaybackRate().mSpeed;
425
426 *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
427 return NO_ERROR;
428}
429
Hyundo Moon9b26e942017-12-14 10:46:54 +0900430audio_format_t JAudioTrack::format() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700431 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900432 jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
433 int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
434 return audioFormatToNative(javaFormat);
435}
436
Dichen Zhangf8726912018-10-17 13:31:26 -0700437size_t JAudioTrack::frameSize() {
438 JNIEnv *env = JavaVMHelper::getJNIEnv();
439
440 // TODO: Calculated here implementing the logic in AudioTrack.java
441 // wait for AudioTrack.java exposing this parameter (i.e. getFrameSizeInBtytes())
442 jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
443 int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
444
445 jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
446 jmethodID jIsEncodingLinearFrames = env->GetStaticMethodID(
447 jAudioFormatCls, "isEncodingLinearFrames", "(I)Z");
448 jboolean javaIsEncodingLinearFrames = env->CallStaticBooleanMethod(
449 jAudioFormatCls, jIsEncodingLinearFrames, javaFormat);
450
451 if (javaIsEncodingLinearFrames == false) {
452 return 1;
453 }
454
455 jmethodID jGetBytesPerSample = env->GetStaticMethodID(jAudioFormatCls,
456 "getBytesPerSample", "(I)I");
457 int javaBytesPerSample = env->CallStaticIntMethod(jAudioFormatCls,
458 jGetBytesPerSample, javaFormat);
459
460 jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
461 int javaChannelCount = env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
462
463 return javaChannelCount * javaBytesPerSample;
464}
465
Hyundo Moon904183e2018-01-21 20:43:41 +0900466status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
467{
468 String8 result;
469
470 result.append(" JAudioTrack::dump\n");
471
472 // TODO: Remove logs that includes unavailable information from below.
473// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
474// mStatus, mState, mSessionId, mFlags);
Hyundo Moon904183e2018-01-21 20:43:41 +0900475// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
476// format(), mChannelMask, channelCount());
477// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
478// getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
479// result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
480// frameCount(), mReqFrameCount);
481// result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
482// " req. notif. per buff(%u)\n",
483// mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
484// result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
485// latency(), mSelectedDeviceId, getRoutedDeviceId());
486// result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
487// mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
488 ::write(fd, result.string(), result.size());
489 return NO_ERROR;
490}
491
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700492jobject JAudioTrack::getRoutedDevice() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700493 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon904183e2018-01-21 20:43:41 +0900494 jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
495 "()Landroid/media/AudioDeviceInfo;");
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700496 return env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
Hyundo Moon904183e2018-01-21 20:43:41 +0900497}
498
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900499audio_session_t JAudioTrack::getAudioSessionId() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700500 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900501 jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
502 jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
503 return (audio_session_t) sessionId;
504}
505
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700506status_t JAudioTrack::setPreferredDevice(jobject device) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700507 JNIEnv *env = JavaVMHelper::getJNIEnv();
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700508 jmethodID jSetPreferredDeviceId = env->GetMethodID(mAudioTrackCls, "setPreferredDevice",
509 "(Landroid/media/AudioDeviceInfo;)Z");
510 jboolean result = env->CallBooleanMethod(mAudioTrackObj, jSetPreferredDeviceId, device);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900511 return result == true ? NO_ERROR : BAD_VALUE;
512}
513
Dichen Zhangf8726912018-10-17 13:31:26 -0700514audio_stream_type_t JAudioTrack::getAudioStreamType() {
Dichen Zhangc2465c52018-11-12 11:56:05 -0800515 if (mAudioAttributesObj == NULL) {
516 return AUDIO_STREAM_DEFAULT;
517 }
Dichen Zhangf8726912018-10-17 13:31:26 -0700518 JNIEnv *env = JavaVMHelper::getJNIEnv();
519 jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
520 jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700521 "getVolumeControlStream", "()I");
Dichen Zhangc2465c52018-11-12 11:56:05 -0800522 int javaAudioStreamType = env->CallIntMethod(
523 mAudioAttributesObj->getJObject(), jGetVolumeControlStream);
Dichen Zhangf8726912018-10-17 13:31:26 -0700524 return (audio_stream_type_t)javaAudioStreamType;
525}
526
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900527status_t JAudioTrack::pendingDuration(int32_t *msec) {
528 if (msec == nullptr) {
529 return BAD_VALUE;
530 }
531
532 bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
533 if (!isPurePcmData) {
534 return INVALID_OPERATION;
535 }
536
537 // TODO: Need to know the difference btw. client and server time.
538 // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
539 // (copied from AudioTrack.cpp)
540
541// ExtendedTimestamp ets;
542// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
543// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
544// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
545// - ets.mPosition[location];
546// if (diff < 0) {
547// *msec = 0;
548// } else {
549// // ms is the playback time by frames
550// int64_t ms = (int64_t)((double)diff * 1000 /
551// ((double)mSampleRate * mPlaybackRate.mSpeed));
552// // clockdiff is the timestamp age (negative)
553// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
554// ets.mTimeNs[location]
555// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
556// - systemTime(SYSTEM_TIME_MONOTONIC);
557//
558// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
559// static const int NANOS_PER_MILLIS = 1000000;
560// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
561// }
562// return NO_ERROR;
563// }
564
565 return NO_ERROR;
566}
567
Dichen Zhangf8726912018-10-17 13:31:26 -0700568status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
569 JNIEnv *env = JavaVMHelper::getJNIEnv();
570 jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
571 "addOnRoutingChangedListener",
572 "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
573 env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900574 return NO_ERROR;
575}
576
Dichen Zhangf8726912018-10-17 13:31:26 -0700577status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
578 JNIEnv *env = JavaVMHelper::getJNIEnv();
579 jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
580 "removeOnRoutingChangedListener",
581 "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
582 env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900583 return NO_ERROR;
584}
585
Dichen Zhangf8726912018-10-17 13:31:26 -0700586void JAudioTrack::registerRoutingDelegates(
587 std::vector<std::pair<jobject, jobject>>& routingDelegates) {
588 for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
589 it != routingDelegates.end(); it++) {
590 addAudioDeviceCallback(it->second, getHandler(it->second));
591 }
592}
593
594/////////////////////////////////////////////////////////////
595/// Static methods begin ///
596/////////////////////////////////////////////////////////////
597jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
598 JNIEnv *env = JavaVMHelper::getJNIEnv();
599 jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
600 jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
601 "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
602 return env->CallObjectMethod(routingDelegateObj, jGetListener);
603}
604
605jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
606 JNIEnv *env = JavaVMHelper::getJNIEnv();
607 jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
608 jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
609 "getHandler", "()Landroid/os/Handler;");
610 return env->CallObjectMethod(routingDelegateObj, jGetHandler);
611}
612
613jobject JAudioTrack::addGlobalRef(const jobject obj) {
614 JNIEnv *env = JavaVMHelper::getJNIEnv();
615 return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
616}
617
618status_t JAudioTrack::removeGlobalRef(const jobject obj) {
619 if (obj == NULL) {
620 return BAD_VALUE;
621 }
622 JNIEnv *env = JavaVMHelper::getJNIEnv();
623 env->DeleteGlobalRef(obj);
624 return NO_ERROR;
625}
626
627jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
628 JNIEnv *env = JavaVMHelper::getJNIEnv();
629 for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
630 if (env->IsSameObject(it->first, key)) {
631 return it->second;
632 }
633 }
634 return nullptr;
635}
636
637void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
638 JNIEnv *env = JavaVMHelper::getJNIEnv();
639 for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
640 if (env->IsSameObject(it->first, key)) {
641 mp.erase(it);
642 return;
643 }
644 }
645}
646
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900647/////////////////////////////////////////////////////////////
648/// Private method begins ///
649/////////////////////////////////////////////////////////////
650
Hyundo Moonfd328172017-12-14 10:46:54 +0900651jobject JAudioTrack::createVolumeShaperConfigurationObj(
652 const sp<media::VolumeShaper::Configuration>& config) {
653
654 // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
655 if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
656 return NULL;
657 }
658
Dongwon Kang8144aee2018-06-28 17:40:03 -0700659 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900660
661 // Referenced "android_media_VolumeShaper.h".
662 jfloatArray xarray = nullptr;
663 jfloatArray yarray = nullptr;
664 if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
665 // convert curve arrays
666 xarray = env->NewFloatArray(config->size());
667 yarray = env->NewFloatArray(config->size());
668 float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
669 float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
670 float *xptr = x, *yptr = y;
671 for (const auto &pt : *config.get()) {
672 *xptr++ = pt.first;
673 *yptr++ = pt.second;
674 }
675 env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
676 env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
677 }
678
679 jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
680 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
681 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
682
683 jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
684 "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
685 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
686
687 jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
688 "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
689 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
690 config->getInterpolatorType());
691
692 jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
693 "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
694 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
695
696 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
697 "()Landroid/media/VolumeShaper$Configuration;");
698 return env->CallObjectMethod(jBuilderObj, jBuild);
699}
700
701jobject JAudioTrack::createVolumeShaperOperationObj(
702 const sp<media::VolumeShaper::Operation>& operation) {
703
Dongwon Kang8144aee2018-06-28 17:40:03 -0700704 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900705
706 jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
707 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
708 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
709
710 // Set XOffset
711 jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
712 "(F)Landroid/media/VolumeShaper$Operation$Builder;");
713 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
714
715 int32_t flags = operation->getFlags();
716
717 if (operation->getReplaceId() >= 0) {
718 jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
719 "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
720 bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
721 jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
722 }
723
724 if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
725 jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
726 "()Landroid/media/VolumeShaper$Operation$Builder;");
727 jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
728 }
729
730 // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
731 if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
732 jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
733 "()Landroid/media/VolumeShaper$Operation$Builder;");
734 jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
735 }
736
737 if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
738 jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
739 "()Landroid/media/VolumeShaper$Operation$Builder;");
740 jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
741 }
742
743 if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
744 jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
745 "()Landroid/media/VolumeShaper$Operation$Builder;");
746 jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
747 }
748
749 // TODO: Handle error case (can it be NULL?)
750 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
751 "()Landroid/media/VolumeShaper$Operation;");
752 return env->CallObjectMethod(jBuilderObj, jBuild);
753}
754
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900755jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700756 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900757 jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
758 jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
759 jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
760 return jCallbackObj;
761}
762
763jobject JAudioTrack::createCallbackExecutor() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700764 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900765 jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
766 jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
767 "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
768 jobject jSingleThreadExecutorObj =
769 env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
770 return jSingleThreadExecutorObj;
771}
772
Hyundo Moon9b26e942017-12-14 10:46:54 +0900773status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
774 switch (javaStatus) {
775 case AUDIO_JAVA_SUCCESS:
776 return NO_ERROR;
777 case AUDIO_JAVA_BAD_VALUE:
778 return BAD_VALUE;
779 case AUDIO_JAVA_INVALID_OPERATION:
780 return INVALID_OPERATION;
781 case AUDIO_JAVA_PERMISSION_DENIED:
782 return PERMISSION_DENIED;
783 case AUDIO_JAVA_NO_INIT:
784 return NO_INIT;
785 case AUDIO_JAVA_WOULD_BLOCK:
786 return WOULD_BLOCK;
787 case AUDIO_JAVA_DEAD_OBJECT:
788 return DEAD_OBJECT;
789 default:
790 return UNKNOWN_ERROR;
791 }
Hyundo Moon660a74e2017-12-13 11:29:45 +0900792}
793
794} // namespace android