blob: 3d6879e5326a92cf6a690f5f31183d90f87edd2e [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 Zhang23658642018-11-15 10:26:16 -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 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
Wei Jia48c16232018-11-17 17:22:59 -0800103 mFlags = AUDIO_OUTPUT_FLAG_NONE;
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900104 if (cbf != NULL) {
105 jmethodID jSetOffloadedPlayback = env->GetMethodID(jBuilderCls, "setOffloadedPlayback",
106 "(Z)Landroid/media/AudioTrack$Builder;");
107 jBuilderObj = env->CallObjectMethod(jBuilderObj, jSetOffloadedPlayback, true);
108 mFlags = AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
109 }
110
Hyundo Moon660a74e2017-12-13 11:29:45 +0900111 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build", "()Landroid/media/AudioTrack;");
Dichen Zhangf8726912018-10-17 13:31:26 -0700112 jobject jAudioTrackObj = env->CallObjectMethod(jBuilderObj, jBuild);
113 mAudioTrackObj = reinterpret_cast<jobject>(env->NewGlobalRef(jAudioTrackObj));
114 env->DeleteLocalRef(jBuilderObj);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900115
116 if (cbf != NULL) {
117 // Set offload mode callback
118 jobject jStreamEventCallbackObj = createStreamEventCallback(cbf, user);
119 jobject jExecutorObj = createCallbackExecutor();
120 jmethodID jSetStreamEventCallback = env->GetMethodID(
121 jAudioTrackCls,
122 "setStreamEventCallback",
123 "(Ljava/util/concurrent/Executor;Landroid/media/AudioTrack$StreamEventCallback;)V");
124 env->CallVoidMethod(
125 mAudioTrackObj, jSetStreamEventCallback, jExecutorObj, jStreamEventCallbackObj);
126 }
Hyundo Moon660a74e2017-12-13 11:29:45 +0900127}
128
Hyundo Moon9b26e942017-12-14 10:46:54 +0900129JAudioTrack::~JAudioTrack() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700130 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900131 env->DeleteGlobalRef(mAudioTrackCls);
Dichen Zhangf8726912018-10-17 13:31:26 -0700132 env->DeleteGlobalRef(mAudioTrackObj);
Hyundo Moon9b26e942017-12-14 10:46:54 +0900133}
134
135size_t JAudioTrack::frameCount() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700136 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900137 jmethodID jGetBufferSizeInFrames = env->GetMethodID(
138 mAudioTrackCls, "getBufferSizeInFrames", "()I");
139 return env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
140}
141
142size_t JAudioTrack::channelCount() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700143 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900144 jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
145 return env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
146}
147
Hyundo Moon904183e2018-01-21 20:43:41 +0900148uint32_t JAudioTrack::latency() {
149 // TODO: Currently hard-coded as returning zero.
150 return 0;
151}
152
Hyundo Moon9b26e942017-12-14 10:46:54 +0900153status_t JAudioTrack::getPosition(uint32_t *position) {
154 if (position == NULL) {
155 return BAD_VALUE;
156 }
157
Dongwon Kang8144aee2018-06-28 17:40:03 -0700158 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900159 jmethodID jGetPlaybackHeadPosition = env->GetMethodID(
160 mAudioTrackCls, "getPlaybackHeadPosition", "()I");
161 *position = env->CallIntMethod(mAudioTrackObj, jGetPlaybackHeadPosition);
162
163 return NO_ERROR;
164}
165
Dichen Zhangf8726912018-10-17 13:31:26 -0700166status_t JAudioTrack::getTimestamp(AudioTimestamp& timestamp) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700167 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900168
169 jclass jAudioTimeStampCls = env->FindClass("android/media/AudioTimestamp");
170 jobject jAudioTimeStampObj = env->AllocObject(jAudioTimeStampCls);
171
Dichen Zhangf8726912018-10-17 13:31:26 -0700172 jfieldID jFramePosition = env->GetFieldID(jAudioTimeStampCls, "framePosition", "J");
173 jfieldID jNanoTime = env->GetFieldID(jAudioTimeStampCls, "nanoTime", "J");
Hyundo Moonfd328172017-12-14 10:46:54 +0900174
175 jmethodID jGetTimestamp = env->GetMethodID(mAudioTrackCls,
Dichen Zhangf8726912018-10-17 13:31:26 -0700176 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z");
Hyundo Moonfd328172017-12-14 10:46:54 +0900177 bool success = env->CallBooleanMethod(mAudioTrackObj, jGetTimestamp, jAudioTimeStampObj);
178
179 if (!success) {
Dichen Zhangf8726912018-10-17 13:31:26 -0700180 return NO_INIT;
Hyundo Moonfd328172017-12-14 10:46:54 +0900181 }
182
183 long long framePosition = env->GetLongField(jAudioTimeStampObj, jFramePosition);
184 long long nanoTime = env->GetLongField(jAudioTimeStampObj, jNanoTime);
185
186 struct timespec ts;
187 const long long secondToNano = 1000000000LL; // 1E9
188 ts.tv_sec = nanoTime / secondToNano;
189 ts.tv_nsec = nanoTime % secondToNano;
190 timestamp.mTime = ts;
191 timestamp.mPosition = (uint32_t) framePosition;
192
Dichen Zhangf8726912018-10-17 13:31:26 -0700193 return NO_ERROR;
Hyundo Moonfd328172017-12-14 10:46:54 +0900194}
195
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900196status_t JAudioTrack::getTimestamp(ExtendedTimestamp *timestamp __unused) {
197 // TODO: Implement this after appropriate Java AudioTrack method is available.
198 return NO_ERROR;
199}
200
Hyundo Moonfd328172017-12-14 10:46:54 +0900201status_t JAudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) {
202 // TODO: existing native AudioTrack returns INVALID_OPERATION on offload/direct/fast tracks.
203 // Should we do the same thing?
Dongwon Kang8144aee2018-06-28 17:40:03 -0700204 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900205
206 jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
207 jmethodID jPlaybackParamsCtor = env->GetMethodID(jPlaybackParamsCls, "<init>", "()V");
208 jobject jPlaybackParamsObj = env->NewObject(jPlaybackParamsCls, jPlaybackParamsCtor);
209
210 jmethodID jSetAudioFallbackMode = env->GetMethodID(
211 jPlaybackParamsCls, "setAudioFallbackMode", "(I)Landroid/media/PlaybackParams;");
212 jPlaybackParamsObj = env->CallObjectMethod(
213 jPlaybackParamsObj, jSetAudioFallbackMode, playbackRate.mFallbackMode);
214
215 jmethodID jSetAudioStretchMode = env->GetMethodID(
216 jPlaybackParamsCls, "setAudioStretchMode", "(I)Landroid/media/PlaybackParams;");
217 jPlaybackParamsObj = env->CallObjectMethod(
218 jPlaybackParamsObj, jSetAudioStretchMode, playbackRate.mStretchMode);
219
220 jmethodID jSetPitch = env->GetMethodID(
221 jPlaybackParamsCls, "setPitch", "(F)Landroid/media/PlaybackParams;");
222 jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetPitch, playbackRate.mPitch);
223
224 jmethodID jSetSpeed = env->GetMethodID(
225 jPlaybackParamsCls, "setSpeed", "(F)Landroid/media/PlaybackParams;");
226 jPlaybackParamsObj = env->CallObjectMethod(jPlaybackParamsObj, jSetSpeed, playbackRate.mSpeed);
227
228
229 // Set this Java PlaybackParams object into Java AudioTrack.
230 jmethodID jSetPlaybackParams = env->GetMethodID(
231 mAudioTrackCls, "setPlaybackParams", "(Landroid/media/PlaybackParams;)V");
232 env->CallVoidMethod(mAudioTrackObj, jSetPlaybackParams, jPlaybackParamsObj);
233 // TODO: Should we catch the Java IllegalArgumentException?
234
235 return NO_ERROR;
236}
237
238const AudioPlaybackRate JAudioTrack::getPlaybackRate() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700239 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900240
241 jmethodID jGetPlaybackParams = env->GetMethodID(
242 mAudioTrackCls, "getPlaybackParams", "()Landroid/media/PlaybackParams;");
243 jobject jPlaybackParamsObj = env->CallObjectMethod(mAudioTrackObj, jGetPlaybackParams);
244
245 AudioPlaybackRate playbackRate;
246 jclass jPlaybackParamsCls = env->FindClass("android/media/PlaybackParams");
247
248 jmethodID jGetAudioFallbackMode = env->GetMethodID(
249 jPlaybackParamsCls, "getAudioFallbackMode", "()I");
250 // TODO: Should we enable passing AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT?
251 // The enum is internal only, so it is not defined in PlaybackParmas.java.
252 // TODO: Is this right way to convert an int to an enum?
253 playbackRate.mFallbackMode = static_cast<AudioTimestretchFallbackMode>(
254 env->CallIntMethod(jPlaybackParamsObj, jGetAudioFallbackMode));
255
256 jmethodID jGetAudioStretchMode = env->GetMethodID(
257 jPlaybackParamsCls, "getAudioStretchMode", "()I");
258 playbackRate.mStretchMode = static_cast<AudioTimestretchStretchMode>(
259 env->CallIntMethod(jPlaybackParamsObj, jGetAudioStretchMode));
260
261 jmethodID jGetPitch = env->GetMethodID(jPlaybackParamsCls, "getPitch", "()F");
262 playbackRate.mPitch = env->CallFloatMethod(jPlaybackParamsObj, jGetPitch);
263
264 jmethodID jGetSpeed = env->GetMethodID(jPlaybackParamsCls, "getSpeed", "()F");
265 playbackRate.mSpeed = env->CallFloatMethod(jPlaybackParamsObj, jGetSpeed);
266
267 return playbackRate;
268}
269
270media::VolumeShaper::Status JAudioTrack::applyVolumeShaper(
271 const sp<media::VolumeShaper::Configuration>& configuration,
272 const sp<media::VolumeShaper::Operation>& operation) {
273
274 jobject jConfigurationObj = createVolumeShaperConfigurationObj(configuration);
275 jobject jOperationObj = createVolumeShaperOperationObj(operation);
276
277 if (jConfigurationObj == NULL || jOperationObj == NULL) {
278 return media::VolumeShaper::Status(BAD_VALUE);
279 }
280
Dongwon Kang8144aee2018-06-28 17:40:03 -0700281 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900282
283 jmethodID jCreateVolumeShaper = env->GetMethodID(mAudioTrackCls, "createVolumeShaper",
284 "(Landroid/media/VolumeShaper$Configuration;)Landroid/media/VolumeShaper;");
285 jobject jVolumeShaperObj = env->CallObjectMethod(
286 mAudioTrackObj, jCreateVolumeShaper, jConfigurationObj);
287
288 jclass jVolumeShaperCls = env->FindClass("android/media/VolumeShaper");
289 jmethodID jApply = env->GetMethodID(jVolumeShaperCls, "apply",
290 "(Landroid/media/VolumeShaper$Operation;)V");
291 env->CallVoidMethod(jVolumeShaperObj, jApply, jOperationObj);
292
293 return media::VolumeShaper::Status(NO_ERROR);
294}
295
Hyundo Moon9b26e942017-12-14 10:46:54 +0900296status_t JAudioTrack::setAuxEffectSendLevel(float level) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700297 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900298 jmethodID jSetAuxEffectSendLevel = env->GetMethodID(
299 mAudioTrackCls, "setAuxEffectSendLevel", "(F)I");
300 int result = env->CallIntMethod(mAudioTrackObj, jSetAuxEffectSendLevel, level);
301 return javaToNativeStatus(result);
302}
303
304status_t JAudioTrack::attachAuxEffect(int effectId) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700305 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900306 jmethodID jAttachAuxEffect = env->GetMethodID(mAudioTrackCls, "attachAuxEffect", "(I)I");
307 int result = env->CallIntMethod(mAudioTrackObj, jAttachAuxEffect, effectId);
308 return javaToNativeStatus(result);
309}
310
311status_t JAudioTrack::setVolume(float left, float right) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700312 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900313 // TODO: Java setStereoVolume is deprecated. Do we really need this method?
314 jmethodID jSetStereoVolume = env->GetMethodID(mAudioTrackCls, "setStereoVolume", "(FF)I");
315 int result = env->CallIntMethod(mAudioTrackObj, jSetStereoVolume, left, right);
316 return javaToNativeStatus(result);
317}
318
319status_t JAudioTrack::setVolume(float volume) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700320 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900321 jmethodID jSetVolume = env->GetMethodID(mAudioTrackCls, "setVolume", "(F)I");
322 int result = env->CallIntMethod(mAudioTrackObj, jSetVolume, volume);
323 return javaToNativeStatus(result);
324}
325
326status_t JAudioTrack::start() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700327 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900328 jmethodID jPlay = env->GetMethodID(mAudioTrackCls, "play", "()V");
329 // TODO: Should we catch the Java IllegalStateException from play()?
330 env->CallVoidMethod(mAudioTrackObj, jPlay);
331 return NO_ERROR;
332}
333
Hyundo Moonfd328172017-12-14 10:46:54 +0900334ssize_t JAudioTrack::write(const void* buffer, size_t size, bool blocking) {
335 if (buffer == NULL) {
336 return BAD_VALUE;
337 }
338
Dongwon Kang8144aee2018-06-28 17:40:03 -0700339 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900340 jbyteArray jAudioData = env->NewByteArray(size);
341 env->SetByteArrayRegion(jAudioData, 0, size, (jbyte *) buffer);
342
343 jclass jByteBufferCls = env->FindClass("java/nio/ByteBuffer");
344 jmethodID jWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;");
345 jobject jByteBufferObj = env->CallStaticObjectMethod(jByteBufferCls, jWrap, jAudioData);
346
347 int writeMode = 0;
348 if (blocking) {
349 jfieldID jWriteBlocking = env->GetStaticFieldID(mAudioTrackCls, "WRITE_BLOCKING", "I");
350 writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteBlocking);
351 } else {
352 jfieldID jWriteNonBlocking = env->GetStaticFieldID(
353 mAudioTrackCls, "WRITE_NON_BLOCKING", "I");
354 writeMode = env->GetStaticIntField(mAudioTrackCls, jWriteNonBlocking);
355 }
356
357 jmethodID jWrite = env->GetMethodID(mAudioTrackCls, "write", "(Ljava/nio/ByteBuffer;II)I");
358 int result = env->CallIntMethod(mAudioTrackObj, jWrite, jByteBufferObj, size, writeMode);
359
360 if (result >= 0) {
361 return result;
362 } else {
363 return javaToNativeStatus(result);
364 }
365}
366
Hyundo Moon660a74e2017-12-13 11:29:45 +0900367void JAudioTrack::stop() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700368 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900369 jmethodID jStop = env->GetMethodID(mAudioTrackCls, "stop", "()V");
Hyundo Moon660a74e2017-12-13 11:29:45 +0900370 env->CallVoidMethod(mAudioTrackObj, jStop);
Hyundo Moon9b26e942017-12-14 10:46:54 +0900371 // TODO: Should we catch IllegalStateException?
372}
373
374// TODO: Is the right implementation?
375bool JAudioTrack::stopped() const {
376 return !isPlaying();
377}
378
379void JAudioTrack::flush() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700380 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900381 jmethodID jFlush = env->GetMethodID(mAudioTrackCls, "flush", "()V");
382 env->CallVoidMethod(mAudioTrackObj, jFlush);
383}
384
385void JAudioTrack::pause() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700386 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900387 jmethodID jPause = env->GetMethodID(mAudioTrackCls, "pause", "()V");
388 env->CallVoidMethod(mAudioTrackObj, jPause);
389 // TODO: Should we catch IllegalStateException?
390}
391
392bool JAudioTrack::isPlaying() const {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700393 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900394 jmethodID jGetPlayState = env->GetMethodID(mAudioTrackCls, "getPlayState", "()I");
395 int currentPlayState = env->CallIntMethod(mAudioTrackObj, jGetPlayState);
396
397 // TODO: In Java AudioTrack, there is no STOPPING state.
398 // This means while stopping, isPlaying() will return different value in two class.
399 // - in existing native AudioTrack: true
400 // - in JAudioTrack: false
401 // If not okay, also modify the implementation of stopped().
402 jfieldID jPlayStatePlaying = env->GetStaticFieldID(mAudioTrackCls, "PLAYSTATE_PLAYING", "I");
403 int statePlaying = env->GetStaticIntField(mAudioTrackCls, jPlayStatePlaying);
404 return currentPlayState == statePlaying;
405}
406
407uint32_t JAudioTrack::getSampleRate() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700408 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900409 jmethodID jGetSampleRate = env->GetMethodID(mAudioTrackCls, "getSampleRate", "()I");
410 return env->CallIntMethod(mAudioTrackObj, jGetSampleRate);
411}
412
Hyundo Moonfd328172017-12-14 10:46:54 +0900413status_t JAudioTrack::getBufferDurationInUs(int64_t *duration) {
414 if (duration == nullptr) {
415 return BAD_VALUE;
416 }
417
Dongwon Kang8144aee2018-06-28 17:40:03 -0700418 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900419 jmethodID jGetBufferSizeInFrames = env->GetMethodID(
420 mAudioTrackCls, "getBufferSizeInFrames", "()I");
421 int bufferSizeInFrames = env->CallIntMethod(mAudioTrackObj, jGetBufferSizeInFrames);
422
423 const double secondToMicro = 1000000LL; // 1E6
424 int sampleRate = JAudioTrack::getSampleRate();
425 float speed = JAudioTrack::getPlaybackRate().mSpeed;
426
427 *duration = (int64_t) (bufferSizeInFrames * secondToMicro / (sampleRate * speed));
428 return NO_ERROR;
429}
430
Hyundo Moon9b26e942017-12-14 10:46:54 +0900431audio_format_t JAudioTrack::format() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700432 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon9b26e942017-12-14 10:46:54 +0900433 jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
434 int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
435 return audioFormatToNative(javaFormat);
436}
437
Dichen Zhangf8726912018-10-17 13:31:26 -0700438size_t JAudioTrack::frameSize() {
439 JNIEnv *env = JavaVMHelper::getJNIEnv();
440
441 // TODO: Calculated here implementing the logic in AudioTrack.java
442 // wait for AudioTrack.java exposing this parameter (i.e. getFrameSizeInBtytes())
443 jmethodID jGetAudioFormat = env->GetMethodID(mAudioTrackCls, "getAudioFormat", "()I");
444 int javaFormat = env->CallIntMethod(mAudioTrackObj, jGetAudioFormat);
445
446 jclass jAudioFormatCls = env->FindClass("android/media/AudioFormat");
447 jmethodID jIsEncodingLinearFrames = env->GetStaticMethodID(
448 jAudioFormatCls, "isEncodingLinearFrames", "(I)Z");
449 jboolean javaIsEncodingLinearFrames = env->CallStaticBooleanMethod(
450 jAudioFormatCls, jIsEncodingLinearFrames, javaFormat);
451
452 if (javaIsEncodingLinearFrames == false) {
453 return 1;
454 }
455
456 jmethodID jGetBytesPerSample = env->GetStaticMethodID(jAudioFormatCls,
457 "getBytesPerSample", "(I)I");
458 int javaBytesPerSample = env->CallStaticIntMethod(jAudioFormatCls,
459 jGetBytesPerSample, javaFormat);
460
461 jmethodID jGetChannelCount = env->GetMethodID(mAudioTrackCls, "getChannelCount", "()I");
462 int javaChannelCount = env->CallIntMethod(mAudioTrackObj, jGetChannelCount);
463
464 return javaChannelCount * javaBytesPerSample;
465}
466
Hyundo Moon904183e2018-01-21 20:43:41 +0900467status_t JAudioTrack::dump(int fd, const Vector<String16>& args __unused) const
468{
469 String8 result;
470
471 result.append(" JAudioTrack::dump\n");
472
473 // TODO: Remove logs that includes unavailable information from below.
474// result.appendFormat(" status(%d), state(%d), session Id(%d), flags(%#x)\n",
475// mStatus, mState, mSessionId, mFlags);
Hyundo Moon904183e2018-01-21 20:43:41 +0900476// result.appendFormat(" format(%#x), channel mask(%#x), channel count(%u)\n",
477// format(), mChannelMask, channelCount());
478// result.appendFormat(" sample rate(%u), original sample rate(%u), speed(%f)\n",
479// getSampleRate(), mOriginalSampleRate, mPlaybackRate.mSpeed);
480// result.appendFormat(" frame count(%zu), req. frame count(%zu)\n",
481// frameCount(), mReqFrameCount);
482// result.appendFormat(" notif. frame count(%u), req. notif. frame count(%u),"
483// " req. notif. per buff(%u)\n",
484// mNotificationFramesAct, mNotificationFramesReq, mNotificationsPerBufferReq);
485// result.appendFormat(" latency (%d), selected device Id(%d), routed device Id(%d)\n",
486// latency(), mSelectedDeviceId, getRoutedDeviceId());
487// result.appendFormat(" output(%d) AF latency (%u) AF frame count(%zu) AF SampleRate(%u)\n",
488// mOutput, mAfLatency, mAfFrameCount, mAfSampleRate);
489 ::write(fd, result.string(), result.size());
490 return NO_ERROR;
491}
492
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700493jobject JAudioTrack::getRoutedDevice() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700494 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon904183e2018-01-21 20:43:41 +0900495 jmethodID jGetRoutedDevice = env->GetMethodID(mAudioTrackCls, "getRoutedDevice",
496 "()Landroid/media/AudioDeviceInfo;");
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700497 return env->CallObjectMethod(mAudioTrackObj, jGetRoutedDevice);
Hyundo Moon904183e2018-01-21 20:43:41 +0900498}
499
Dichen Zhang23658642018-11-15 10:26:16 -0800500int32_t JAudioTrack::getAudioSessionId() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700501 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900502 jmethodID jGetAudioSessionId = env->GetMethodID(mAudioTrackCls, "getAudioSessionId", "()I");
503 jint sessionId = env->CallIntMethod(mAudioTrackObj, jGetAudioSessionId);
Dichen Zhang23658642018-11-15 10:26:16 -0800504 return sessionId;
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900505}
506
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700507status_t JAudioTrack::setPreferredDevice(jobject device) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700508 JNIEnv *env = JavaVMHelper::getJNIEnv();
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700509 jmethodID jSetPreferredDeviceId = env->GetMethodID(mAudioTrackCls, "setPreferredDevice",
510 "(Landroid/media/AudioDeviceInfo;)Z");
511 jboolean result = env->CallBooleanMethod(mAudioTrackObj, jSetPreferredDeviceId, device);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900512 return result == true ? NO_ERROR : BAD_VALUE;
513}
514
Dichen Zhangf8726912018-10-17 13:31:26 -0700515audio_stream_type_t JAudioTrack::getAudioStreamType() {
Dichen Zhangc2465c52018-11-12 11:56:05 -0800516 if (mAudioAttributesObj == NULL) {
517 return AUDIO_STREAM_DEFAULT;
518 }
Dichen Zhangf8726912018-10-17 13:31:26 -0700519 JNIEnv *env = JavaVMHelper::getJNIEnv();
520 jclass jAudioAttributesCls = env->FindClass("android/media/AudioAttributes");
521 jmethodID jGetVolumeControlStream = env->GetMethodID(jAudioAttributesCls,
Dongwon Kang0d7042d2018-10-12 16:52:14 -0700522 "getVolumeControlStream", "()I");
Dichen Zhangc2465c52018-11-12 11:56:05 -0800523 int javaAudioStreamType = env->CallIntMethod(
524 mAudioAttributesObj->getJObject(), jGetVolumeControlStream);
Dichen Zhangf8726912018-10-17 13:31:26 -0700525 return (audio_stream_type_t)javaAudioStreamType;
526}
527
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900528status_t JAudioTrack::pendingDuration(int32_t *msec) {
529 if (msec == nullptr) {
530 return BAD_VALUE;
531 }
532
533 bool isPurePcmData = audio_is_linear_pcm(format()) && (getFlags() & AUDIO_FLAG_HW_AV_SYNC) == 0;
534 if (!isPurePcmData) {
535 return INVALID_OPERATION;
536 }
537
538 // TODO: Need to know the difference btw. client and server time.
539 // If getTimestamp(ExtendedTimestamp) is ready, and un-comment below and modify appropriately.
540 // (copied from AudioTrack.cpp)
541
542// ExtendedTimestamp ets;
543// ExtendedTimestamp::LOCATION location = ExtendedTimestamp::LOCATION_SERVER;
544// if (getTimestamp_l(&ets) == OK && ets.mTimeNs[location] > 0) {
545// int64_t diff = ets.mPosition[ExtendedTimestamp::LOCATION_CLIENT]
546// - ets.mPosition[location];
547// if (diff < 0) {
548// *msec = 0;
549// } else {
550// // ms is the playback time by frames
551// int64_t ms = (int64_t)((double)diff * 1000 /
552// ((double)mSampleRate * mPlaybackRate.mSpeed));
553// // clockdiff is the timestamp age (negative)
554// int64_t clockdiff = (mState != STATE_ACTIVE) ? 0 :
555// ets.mTimeNs[location]
556// + ets.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_MONOTONIC]
557// - systemTime(SYSTEM_TIME_MONOTONIC);
558//
559// //ALOGV("ms: %lld clockdiff: %lld", (long long)ms, (long long)clockdiff);
560// static const int NANOS_PER_MILLIS = 1000000;
561// *msec = (int32_t)(ms + clockdiff / NANOS_PER_MILLIS);
562// }
563// return NO_ERROR;
564// }
565
566 return NO_ERROR;
567}
568
Dichen Zhangf8726912018-10-17 13:31:26 -0700569status_t JAudioTrack::addAudioDeviceCallback(jobject listener, jobject handler) {
570 JNIEnv *env = JavaVMHelper::getJNIEnv();
571 jmethodID jAddOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
572 "addOnRoutingChangedListener",
573 "(Landroid/media/AudioRouting$OnRoutingChangedListener;Landroid/os/Handler;)V");
574 env->CallVoidMethod(mAudioTrackObj, jAddOnRoutingChangedListener, listener, handler);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900575 return NO_ERROR;
576}
577
Dichen Zhangf8726912018-10-17 13:31:26 -0700578status_t JAudioTrack::removeAudioDeviceCallback(jobject listener) {
579 JNIEnv *env = JavaVMHelper::getJNIEnv();
580 jmethodID jRemoveOnRoutingChangedListener = env->GetMethodID(mAudioTrackCls,
581 "removeOnRoutingChangedListener",
582 "(Landroid/media/AudioRouting$OnRoutingChangedListener;)V");
583 env->CallVoidMethod(mAudioTrackObj, jRemoveOnRoutingChangedListener, listener);
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900584 return NO_ERROR;
585}
586
Dichen Zhangf8726912018-10-17 13:31:26 -0700587void JAudioTrack::registerRoutingDelegates(
588 std::vector<std::pair<jobject, jobject>>& routingDelegates) {
589 for (std::vector<std::pair<jobject, jobject>>::iterator it = routingDelegates.begin();
590 it != routingDelegates.end(); it++) {
591 addAudioDeviceCallback(it->second, getHandler(it->second));
592 }
593}
594
595/////////////////////////////////////////////////////////////
596/// Static methods begin ///
597/////////////////////////////////////////////////////////////
598jobject JAudioTrack::getListener(const jobject routingDelegateObj) {
599 JNIEnv *env = JavaVMHelper::getJNIEnv();
600 jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
601 jmethodID jGetListener = env->GetMethodID(jRoutingDelegateCls,
602 "getListener", "()Landroid/media/AudioRouting$OnRoutingChangedListener;");
603 return env->CallObjectMethod(routingDelegateObj, jGetListener);
604}
605
606jobject JAudioTrack::getHandler(const jobject routingDelegateObj) {
607 JNIEnv *env = JavaVMHelper::getJNIEnv();
608 jclass jRoutingDelegateCls = env->FindClass("android/media/RoutingDelegate");
609 jmethodID jGetHandler = env->GetMethodID(jRoutingDelegateCls,
610 "getHandler", "()Landroid/os/Handler;");
611 return env->CallObjectMethod(routingDelegateObj, jGetHandler);
612}
613
614jobject JAudioTrack::addGlobalRef(const jobject obj) {
615 JNIEnv *env = JavaVMHelper::getJNIEnv();
616 return reinterpret_cast<jobject>(env->NewGlobalRef(obj));
617}
618
619status_t JAudioTrack::removeGlobalRef(const jobject obj) {
620 if (obj == NULL) {
621 return BAD_VALUE;
622 }
623 JNIEnv *env = JavaVMHelper::getJNIEnv();
624 env->DeleteGlobalRef(obj);
625 return NO_ERROR;
626}
627
628jobject JAudioTrack::findByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
629 JNIEnv *env = JavaVMHelper::getJNIEnv();
630 for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
631 if (env->IsSameObject(it->first, key)) {
632 return it->second;
633 }
634 }
635 return nullptr;
636}
637
638void JAudioTrack::eraseByKey(std::vector<std::pair<jobject, jobject>>& mp, const jobject key) {
639 JNIEnv *env = JavaVMHelper::getJNIEnv();
640 for (std::vector<std::pair<jobject, jobject>>::iterator it = mp.begin(); it != mp.end(); it++) {
641 if (env->IsSameObject(it->first, key)) {
642 mp.erase(it);
643 return;
644 }
645 }
646}
647
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900648/////////////////////////////////////////////////////////////
649/// Private method begins ///
650/////////////////////////////////////////////////////////////
651
Hyundo Moonfd328172017-12-14 10:46:54 +0900652jobject JAudioTrack::createVolumeShaperConfigurationObj(
653 const sp<media::VolumeShaper::Configuration>& config) {
654
655 // TODO: Java VolumeShaper's setId() / setOptionFlags() are hidden.
656 if (config == NULL || config->getType() == media::VolumeShaper::Configuration::TYPE_ID) {
657 return NULL;
658 }
659
Dongwon Kang8144aee2018-06-28 17:40:03 -0700660 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900661
662 // Referenced "android_media_VolumeShaper.h".
663 jfloatArray xarray = nullptr;
664 jfloatArray yarray = nullptr;
665 if (config->getType() == media::VolumeShaper::Configuration::TYPE_SCALE) {
666 // convert curve arrays
667 xarray = env->NewFloatArray(config->size());
668 yarray = env->NewFloatArray(config->size());
669 float * const x = env->GetFloatArrayElements(xarray, nullptr /* isCopy */);
670 float * const y = env->GetFloatArrayElements(yarray, nullptr /* isCopy */);
671 float *xptr = x, *yptr = y;
672 for (const auto &pt : *config.get()) {
673 *xptr++ = pt.first;
674 *yptr++ = pt.second;
675 }
676 env->ReleaseFloatArrayElements(xarray, x, 0 /* mode */);
677 env->ReleaseFloatArrayElements(yarray, y, 0 /* mode */);
678 }
679
680 jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Configuration$Builder");
681 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
682 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
683
684 jmethodID jSetDuration = env->GetMethodID(jBuilderCls, "setDuration",
685 "(L)Landroid/media/VolumeShaper$Configuration$Builder;");
686 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetDuration, (jlong) config->getDurationMs());
687
688 jmethodID jSetInterpolatorType = env->GetMethodID(jBuilderCls, "setInterpolatorType",
689 "(I)Landroid/media/VolumeShaper$Configuration$Builder;");
690 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetInterpolatorType,
691 config->getInterpolatorType());
692
693 jmethodID jSetCurve = env->GetMethodID(jBuilderCls, "setCurve",
694 "([F[F)Landroid/media/VolumeShaper$Configuration$Builder;");
695 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetCurve, xarray, yarray);
696
697 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
698 "()Landroid/media/VolumeShaper$Configuration;");
699 return env->CallObjectMethod(jBuilderObj, jBuild);
700}
701
702jobject JAudioTrack::createVolumeShaperOperationObj(
703 const sp<media::VolumeShaper::Operation>& operation) {
704
Dongwon Kang8144aee2018-06-28 17:40:03 -0700705 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moonfd328172017-12-14 10:46:54 +0900706
707 jclass jBuilderCls = env->FindClass("android/media/VolumeShaper$Operation$Builder");
708 jmethodID jBuilderCtor = env->GetMethodID(jBuilderCls, "<init>", "()V");
709 jobject jBuilderObj = env->NewObject(jBuilderCls, jBuilderCtor);
710
711 // Set XOffset
712 jmethodID jSetXOffset = env->GetMethodID(jBuilderCls, "setXOffset",
713 "(F)Landroid/media/VolumeShaper$Operation$Builder;");
714 jBuilderObj = env->CallObjectMethod(jBuilderCls, jSetXOffset, operation->getXOffset());
715
716 int32_t flags = operation->getFlags();
717
718 if (operation->getReplaceId() >= 0) {
719 jmethodID jReplace = env->GetMethodID(jBuilderCls, "replace",
720 "(IB)Landroid/media/VolumeShaper$Operation$Builder;");
721 bool join = (flags | media::VolumeShaper::Operation::FLAG_JOIN) != 0;
722 jBuilderObj = env->CallObjectMethod(jBuilderCls, jReplace, operation->getReplaceId(), join);
723 }
724
725 if (flags | media::VolumeShaper::Operation::FLAG_REVERSE) {
726 jmethodID jReverse = env->GetMethodID(jBuilderCls, "reverse",
727 "()Landroid/media/VolumeShaper$Operation$Builder;");
728 jBuilderObj = env->CallObjectMethod(jBuilderCls, jReverse);
729 }
730
731 // TODO: VolumeShaper Javadoc says "Do not call terminate() directly". Can we call this?
732 if (flags | media::VolumeShaper::Operation::FLAG_TERMINATE) {
733 jmethodID jTerminate = env->GetMethodID(jBuilderCls, "terminate",
734 "()Landroid/media/VolumeShaper$Operation$Builder;");
735 jBuilderObj = env->CallObjectMethod(jBuilderCls, jTerminate);
736 }
737
738 if (flags | media::VolumeShaper::Operation::FLAG_DELAY) {
739 jmethodID jDefer = env->GetMethodID(jBuilderCls, "defer",
740 "()Landroid/media/VolumeShaper$Operation$Builder;");
741 jBuilderObj = env->CallObjectMethod(jBuilderCls, jDefer);
742 }
743
744 if (flags | media::VolumeShaper::Operation::FLAG_CREATE_IF_NECESSARY) {
745 jmethodID jCreateIfNeeded = env->GetMethodID(jBuilderCls, "createIfNeeded",
746 "()Landroid/media/VolumeShaper$Operation$Builder;");
747 jBuilderObj = env->CallObjectMethod(jBuilderCls, jCreateIfNeeded);
748 }
749
750 // TODO: Handle error case (can it be NULL?)
751 jmethodID jBuild = env->GetMethodID(jBuilderCls, "build",
752 "()Landroid/media/VolumeShaper$Operation;");
753 return env->CallObjectMethod(jBuilderObj, jBuild);
754}
755
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900756jobject JAudioTrack::createStreamEventCallback(callback_t cbf, void* user) {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700757 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900758 jclass jCallbackCls = env->FindClass("android/media/MediaPlayer2Impl$StreamEventCallback");
759 jmethodID jCallbackCtor = env->GetMethodID(jCallbackCls, "<init>", "(JJJ)V");
760 jobject jCallbackObj = env->NewObject(jCallbackCls, jCallbackCtor, this, cbf, user);
761 return jCallbackObj;
762}
763
764jobject JAudioTrack::createCallbackExecutor() {
Dongwon Kang8144aee2018-06-28 17:40:03 -0700765 JNIEnv *env = JavaVMHelper::getJNIEnv();
Hyundo Moon42a6dec2018-01-22 19:26:47 +0900766 jclass jExecutorsCls = env->FindClass("java/util/concurrent/Executors");
767 jmethodID jNewSingleThreadExecutor = env->GetStaticMethodID(jExecutorsCls,
768 "newSingleThreadExecutor", "()Ljava/util/concurrent/ExecutorService;");
769 jobject jSingleThreadExecutorObj =
770 env->CallStaticObjectMethod(jExecutorsCls, jNewSingleThreadExecutor);
771 return jSingleThreadExecutorObj;
772}
773
Hyundo Moon9b26e942017-12-14 10:46:54 +0900774status_t JAudioTrack::javaToNativeStatus(int javaStatus) {
775 switch (javaStatus) {
776 case AUDIO_JAVA_SUCCESS:
777 return NO_ERROR;
778 case AUDIO_JAVA_BAD_VALUE:
779 return BAD_VALUE;
780 case AUDIO_JAVA_INVALID_OPERATION:
781 return INVALID_OPERATION;
782 case AUDIO_JAVA_PERMISSION_DENIED:
783 return PERMISSION_DENIED;
784 case AUDIO_JAVA_NO_INIT:
785 return NO_INIT;
786 case AUDIO_JAVA_WOULD_BLOCK:
787 return WOULD_BLOCK;
788 case AUDIO_JAVA_DEAD_OBJECT:
789 return DEAD_OBJECT;
790 default:
791 return UNKNOWN_ERROR;
792 }
Hyundo Moon660a74e2017-12-13 11:29:45 +0900793}
794
795} // namespace android