blob: 033ff4cb1d5d671463f3966b1797d2904ea101a6 [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
Dichen Zhang28d27f52018-11-19 14:08:39 -080037 int32_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 Zhang28d27f52018-11-19 14:08:39 -080068 {
69 sp<JObjectHolder> audioAttributesObj;
70 if (attributes != NULL) {
71 audioAttributesObj = new JObjectHolder(attributes);
72 } else {
73 audioAttributesObj = new JObjectHolder(
74 JAudioAttributes::createAudioAttributesObj(env, NULL));
75 }
76 jmethodID jSetAudioAttributes = env->GetMethodID(jBuilderCls, "setAudioAttributes",
77 "(Landroid/media/AudioAttributes;)Landroid/media/AudioTrack$Builder;");
78 jBuilderObj = env->CallObjectMethod(jBuilderObj,
79 jSetAudioAttributes, audioAttributesObj->getJObject());
Dichen Zhangc2465c52018-11-12 11:56:05 -080080 }
Dichen Zhangf8726912018-10-17 13:31:26 -070081
Hyundo Moon660a74e2017-12-13 11:29:45 +090082 jmethodID jSetAudioFormat = env->GetMethodID(jBuilderCls, "setAudioFormat",
83 "(Landroid/media/AudioFormat;)Landroid/media/AudioTrack$Builder;");
84 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetAudioFormat,
85 JAudioFormat::createAudioFormatObj(env, sampleRate, format, channelMask));
86
87 jmethodID jSetBufferSizeInBytes = env->GetMethodID(jBuilderCls, "setBufferSizeInBytes",
88 "(I)Landroid/media/AudioTrack$Builder;");
89 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetBufferSizeInBytes, bufferSizeInBytes);
90
91 // We only use streaming mode of Java AudioTrack.
Hyundo Moon9b26e942017-12-14 10:46:54 +090092 jfieldID jModeStream = env->GetStaticFieldID(mAudioTrackCls, "MODE_STREAM", "I");
93 jint transferMode = env->GetStaticIntField(mAudioTrackCls, jModeStream);
Hyundo Moon660a74e2017-12-13 11:29:45 +090094 jmethodID jSetTransferMode = env->GetMethodID(jBuilderCls, "setTransferMode",
95 "(I)Landroid/media/AudioTrack$Builder;");
96 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetTransferMode,
97 transferMode /* Java AudioTrack::MODE_STREAM */);
98
99 if (sessionId != 0) {
100 jmethodID jSetSessionId = env->GetMethodID(jBuilderCls, "setSessionId",
101 "(I)Landroid/media/AudioTrack$Builder;");
102 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetSessionId, sessionId);
103 }
104
Wei Jia48c16232018-11-17 17:22:59 -0800105 mFlags = AUDIO_OUTPUT_FLAG_NONE;
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900106 if (cbf != NULL) {
107 jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
108 "(Z)Landroid/media/AudioTrack$Builder;");
109 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
110 mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
111 }
112
Hyundo Moon660a74e2017-12-13 11:29:45 +0900113 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
Dichen Zhangf8726912018-10-17 13:31:26 -0700114 jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
115 mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
116 env->DeleteLocalRef(jBuilderObj);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900117
118 if (cbf != NULL) {
119 // Set offload mode callback
120 jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
121 jobject jExecutorObj = createCallbackExecutor();
122 jmethodID jSetStreamEventCallback = env->GetMethodID(
123 jAudioTrackCls,
124 "setStreamEventCallback",
125 "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
126 env->CallVoidMethod(
127 mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
128 }
Hyundo Moon660a74e2017-12-13 11:29:45 +0900129}
130
Hyundo Moon9b26e942017-12-14 10:46:54 +0900131JAudioTrack::~JAudioTrack() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700132 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900133 env->DeleteGlobalRef(mAudioTrackCls);
Dichen Zhangf8726912018-10-17 13:31:26 -0700134 env->DeleteGlobalRef(mAudioTrackObj);
Hyundo Moon9b26e942017-12-14 10:46:54 +0900135}
136
137size_t JAudioTrack::frameCount() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700138 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900139 jmethodID jGetBufferSizeInFrames = env->GetMethodID(
140 mAudioTrackCls, "getBufferSizeInFrames", "()I");
141 return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
142}
143
144size_t JAudioTrack::channelCount() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700145 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900146 jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
147 return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
148}
149
Hyundo Moon904183e2018-01-21 20:43:41 +0900150uint32_t JAudioTrack::latency() {
151 // TODO: Currently hard-coded as returning zero.
152 return 0;
153}
154
Hyundo Moon9b26e942017-12-14 10:46:54 +0900155status_t JAudioTrack::getPosition(uint32_t *position) {
156 if (position == NULL) {
157 return BAD_VALUE;
158 }
159
Dongwon Kang8144aee2018-06-28 17:40:03 -0700160 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900161 jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
162 mAudioTrackCls, "getPlaybackHeadPosition", "()I");
163 *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
164
165 return NO_ERROR;
166}
167
Dichen Zhangf8726912018-10-17 13:31:26 -0700168status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700169 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900170
171 jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
172 jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
173
Dichen Zhangf8726912018-10-17 13:31:26 -0700174 jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
175 jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
Hyundo Moonfd328172017-12-14 10:46:54 +0900176
177 jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
Dichen Zhangf8726912018-10-17 13:31:26 -0700178 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
Hyundo Moonfd328172017-12-14 10:46:54 +0900179 bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
180
181 if (!success) {
Dichen Zhangf8726912018-10-17 13:31:26 -0700182 return NO_INIT;
Hyundo Moonfd328172017-12-14 10:46:54 +0900183 }
184
185 long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
186 long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
187
188 struct timespec ts;
189 const long long secondToNano = 1000000000LL; // 1E9
190 ts.tv_sec = nanoTime / secondToNano;
191 ts.tv_nsec = nanoTime % secondToNano;
192 timestamp.mTime = ts;
193 timestamp.mPosition = (uint32_t) framePosition;
194
Dichen Zhangf8726912018-10-17 13:31:26 -0700195 return NO_ERROR;
Hyundo Moonfd328172017-12-14 10:46:54 +0900196}
197
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900198status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
199 // TODO: Implement this after appropriate Java AudioTrack method is available.
200 return NO_ERROR;
201}
202
Hyundo Moonfd328172017-12-14 10:46:54 +0900203status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
204 // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
205 // Should we do the same thing?
Dongwon Kang8144aee2018-06-28 17:40:03 -0700206 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900207
208 jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
209 jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
210 jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
211
212 jmethodID jSetAudioFallbackMode = env->GetMethodID(
213 jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
214 jPlaybackParamsObj = env->CallObjectMethod(
215 jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
216
217 jmethodID jSetAudioStretchMode = env->GetMethodID(
218 jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
219 jPlaybackParamsObj = env->CallObjectMethod(
220 jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
221
222 jmethodID jSetPitch = env->GetMethodID(
223 jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
224 jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
225
226 jmethodID jSetSpeed = env->GetMethodID(
227 jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
228 jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
229
230
231 // Set this Java PlaybackParams object into Java AudioTrack.
232 jmethodID jSetPlaybackParams = env->GetMethodID(
233 mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
234 env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
235 // TODO: Should we catch the Java IllegalArgumentException?
236
237 return NO_ERROR;
238}
239
240const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700241 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900242
243 jmethodID jGetPlaybackParams = env->GetMethodID(
244 mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
245 jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
246
247 AudioPlaybackRate playbackRate;
248 jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
249
250 jmethodID jGetAudioFallbackMode = env->GetMethodID(
251 jPlaybackParamsCls, "getAudioFallbackMode", "()I");
252 // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
253 // The enum is internal only, so it is not defined in PlaybackParmas.java.
254 // TODO: Is this right way to convert an int to an enum?
255 playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
256 env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
257
258 jmethodID jGetAudioStretchMode = env->GetMethodID(
259 jPlaybackParamsCls, "getAudioStretchMode", "()I");
260 playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
261 env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
262
263 jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
264 playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
265
266 jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
267 playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
268
269 return playbackRate;
270}
271
272media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
273 const sp<media::VolumeShaper::Configuration>& configuration,
274 const sp<media::VolumeShaper::Operation>& operation) {
275
276 jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
277 jobject jOperationObj = createVolumeShaperOperationObj(operation);
278
279 if (jConfigurationObj == NULL || jOperationObj == NULL) {
280 return media::VolumeShaper::Status(BAD_VALUE);
281 }
282
Dongwon Kang8144aee2018-06-28 17:40:03 -0700283 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900284
285 jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
286 "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
287 jobject jVolumeShaperObj = env->CallObjectMethod(
288 mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
289
290 jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
291 jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
292 "(Landroid/media/VolumeShaper$Operation;)V");
293 env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
294
295 return media::VolumeShaper::Status(NO_ERROR);
296}
297
Hyundo Moon9b26e942017-12-14 10:46:54 +0900298status_t JAudioTrack::setAuxEffectSendLevel(float level) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700299 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900300 jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
301 mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
302 int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
303 return javaToNativeStatus(result);
304}
305
306status_t JAudioTrack::attachAuxEffect(int effectId) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700307 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900308 jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
309 int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
310 return javaToNativeStatus(result);
311}
312
313status_t JAudioTrack::setVolume(float left, float right) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700314 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900315 // TODO: Java setStereoVolume is deprecated. Do we really need this method?
316 jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
317 int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
318 return javaToNativeStatus(result);
319}
320
321status_t JAudioTrack::setVolume(float volume) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700322 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900323 jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
324 int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
325 return javaToNativeStatus(result);
326}
327
328status_t JAudioTrack::start() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700329 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900330 jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
331 // TODO: Should we catch the Java IllegalStateException from play()?
332 env->CallVoidMethod(mAudioTrackObj, jPlay);
333 return NO_ERROR;
334}
335
Hyundo Moonfd328172017-12-14 10:46:54 +0900336ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
337 if (buffer == NULL) {
338 return BAD_VALUE;
339 }
340
Dongwon Kang8144aee2018-06-28 17:40:03 -0700341 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900342 jbyteArray jAudioData = env->NewByteArray(size);
343 env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
344
345 jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
346 jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
347 jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
348
349 int writeMode = 0;
350 if (blocking) {
351 jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
352 writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
353 } else {
354 jfieldID jWriteNonBlocking = env->GetStaticFieldID(
355 mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
356 writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
357 }
358
359 jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
360 int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
361
362 if (result >= 0) {
363 return result;
364 } else {
365 return javaToNativeStatus(result);
366 }
367}
368
Hyundo Moon660a74e2017-12-13 11:29:45 +0900369void JAudioTrack::stop() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700370 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900371 jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
Hyundo Moon660a74e2017-12-13 11:29:45 +0900372 env->CallVoidMethod(mAudioTrackObj, jStop);
Hyundo Moon9b26e942017-12-14 10:46:54 +0900373 // TODO: Should we catch IllegalStateException?
374}
375
376// TODO: Is the right implementation?
377bool JAudioTrack::stopped() const {
378 return !isPlaying();
379}
380
381void JAudioTrack::flush() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700382 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900383 jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
384 env->CallVoidMethod(mAudioTrackObj, jFlush);
385}
386
387void JAudioTrack::pause() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700388 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900389 jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
390 env->CallVoidMethod(mAudioTrackObj, jPause);
391 // TODO: Should we catch IllegalStateException?
392}
393
394bool JAudioTrack::isPlaying() const {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700395 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900396 jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
397 int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
398
399 // TODO: In Java AudioTrack, there is no STOPPING state.
400 // This means while stopping, isPlaying() will return different value in two class.
401 // - in existing native AudioTrack: true
402 // - in JAudioTrack: false
403 // If not okay, also modify the implementation of stopped().
404 jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
405 int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
406 return currentPlayState == statePlaying;
407}
408
409uint32_t JAudioTrack::getSampleRate() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700410 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900411 jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
412 return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
413}
414
Hyundo Moonfd328172017-12-14 10:46:54 +0900415status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
416 if (duration == nullptr) {
417 return BAD_VALUE;
418 }
419
Dongwon Kang8144aee2018-06-28 17:40:03 -0700420 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900421 jmethodID jGetBufferSizeInFrames = env->GetMethodID(
422 mAudioTrackCls, "getBufferSizeInFrames", "()I");
423 int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
424
425 const double secondToMicro = 1000000LL; // 1E6
426 int sampleRate = JAudioTrack::getSampleRate();
427 float speed = JAudioTrack::getPlaybackRate().mSpeed;
428
429 *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
430 return NO_ERROR;
431}
432
Hyundo Moon9b26e942017-12-14 10:46:54 +0900433audio_format_t JAudioTrack::format() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700434 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900435 jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
436 int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
437 return audioFormatToNative(javaFormat);
438}
439
Dichen Zhangf8726912018-10-17 13:31:26 -0700440size_t JAudioTrack::frameSize() {
441 JNIEnv *env = JavaVMHelper::getJNIEnv();
442
443 // TODO: Calculated here implementing the logic in AudioTrack.java
444 // wait for AudioTrack.java exposing this parameter (i.e. getFrameSizeInBtytes())
445 jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
446 int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
447
448 jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
449 jmethodID jIsEncodingLinearFrames = env->GetStaticMethodID(
450 jAudioFormatCls, "isEncodingLinearFrames", "(I)Z");
451 jboolean javaIsEncodingLinearFrames = env->CallStaticBooleanMethod(
452 jAudioFormatCls, jIsEncodingLinearFrames, javaFormat);
453
454 if (javaIsEncodingLinearFrames == false) {
455 return 1;
456 }
457
458 jmethodID jGetBytesPerSample = env->GetStaticMethodID(jAudioFormatCls,
459 "getBytesPerSample", "(I)I");
460 int javaBytesPerSample = env->CallStaticIntMethod(jAudioFormatCls,
461 jGetBytesPerSample, javaFormat);
462
463 jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
464 int javaChannelCount = env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
465
466 return javaChannelCount * javaBytesPerSample;
467}
468
Hyundo Moon904183e2018-01-21 20:43:41 +0900469status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
470{
471 String8 result;
472
473 result.append(" JAudioTrack::dump\n");
474
475 // TODO: Remove logs that includes unavailable information from below.
476// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
477// mStatus, mState, mSessionId, mFlags);
Hyundo Moon904183e2018-01-21 20:43:41 +0900478// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
479// format(), mChannelMask, channelCount());
480// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
481// getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
482// result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
483// frameCount(), mReqFrameCount);
484// result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
485// " req. notif. per buff(%u)\n",
486// mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
487// result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
488// latency(), mSelectedDeviceId, getRoutedDeviceId());
489// result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
490// mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
491 ::write(fd, result.string(), result.size());
492 return NO_ERROR;
493}
494
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700495jobject JAudioTrack::getRoutedDevice() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700496 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon904183e2018-01-21 20:43:41 +0900497 jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
498 "()Landroid/media/AudioDeviceInfo;");
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700499 return env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
Hyundo Moon904183e2018-01-21 20:43:41 +0900500}
501
Dichen Zhang23658642018-11-15 10:26:16 -0800502int32_t JAudioTrack::getAudioSessionId() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700503 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900504 jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
505 jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
Dichen Zhang23658642018-11-15 10:26:16 -0800506 return sessionId;
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900507}
508
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700509status_t JAudioTrack::setPreferredDevice(jobject device) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700510 JNIEnv *env = JavaVMHelper::getJNIEnv();
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700511 jmethodID jSetPreferredDeviceId = env->GetMethodID(mAudioTrackCls, "setPreferredDevice",
512 "(Landroid/media/AudioDeviceInfo;)Z");
513 jboolean result = env->CallBooleanMethod(mAudioTrackObj, jSetPreferredDeviceId, device);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900514 return result == true ? NO_ERROR : BAD_VALUE;
515}
516
Dichen Zhangf8726912018-10-17 13:31:26 -0700517audio_stream_type_t JAudioTrack::getAudioStreamType() {
518 JNIEnv *env = JavaVMHelper::getJNIEnv();
Dichen Zhang28d27f52018-11-19 14:08:39 -0800519 jmethodID jGetAudioAttributes = env->GetMethodID(mAudioTrackCls, "getAudioAttributes",
520 "()Landroid/media/AudioAttributes;");
521 jobject jAudioAttributes = env->CallObjectMethod(mAudioTrackObj, jGetAudioAttributes);
Dichen Zhangf8726912018-10-17 13:31:26 -0700522 jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
523 jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700524 "getVolumeControlStream", "()I");
Dichen Zhang28d27f52018-11-19 14:08:39 -0800525 int javaAudioStreamType = env->CallIntMethod(jAudioAttributes, jGetVolumeControlStream);
Dichen Zhangf8726912018-10-17 13:31:26 -0700526 return (audio_stream_type_t)javaAudioStreamType;
527}
528
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900529status_t JAudioTrack::pendingDuration(int32_t *msec) {
530 if (msec == nullptr) {
531 return BAD_VALUE;
532 }
533
534 bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
535 if (!isPurePcmData) {
536 return INVALID_OPERATION;
537 }
538
539 // TODO: Need to know the difference btw. client and server time.
540 // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
541 // (copied from AudioTrack.cpp)
542
543// ExtendedTimestamp ets;
544// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
545// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
546// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
547// - ets.mPosition[location];
548// if (diff < 0) {
549// *msec = 0;
550// } else {
551// // ms is the playback time by frames
552// int64_t ms = (int64_t)((double)diff * 1000 /
553// ((double)mSampleRate * mPlaybackRate.mSpeed));
554// // clockdiff is the timestamp age (negative)
555// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
556// ets.mTimeNs[location]
557// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
558// - systemTime(SYSTEM_TIME_MONOTONIC);
559//
560// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
561// static const int NANOS_PER_MILLIS = 1000000;
562// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
563// }
564// return NO_ERROR;
565// }
566
567 return NO_ERROR;
568}
569
Dichen Zhangf8726912018-10-17 13:31:26 -0700570status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
571 JNIEnv *env = JavaVMHelper::getJNIEnv();
572 jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
573 "addOnRoutingChangedListener",
574 "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
575 env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900576 return NO_ERROR;
577}
578
Dichen Zhangf8726912018-10-17 13:31:26 -0700579status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
580 JNIEnv *env = JavaVMHelper::getJNIEnv();
581 jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
582 "removeOnRoutingChangedListener",
583 "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
584 env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900585 return NO_ERROR;
586}
587
Dichen Zhangf8726912018-10-17 13:31:26 -0700588void JAudioTrack::registerRoutingDelegates(
589 std::vector<std::pair<jobject, jobject>>& routingDelegates) {
590 for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
591 it != routingDelegates.end(); it++) {
592 addAudioDeviceCallback(it->second, getHandler(it->second));
593 }
594}
595
596/////////////////////////////////////////////////////////////
597/// Static methods begin ///
598/////////////////////////////////////////////////////////////
599jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
600 JNIEnv *env = JavaVMHelper::getJNIEnv();
601 jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
602 jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
603 "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
604 return env->CallObjectMethod(routingDelegateObj, jGetListener);
605}
606
607jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
608 JNIEnv *env = JavaVMHelper::getJNIEnv();
609 jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
610 jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
611 "getHandler", "()Landroid/os/Handler;");
612 return env->CallObjectMethod(routingDelegateObj, jGetHandler);
613}
614
615jobject JAudioTrack::addGlobalRef(const jobject obj) {
616 JNIEnv *env = JavaVMHelper::getJNIEnv();
617 return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
618}
619
620status_t JAudioTrack::removeGlobalRef(const jobject obj) {
621 if (obj == NULL) {
622 return BAD_VALUE;
623 }
624 JNIEnv *env = JavaVMHelper::getJNIEnv();
625 env->DeleteGlobalRef(obj);
626 return NO_ERROR;
627}
628
629jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
630 JNIEnv *env = JavaVMHelper::getJNIEnv();
631 for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
632 if (env->IsSameObject(it->first, key)) {
633 return it->second;
634 }
635 }
636 return nullptr;
637}
638
639void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
640 JNIEnv *env = JavaVMHelper::getJNIEnv();
641 for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
642 if (env->IsSameObject(it->first, key)) {
643 mp.erase(it);
644 return;
645 }
646 }
647}
648
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900649/////////////////////////////////////////////////////////////
650/// Private method begins ///
651/////////////////////////////////////////////////////////////
652
Hyundo Moonfd328172017-12-14 10:46:54 +0900653jobject JAudioTrack::createVolumeShaperConfigurationObj(
654 const sp<media::VolumeShaper::Configuration>& config) {
655
656 // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
657 if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
658 return NULL;
659 }
660
Dongwon Kang8144aee2018-06-28 17:40:03 -0700661 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900662
663 // Referenced "android_media_VolumeShaper.h".
664 jfloatArray xarray = nullptr;
665 jfloatArray yarray = nullptr;
666 if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
667 // convert curve arrays
668 xarray = env->NewFloatArray(config->size());
669 yarray = env->NewFloatArray(config->size());
670 float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
671 float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
672 float *xptr = x, *yptr = y;
673 for (const auto &pt : *config.get()) {
674 *xptr++ = pt.first;
675 *yptr++ = pt.second;
676 }
677 env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
678 env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
679 }
680
681 jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
682 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
683 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
684
685 jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
686 "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
687 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
688
689 jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
690 "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
691 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
692 config->getInterpolatorType());
693
694 jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
695 "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
696 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
697
698 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
699 "()Landroid/media/VolumeShaper$Configuration;");
700 return env->CallObjectMethod(jBuilderObj, jBuild);
701}
702
703jobject JAudioTrack::createVolumeShaperOperationObj(
704 const sp<media::VolumeShaper::Operation>& operation) {
705
Dongwon Kang8144aee2018-06-28 17:40:03 -0700706 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900707
708 jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
709 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
710 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
711
712 // Set XOffset
713 jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
714 "(F)Landroid/media/VolumeShaper$Operation$Builder;");
715 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
716
717 int32_t flags = operation->getFlags();
718
719 if (operation->getReplaceId() >= 0) {
720 jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
721 "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
722 bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
723 jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
724 }
725
726 if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
727 jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
728 "()Landroid/media/VolumeShaper$Operation$Builder;");
729 jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
730 }
731
732 // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
733 if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
734 jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
735 "()Landroid/media/VolumeShaper$Operation$Builder;");
736 jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
737 }
738
739 if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
740 jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
741 "()Landroid/media/VolumeShaper$Operation$Builder;");
742 jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
743 }
744
745 if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
746 jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
747 "()Landroid/media/VolumeShaper$Operation$Builder;");
748 jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
749 }
750
751 // TODO: Handle error case (can it be NULL?)
752 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
753 "()Landroid/media/VolumeShaper$Operation;");
754 return env->CallObjectMethod(jBuilderObj, jBuild);
755}
756
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900757jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700758 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900759 jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
760 jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
761 jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
762 return jCallbackObj;
763}
764
765jobject JAudioTrack::createCallbackExecutor() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700766 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900767 jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
768 jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
769 "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
770 jobject jSingleThreadExecutorObj =
771 env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
772 return jSingleThreadExecutorObj;
773}
774
Hyundo Moon9b26e942017-12-14 10:46:54 +0900775status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
776 switch (javaStatus) {
777 case AUDIO_JAVA_SUCCESS:
778 return NO_ERROR;
779 case AUDIO_JAVA_BAD_VALUE:
780 return BAD_VALUE;
781 case AUDIO_JAVA_INVALID_OPERATION:
782 return INVALID_OPERATION;
783 case AUDIO_JAVA_PERMISSION_DENIED:
784 return PERMISSION_DENIED;
785 case AUDIO_JAVA_NO_INIT:
786 return NO_INIT;
787 case AUDIO_JAVA_WOULD_BLOCK:
788 return WOULD_BLOCK;
789 case AUDIO_JAVA_DEAD_OBJECT:
790 return DEAD_OBJECT;
791 default:
792 return UNKNOWN_ERROR;
793 }
Hyundo Moon660a74e2017-12-13 11:29:45 +0900794}
795
796} // namespace android