1 /*
2 **
3 ** Copyright 2007, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 //#define LOG_NDEBUG 0
19 #define LOG_TAG "MediaPlayer-JNI"
20 #include "utils/Log.h"
21
22 #include <media/mediaplayer.h>
23 #include <media/AudioResamplerPublic.h>
24 #include <media/IMediaHTTPService.h>
25 #include <media/MediaPlayerInterface.h>
26 #include <media/MediaAnalyticsItem.h>
27 #include <media/stagefright/foundation/ByteUtils.h> // for FOURCC definition
28 #include <stdio.h>
29 #include <assert.h>
30 #include <limits.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <utils/threads.h>
34 #include "jni.h"
35 #include <nativehelper/JNIHelp.h>
36 #include "android_runtime/AndroidRuntime.h"
37 #include "android_runtime/android_view_Surface.h"
38 #include "android_runtime/Log.h"
39 #include "utils/Errors.h" // for status_t
40 #include "utils/KeyedVector.h"
41 #include "utils/String8.h"
42 #include "android_media_BufferingParams.h"
43 #include "android_media_MediaDataSource.h"
44 #include "android_media_MediaMetricsJNI.h"
45 #include "android_media_PlaybackParams.h"
46 #include "android_media_SyncParams.h"
47 #include "android_media_VolumeShaper.h"
48 #include "android_media_Utils.h"
49
50 #include "android_os_Parcel.h"
51 #include "android_util_Binder.h"
52 #include <binder/Parcel.h>
53 #include <gui/IGraphicBufferProducer.h>
54 #include <gui/Surface.h>
55 #include <binder/IPCThreadState.h>
56 #include <binder/IServiceManager.h>
57
58 #include "android_util_Binder.h"
59
60 // Modular DRM begin
61 #define FIND_CLASS(var, className) \
62 var = env->FindClass(className); \
63 LOG_FATAL_IF(! (var), "Unable to find class " className);
64
65 #define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
66 var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
67 LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
68
69 struct StateExceptionFields {
70 jmethodID init;
71 jclass classId;
72 };
73
74 static StateExceptionFields gStateExceptionFields;
75 // Modular DRM end
76
77 // ----------------------------------------------------------------------------
78
79 using namespace android;
80
81 using media::VolumeShaper;
82
83 // ----------------------------------------------------------------------------
84
85 struct fields_t {
86 jfieldID context;
87 jfieldID surface_texture;
88
89 jmethodID post_event;
90
91 jmethodID proxyConfigGetHost;
92 jmethodID proxyConfigGetPort;
93 jmethodID proxyConfigGetExclusionList;
94 };
95 static fields_t fields;
96
97 static BufferingParams::fields_t gBufferingParamsFields;
98 static PlaybackParams::fields_t gPlaybackParamsFields;
99 static SyncParams::fields_t gSyncParamsFields;
100 static VolumeShaperHelper::fields_t gVolumeShaperFields;
101
102 static Mutex sLock;
103
104 // ----------------------------------------------------------------------------
105 // ref-counted object for callbacks
106 class JNIMediaPlayerListener: public MediaPlayerListener
107 {
108 public:
109 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
110 ~JNIMediaPlayerListener();
111 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
112 private:
113 JNIMediaPlayerListener();
114 jclass mClass; // Reference to MediaPlayer class
115 jobject mObject; // Weak ref to MediaPlayer Java object to call on
116 };
117
JNIMediaPlayerListener(JNIEnv * env,jobject thiz,jobject weak_thiz)118 JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
119 {
120
121 // Hold onto the MediaPlayer class for use in calling the static method
122 // that posts events to the application thread.
123 jclass clazz = env->GetObjectClass(thiz);
124 if (clazz == NULL) {
125 ALOGE("Can't find android/media/MediaPlayer");
126 jniThrowException(env, "java/lang/Exception", NULL);
127 return;
128 }
129 mClass = (jclass)env->NewGlobalRef(clazz);
130
131 // We use a weak reference so the MediaPlayer object can be garbage collected.
132 // The reference is only used as a proxy for callbacks.
133 mObject = env->NewGlobalRef(weak_thiz);
134 }
135
~JNIMediaPlayerListener()136 JNIMediaPlayerListener::~JNIMediaPlayerListener()
137 {
138 // remove global references
139 JNIEnv *env = AndroidRuntime::getJNIEnv();
140 env->DeleteGlobalRef(mObject);
141 env->DeleteGlobalRef(mClass);
142 }
143
notify(int msg,int ext1,int ext2,const Parcel * obj)144 void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
145 {
146 JNIEnv *env = AndroidRuntime::getJNIEnv();
147 if (obj && obj->dataSize() > 0) {
148 jobject jParcel = createJavaParcelObject(env);
149 if (jParcel != NULL) {
150 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
151 nativeParcel->setData(obj->data(), obj->dataSize());
152 env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
153 msg, ext1, ext2, jParcel);
154 env->DeleteLocalRef(jParcel);
155 }
156 } else {
157 env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
158 msg, ext1, ext2, NULL);
159 }
160 if (env->ExceptionCheck()) {
161 ALOGW("An exception occurred while notifying an event.");
162 LOGW_EX(env);
163 env->ExceptionClear();
164 }
165 }
166
167 // ----------------------------------------------------------------------------
168
getMediaPlayer(JNIEnv * env,jobject thiz)169 static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
170 {
171 Mutex::Autolock l(sLock);
172 MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
173 return sp<MediaPlayer>(p);
174 }
175
setMediaPlayer(JNIEnv * env,jobject thiz,const sp<MediaPlayer> & player)176 static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
177 {
178 Mutex::Autolock l(sLock);
179 sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
180 if (player.get()) {
181 player->incStrong((void*)setMediaPlayer);
182 }
183 if (old != 0) {
184 old->decStrong((void*)setMediaPlayer);
185 }
186 env->SetLongField(thiz, fields.context, (jlong)player.get());
187 return old;
188 }
189
190 // If exception is NULL and opStatus is not OK, this method sends an error
191 // event to the client application; otherwise, if exception is not NULL and
192 // opStatus is not OK, this method throws the given exception to the client
193 // application.
process_media_player_call(JNIEnv * env,jobject thiz,status_t opStatus,const char * exception,const char * message)194 static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
195 {
196 if (exception == NULL) { // Don't throw exception. Instead, send an event.
197 if (opStatus != (status_t) OK) {
198 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
199 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
200 }
201 } else { // Throw exception!
202 if ( opStatus == (status_t) INVALID_OPERATION ) {
203 jniThrowException(env, "java/lang/IllegalStateException", NULL);
204 } else if ( opStatus == (status_t) BAD_VALUE ) {
205 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
206 } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
207 jniThrowException(env, "java/lang/SecurityException", NULL);
208 } else if ( opStatus != (status_t) OK ) {
209 if (strlen(message) > 230) {
210 // if the message is too long, don't bother displaying the status code
211 jniThrowException( env, exception, message);
212 } else {
213 char msg[256];
214 // append the status code to the message
215 sprintf(msg, "%s: status=0x%X", message, opStatus);
216 jniThrowException( env, exception, msg);
217 }
218 }
219 }
220 }
221
222 static void
android_media_MediaPlayer_setDataSourceAndHeaders(JNIEnv * env,jobject thiz,jobject httpServiceBinderObj,jstring path,jobjectArray keys,jobjectArray values)223 android_media_MediaPlayer_setDataSourceAndHeaders(
224 JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
225 jobjectArray keys, jobjectArray values) {
226
227 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
228 if (mp == NULL ) {
229 jniThrowException(env, "java/lang/IllegalStateException", NULL);
230 return;
231 }
232
233 if (path == NULL) {
234 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
235 return;
236 }
237
238 const char *tmp = env->GetStringUTFChars(path, NULL);
239 if (tmp == NULL) { // Out of memory
240 return;
241 }
242 ALOGV("setDataSource: path %s", tmp);
243
244 String8 pathStr(tmp);
245 env->ReleaseStringUTFChars(path, tmp);
246 tmp = NULL;
247
248 // We build a KeyedVector out of the key and val arrays
249 KeyedVector<String8, String8> headersVector;
250 if (!ConvertKeyValueArraysToKeyedVector(
251 env, keys, values, &headersVector)) {
252 return;
253 }
254
255 sp<IMediaHTTPService> httpService;
256 if (httpServiceBinderObj != NULL) {
257 sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
258 httpService = interface_cast<IMediaHTTPService>(binder);
259 }
260
261 status_t opStatus =
262 mp->setDataSource(
263 httpService,
264 pathStr,
265 headersVector.size() > 0? &headersVector : NULL);
266
267 process_media_player_call(
268 env, thiz, opStatus, "java/io/IOException",
269 "setDataSource failed." );
270 }
271
272 static void
android_media_MediaPlayer_setDataSourceFD(JNIEnv * env,jobject thiz,jobject fileDescriptor,jlong offset,jlong length)273 android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
274 {
275 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
276 if (mp == NULL ) {
277 jniThrowException(env, "java/lang/IllegalStateException", NULL);
278 return;
279 }
280
281 if (fileDescriptor == NULL) {
282 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
283 return;
284 }
285 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
286 ALOGV("setDataSourceFD: fd %d", fd);
287 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
288 }
289
290 static void
android_media_MediaPlayer_setDataSourceCallback(JNIEnv * env,jobject thiz,jobject dataSource)291 android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
292 {
293 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
294 if (mp == NULL ) {
295 jniThrowException(env, "java/lang/IllegalStateException", NULL);
296 return;
297 }
298
299 if (dataSource == NULL) {
300 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
301 return;
302 }
303 sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
304 process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
305 }
306
307 static sp<IGraphicBufferProducer>
getVideoSurfaceTexture(JNIEnv * env,jobject thiz)308 getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
309 IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
310 return sp<IGraphicBufferProducer>(p);
311 }
312
313 static void
decVideoSurfaceRef(JNIEnv * env,jobject thiz)314 decVideoSurfaceRef(JNIEnv *env, jobject thiz)
315 {
316 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
317 if (mp == NULL) {
318 return;
319 }
320
321 sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz);
322 if (old_st != NULL) {
323 old_st->decStrong((void*)decVideoSurfaceRef);
324 }
325 }
326
327 static void
setVideoSurface(JNIEnv * env,jobject thiz,jobject jsurface,jboolean mediaPlayerMustBeAlive)328 setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
329 {
330 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
331 if (mp == NULL) {
332 if (mediaPlayerMustBeAlive) {
333 jniThrowException(env, "java/lang/IllegalStateException", NULL);
334 }
335 return;
336 }
337
338 decVideoSurfaceRef(env, thiz);
339
340 sp<IGraphicBufferProducer> new_st;
341 if (jsurface) {
342 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
343 if (surface != NULL) {
344 new_st = surface->getIGraphicBufferProducer();
345 if (new_st == NULL) {
346 jniThrowException(env, "java/lang/IllegalArgumentException",
347 "The surface does not have a binding SurfaceTexture!");
348 return;
349 }
350 new_st->incStrong((void*)decVideoSurfaceRef);
351 } else {
352 jniThrowException(env, "java/lang/IllegalArgumentException",
353 "The surface has been released");
354 return;
355 }
356 }
357
358 env->SetLongField(thiz, fields.surface_texture, (jlong)new_st.get());
359
360 // This will fail if the media player has not been initialized yet. This
361 // can be the case if setDisplay() on MediaPlayer.java has been called
362 // before setDataSource(). The redundant call to setVideoSurfaceTexture()
363 // in prepare/prepareAsync covers for this case.
364 mp->setVideoSurfaceTexture(new_st);
365 }
366
367 static void
android_media_MediaPlayer_setVideoSurface(JNIEnv * env,jobject thiz,jobject jsurface)368 android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
369 {
370 setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
371 }
372
373 static jobject
android_media_MediaPlayer_getBufferingParams(JNIEnv * env,jobject thiz)374 android_media_MediaPlayer_getBufferingParams(JNIEnv *env, jobject thiz)
375 {
376 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
377 if (mp == NULL) {
378 jniThrowException(env, "java/lang/IllegalStateException", NULL);
379 return NULL;
380 }
381
382 BufferingParams bp;
383 BufferingSettings &settings = bp.settings;
384 process_media_player_call(
385 env, thiz, mp->getBufferingSettings(&settings),
386 "java/lang/IllegalStateException", "unexpected error");
387 if (env->ExceptionCheck()) {
388 return nullptr;
389 }
390 ALOGV("getBufferingSettings:{%s}", settings.toString().string());
391
392 return bp.asJobject(env, gBufferingParamsFields);
393 }
394
395 static void
android_media_MediaPlayer_setBufferingParams(JNIEnv * env,jobject thiz,jobject params)396 android_media_MediaPlayer_setBufferingParams(JNIEnv *env, jobject thiz, jobject params)
397 {
398 if (params == NULL) {
399 return;
400 }
401
402 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
403 if (mp == NULL) {
404 jniThrowException(env, "java/lang/IllegalStateException", NULL);
405 return;
406 }
407
408 BufferingParams bp;
409 bp.fillFromJobject(env, gBufferingParamsFields, params);
410 ALOGV("setBufferingParams:{%s}", bp.settings.toString().string());
411
412 process_media_player_call(
413 env, thiz, mp->setBufferingSettings(bp.settings),
414 "java/lang/IllegalStateException", "unexpected error");
415 }
416
417 static void
android_media_MediaPlayer_prepare(JNIEnv * env,jobject thiz)418 android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz)
419 {
420 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
421 if (mp == NULL ) {
422 jniThrowException(env, "java/lang/IllegalStateException", NULL);
423 return;
424 }
425
426 // Handle the case where the display surface was set before the mp was
427 // initialized. We try again to make it stick.
428 sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
429 mp->setVideoSurfaceTexture(st);
430
431 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
432 }
433
434 static void
android_media_MediaPlayer_prepareAsync(JNIEnv * env,jobject thiz)435 android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz)
436 {
437 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
438 if (mp == NULL ) {
439 jniThrowException(env, "java/lang/IllegalStateException", NULL);
440 return;
441 }
442
443 // Handle the case where the display surface was set before the mp was
444 // initialized. We try again to make it stick.
445 sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
446 mp->setVideoSurfaceTexture(st);
447
448 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
449 }
450
451 static void
android_media_MediaPlayer_start(JNIEnv * env,jobject thiz)452 android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
453 {
454 ALOGV("start");
455 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
456 if (mp == NULL ) {
457 jniThrowException(env, "java/lang/IllegalStateException", NULL);
458 return;
459 }
460 process_media_player_call( env, thiz, mp->start(), NULL, NULL );
461 }
462
463 static void
android_media_MediaPlayer_stop(JNIEnv * env,jobject thiz)464 android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
465 {
466 ALOGV("stop");
467 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
468 if (mp == NULL ) {
469 jniThrowException(env, "java/lang/IllegalStateException", NULL);
470 return;
471 }
472 process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
473 }
474
475 static void
android_media_MediaPlayer_pause(JNIEnv * env,jobject thiz)476 android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
477 {
478 ALOGV("pause");
479 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
480 if (mp == NULL ) {
481 jniThrowException(env, "java/lang/IllegalStateException", NULL);
482 return;
483 }
484 process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
485 }
486
487 static jboolean
android_media_MediaPlayer_isPlaying(JNIEnv * env,jobject thiz)488 android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
489 {
490 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
491 if (mp == NULL ) {
492 jniThrowException(env, "java/lang/IllegalStateException", NULL);
493 return JNI_FALSE;
494 }
495 const jboolean is_playing = mp->isPlaying();
496
497 ALOGV("isPlaying: %d", is_playing);
498 return is_playing;
499 }
500
501 static void
android_media_MediaPlayer_setPlaybackParams(JNIEnv * env,jobject thiz,jobject params)502 android_media_MediaPlayer_setPlaybackParams(JNIEnv *env, jobject thiz, jobject params)
503 {
504 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
505 if (mp == NULL) {
506 jniThrowException(env, "java/lang/IllegalStateException", NULL);
507 return;
508 }
509
510 PlaybackParams pbp;
511 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
512 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
513 pbp.speedSet, pbp.audioRate.mSpeed,
514 pbp.pitchSet, pbp.audioRate.mPitch,
515 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
516 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
517
518 AudioPlaybackRate rate;
519 status_t err = mp->getPlaybackSettings(&rate);
520 if (err == OK) {
521 bool updatedRate = false;
522 if (pbp.speedSet) {
523 rate.mSpeed = pbp.audioRate.mSpeed;
524 updatedRate = true;
525 }
526 if (pbp.pitchSet) {
527 rate.mPitch = pbp.audioRate.mPitch;
528 updatedRate = true;
529 }
530 if (pbp.audioFallbackModeSet) {
531 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
532 updatedRate = true;
533 }
534 if (pbp.audioStretchModeSet) {
535 rate.mStretchMode = pbp.audioRate.mStretchMode;
536 updatedRate = true;
537 }
538 if (updatedRate) {
539 err = mp->setPlaybackSettings(rate);
540 }
541 }
542 process_media_player_call(
543 env, thiz, err,
544 "java/lang/IllegalStateException", "unexpected error");
545 }
546
547 static jobject
android_media_MediaPlayer_getPlaybackParams(JNIEnv * env,jobject thiz)548 android_media_MediaPlayer_getPlaybackParams(JNIEnv *env, jobject thiz)
549 {
550 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
551 if (mp == NULL) {
552 jniThrowException(env, "java/lang/IllegalStateException", NULL);
553 return NULL;
554 }
555
556 PlaybackParams pbp;
557 AudioPlaybackRate &audioRate = pbp.audioRate;
558 process_media_player_call(
559 env, thiz, mp->getPlaybackSettings(&audioRate),
560 "java/lang/IllegalStateException", "unexpected error");
561 if (env->ExceptionCheck()) {
562 return nullptr;
563 }
564 ALOGV("getPlaybackSettings: %f %f %d %d",
565 audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
566
567 pbp.speedSet = true;
568 pbp.pitchSet = true;
569 pbp.audioFallbackModeSet = true;
570 pbp.audioStretchModeSet = true;
571
572 return pbp.asJobject(env, gPlaybackParamsFields);
573 }
574
575 static void
android_media_MediaPlayer_setSyncParams(JNIEnv * env,jobject thiz,jobject params)576 android_media_MediaPlayer_setSyncParams(JNIEnv *env, jobject thiz, jobject params)
577 {
578 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
579 if (mp == NULL) {
580 jniThrowException(env, "java/lang/IllegalStateException", NULL);
581 return;
582 }
583
584 SyncParams scp;
585 scp.fillFromJobject(env, gSyncParamsFields, params);
586 ALOGV("setSyncParams: %d:%d %d:%d %d:%f %d:%f",
587 scp.syncSourceSet, scp.sync.mSource,
588 scp.audioAdjustModeSet, scp.sync.mAudioAdjustMode,
589 scp.toleranceSet, scp.sync.mTolerance,
590 scp.frameRateSet, scp.frameRate);
591
592 AVSyncSettings avsync;
593 float videoFrameRate;
594 status_t err = mp->getSyncSettings(&avsync, &videoFrameRate);
595 if (err == OK) {
596 bool updatedSync = scp.frameRateSet;
597 if (scp.syncSourceSet) {
598 avsync.mSource = scp.sync.mSource;
599 updatedSync = true;
600 }
601 if (scp.audioAdjustModeSet) {
602 avsync.mAudioAdjustMode = scp.sync.mAudioAdjustMode;
603 updatedSync = true;
604 }
605 if (scp.toleranceSet) {
606 avsync.mTolerance = scp.sync.mTolerance;
607 updatedSync = true;
608 }
609 if (updatedSync) {
610 err = mp->setSyncSettings(avsync, scp.frameRateSet ? scp.frameRate : -1.f);
611 }
612 }
613 process_media_player_call(
614 env, thiz, err,
615 "java/lang/IllegalStateException", "unexpected error");
616 }
617
618 static jobject
android_media_MediaPlayer_getSyncParams(JNIEnv * env,jobject thiz)619 android_media_MediaPlayer_getSyncParams(JNIEnv *env, jobject thiz)
620 {
621 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
622 if (mp == NULL) {
623 jniThrowException(env, "java/lang/IllegalStateException", NULL);
624 return NULL;
625 }
626
627 SyncParams scp;
628 scp.frameRate = -1.f;
629 process_media_player_call(
630 env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
631 "java/lang/IllegalStateException", "unexpected error");
632 if (env->ExceptionCheck()) {
633 return nullptr;
634 }
635
636 ALOGV("getSyncSettings: %d %d %f %f",
637 scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
638
639 // sanity check params
640 if (scp.sync.mSource >= AVSYNC_SOURCE_MAX
641 || scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
642 || scp.sync.mTolerance < 0.f
643 || scp.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
644 jniThrowException(env, "java/lang/IllegalStateException", NULL);
645 return NULL;
646 }
647
648 scp.syncSourceSet = true;
649 scp.audioAdjustModeSet = true;
650 scp.toleranceSet = true;
651 scp.frameRateSet = scp.frameRate >= 0.f;
652
653 return scp.asJobject(env, gSyncParamsFields);
654 }
655
656 static void
android_media_MediaPlayer_seekTo(JNIEnv * env,jobject thiz,jlong msec,jint mode)657 android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jlong msec, jint mode)
658 {
659 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
660 if (mp == NULL ) {
661 jniThrowException(env, "java/lang/IllegalStateException", NULL);
662 return;
663 }
664 ALOGV("seekTo: %lld(msec), mode=%d", (long long)msec, mode);
665 process_media_player_call( env, thiz, mp->seekTo((int)msec, (MediaPlayerSeekMode)mode), NULL, NULL );
666 }
667
668 static void
android_media_MediaPlayer_notifyAt(JNIEnv * env,jobject thiz,jlong mediaTimeUs)669 android_media_MediaPlayer_notifyAt(JNIEnv *env, jobject thiz, jlong mediaTimeUs)
670 {
671 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
672 if (mp == NULL) {
673 jniThrowException(env, "java/lang/IllegalStateException", NULL);
674 return;
675 }
676 ALOGV("notifyAt: %lld", (long long)mediaTimeUs);
677 process_media_player_call( env, thiz, mp->notifyAt((int64_t)mediaTimeUs), NULL, NULL );
678 }
679
680 static jint
android_media_MediaPlayer_getVideoWidth(JNIEnv * env,jobject thiz)681 android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
682 {
683 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
684 if (mp == NULL ) {
685 jniThrowException(env, "java/lang/IllegalStateException", NULL);
686 return 0;
687 }
688 int w;
689 if (0 != mp->getVideoWidth(&w)) {
690 ALOGE("getVideoWidth failed");
691 w = 0;
692 }
693 ALOGV("getVideoWidth: %d", w);
694 return (jint) w;
695 }
696
697 static jint
android_media_MediaPlayer_getVideoHeight(JNIEnv * env,jobject thiz)698 android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
699 {
700 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
701 if (mp == NULL ) {
702 jniThrowException(env, "java/lang/IllegalStateException", NULL);
703 return 0;
704 }
705 int h;
706 if (0 != mp->getVideoHeight(&h)) {
707 ALOGE("getVideoHeight failed");
708 h = 0;
709 }
710 ALOGV("getVideoHeight: %d", h);
711 return (jint) h;
712 }
713
714 static jobject
android_media_MediaPlayer_native_getMetrics(JNIEnv * env,jobject thiz)715 android_media_MediaPlayer_native_getMetrics(JNIEnv *env, jobject thiz)
716 {
717 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
718 if (mp == NULL ) {
719 jniThrowException(env, "java/lang/IllegalStateException", NULL);
720 return 0;
721 }
722
723 Parcel p;
724 int key = FOURCC('m','t','r','X');
725 status_t status = mp->getParameter(key, &p);
726 if (status != OK) {
727 ALOGD("getMetrics() failed: %d", status);
728 return (jobject) NULL;
729 }
730
731 MediaAnalyticsItem *item = new MediaAnalyticsItem;
732 item->readFromParcel(p);
733 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item, NULL);
734
735 // housekeeping
736 delete item;
737 item = NULL;
738
739 return mybundle;
740 }
741
742 static jint
android_media_MediaPlayer_getCurrentPosition(JNIEnv * env,jobject thiz)743 android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
744 {
745 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
746 if (mp == NULL ) {
747 jniThrowException(env, "java/lang/IllegalStateException", NULL);
748 return 0;
749 }
750 int msec;
751 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
752 ALOGV("getCurrentPosition: %d (msec)", msec);
753 return (jint) msec;
754 }
755
756 static jint
android_media_MediaPlayer_getDuration(JNIEnv * env,jobject thiz)757 android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
758 {
759 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
760 if (mp == NULL ) {
761 jniThrowException(env, "java/lang/IllegalStateException", NULL);
762 return 0;
763 }
764 int msec;
765 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
766 ALOGV("getDuration: %d (msec)", msec);
767 return (jint) msec;
768 }
769
770 static void
android_media_MediaPlayer_reset(JNIEnv * env,jobject thiz)771 android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
772 {
773 ALOGV("reset");
774 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
775 if (mp == NULL ) {
776 jniThrowException(env, "java/lang/IllegalStateException", NULL);
777 return;
778 }
779 process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
780 }
781
782 static void
android_media_MediaPlayer_setAudioStreamType(JNIEnv * env,jobject thiz,jint streamtype)783 android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint streamtype)
784 {
785 ALOGV("setAudioStreamType: %d", streamtype);
786 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
787 if (mp == NULL ) {
788 jniThrowException(env, "java/lang/IllegalStateException", NULL);
789 return;
790 }
791 process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
792 }
793
794 static jint
android_media_MediaPlayer_getAudioStreamType(JNIEnv * env,jobject thiz)795 android_media_MediaPlayer_getAudioStreamType(JNIEnv *env, jobject thiz)
796 {
797 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
798 if (mp == NULL ) {
799 jniThrowException(env, "java/lang/IllegalStateException", NULL);
800 return 0;
801 }
802 audio_stream_type_t streamtype;
803 process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
804 ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
805 return (jint) streamtype;
806 }
807
808 static jboolean
android_media_MediaPlayer_setParameter(JNIEnv * env,jobject thiz,jint key,jobject java_request)809 android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
810 {
811 ALOGV("setParameter: key %d", key);
812 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
813 if (mp == NULL ) {
814 jniThrowException(env, "java/lang/IllegalStateException", NULL);
815 return false;
816 }
817
818 Parcel *request = parcelForJavaObject(env, java_request);
819 status_t err = mp->setParameter(key, *request);
820 if (err == OK) {
821 return true;
822 } else {
823 return false;
824 }
825 }
826
827 static void
android_media_MediaPlayer_setLooping(JNIEnv * env,jobject thiz,jboolean looping)828 android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
829 {
830 ALOGV("setLooping: %d", looping);
831 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
832 if (mp == NULL ) {
833 jniThrowException(env, "java/lang/IllegalStateException", NULL);
834 return;
835 }
836 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
837 }
838
839 static jboolean
android_media_MediaPlayer_isLooping(JNIEnv * env,jobject thiz)840 android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
841 {
842 ALOGV("isLooping");
843 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
844 if (mp == NULL ) {
845 jniThrowException(env, "java/lang/IllegalStateException", NULL);
846 return JNI_FALSE;
847 }
848 return mp->isLooping() ? JNI_TRUE : JNI_FALSE;
849 }
850
851 static void
android_media_MediaPlayer_setVolume(JNIEnv * env,jobject thiz,jfloat leftVolume,jfloat rightVolume)852 android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume)
853 {
854 ALOGV("setVolume: left %f right %f", (float) leftVolume, (float) rightVolume);
855 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
856 if (mp == NULL ) {
857 jniThrowException(env, "java/lang/IllegalStateException", NULL);
858 return;
859 }
860 process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL );
861 }
862
863 // Sends the request and reply parcels to the media player via the
864 // binder interface.
865 static jint
android_media_MediaPlayer_invoke(JNIEnv * env,jobject thiz,jobject java_request,jobject java_reply)866 android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
867 jobject java_request, jobject java_reply)
868 {
869 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
870 if (media_player == NULL ) {
871 jniThrowException(env, "java/lang/IllegalStateException", NULL);
872 return UNKNOWN_ERROR;
873 }
874
875 Parcel *request = parcelForJavaObject(env, java_request);
876 Parcel *reply = parcelForJavaObject(env, java_reply);
877
878 // Don't use process_media_player_call which use the async loop to
879 // report errors, instead returns the status.
880 return (jint) media_player->invoke(*request, reply);
881 }
882
883 // Sends the new filter to the client.
884 static jint
android_media_MediaPlayer_setMetadataFilter(JNIEnv * env,jobject thiz,jobject request)885 android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
886 {
887 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
888 if (media_player == NULL ) {
889 jniThrowException(env, "java/lang/IllegalStateException", NULL);
890 return UNKNOWN_ERROR;
891 }
892
893 Parcel *filter = parcelForJavaObject(env, request);
894
895 if (filter == NULL ) {
896 jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
897 return UNKNOWN_ERROR;
898 }
899
900 return (jint) media_player->setMetadataFilter(*filter);
901 }
902
903 static jboolean
android_media_MediaPlayer_getMetadata(JNIEnv * env,jobject thiz,jboolean update_only,jboolean apply_filter,jobject reply)904 android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
905 jboolean apply_filter, jobject reply)
906 {
907 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
908 if (media_player == NULL ) {
909 jniThrowException(env, "java/lang/IllegalStateException", NULL);
910 return JNI_FALSE;
911 }
912
913 Parcel *metadata = parcelForJavaObject(env, reply);
914
915 if (metadata == NULL ) {
916 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
917 return JNI_FALSE;
918 }
919
920 metadata->freeData();
921 // On return metadata is positioned at the beginning of the
922 // metadata. Note however that the parcel actually starts with the
923 // return code so you should not rewind the parcel using
924 // setDataPosition(0).
925 if (media_player->getMetadata(update_only, apply_filter, metadata) == OK) {
926 return JNI_TRUE;
927 } else {
928 return JNI_FALSE;
929 }
930 }
931
932 // This function gets some field IDs, which in turn causes class initialization.
933 // It is called from a static block in MediaPlayer, which won't run until the
934 // first time an instance of this class is used.
935 static void
android_media_MediaPlayer_native_init(JNIEnv * env)936 android_media_MediaPlayer_native_init(JNIEnv *env)
937 {
938 jclass clazz;
939
940 clazz = env->FindClass("android/media/MediaPlayer");
941 if (clazz == NULL) {
942 return;
943 }
944
945 fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
946 if (fields.context == NULL) {
947 return;
948 }
949
950 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
951 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
952 if (fields.post_event == NULL) {
953 return;
954 }
955
956 fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
957 if (fields.surface_texture == NULL) {
958 return;
959 }
960
961 env->DeleteLocalRef(clazz);
962
963 clazz = env->FindClass("android/net/ProxyInfo");
964 if (clazz == NULL) {
965 return;
966 }
967
968 fields.proxyConfigGetHost =
969 env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
970
971 fields.proxyConfigGetPort =
972 env->GetMethodID(clazz, "getPort", "()I");
973
974 fields.proxyConfigGetExclusionList =
975 env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
976
977 env->DeleteLocalRef(clazz);
978
979 gBufferingParamsFields.init(env);
980
981 // Modular DRM
982 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
983 if (clazz) {
984 GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V");
985 gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
986
987 env->DeleteLocalRef(clazz);
988 } else {
989 ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
990 "get clazz android/media/MediaDrm$MediaDrmStateException");
991 }
992
993 gPlaybackParamsFields.init(env);
994 gSyncParamsFields.init(env);
995 gVolumeShaperFields.init(env);
996 }
997
998 static void
android_media_MediaPlayer_native_setup(JNIEnv * env,jobject thiz,jobject weak_this)999 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
1000 {
1001 ALOGV("native_setup");
1002 sp<MediaPlayer> mp = new MediaPlayer();
1003 if (mp == NULL) {
1004 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
1005 return;
1006 }
1007
1008 // create new listener and give it to MediaPlayer
1009 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
1010 mp->setListener(listener);
1011
1012 // Stow our new C++ MediaPlayer in an opaque field in the Java object.
1013 setMediaPlayer(env, thiz, mp);
1014 }
1015
1016 static void
android_media_MediaPlayer_release(JNIEnv * env,jobject thiz)1017 android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
1018 {
1019 ALOGV("release");
1020 decVideoSurfaceRef(env, thiz);
1021 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
1022 if (mp != NULL) {
1023 // this prevents native callbacks after the object is released
1024 mp->setListener(0);
1025 mp->disconnect();
1026 }
1027 }
1028
1029 static void
android_media_MediaPlayer_native_finalize(JNIEnv * env,jobject thiz)1030 android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
1031 {
1032 ALOGV("native_finalize");
1033 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1034 if (mp != NULL) {
1035 ALOGW("MediaPlayer finalized without being released");
1036 }
1037 android_media_MediaPlayer_release(env, thiz);
1038 }
1039
android_media_MediaPlayer_set_audio_session_id(JNIEnv * env,jobject thiz,jint sessionId)1040 static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz,
1041 jint sessionId) {
1042 ALOGV("set_session_id(): %d", sessionId);
1043 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1044 if (mp == NULL ) {
1045 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1046 return;
1047 }
1048 process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL,
1049 NULL);
1050 }
1051
android_media_MediaPlayer_get_audio_session_id(JNIEnv * env,jobject thiz)1052 static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
1053 ALOGV("get_session_id()");
1054 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1055 if (mp == NULL ) {
1056 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1057 return 0;
1058 }
1059
1060 return (jint) mp->getAudioSessionId();
1061 }
1062
1063 static void
android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv * env,jobject thiz,jfloat level)1064 android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
1065 {
1066 ALOGV("setAuxEffectSendLevel: level %f", level);
1067 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1068 if (mp == NULL ) {
1069 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1070 return;
1071 }
1072 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
1073 }
1074
android_media_MediaPlayer_attachAuxEffect(JNIEnv * env,jobject thiz,jint effectId)1075 static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
1076 ALOGV("attachAuxEffect(): %d", effectId);
1077 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1078 if (mp == NULL ) {
1079 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1080 return;
1081 }
1082 process_media_player_call( env, thiz, mp->attachAuxEffect(effectId), NULL, NULL );
1083 }
1084
1085 static jint
android_media_MediaPlayer_pullBatteryData(JNIEnv * env,jobject,jobject java_reply)1086 android_media_MediaPlayer_pullBatteryData(
1087 JNIEnv *env, jobject /* thiz */, jobject java_reply)
1088 {
1089 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
1090 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1091 if (service.get() == NULL) {
1092 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
1093 return UNKNOWN_ERROR;
1094 }
1095
1096 Parcel *reply = parcelForJavaObject(env, java_reply);
1097
1098 return (jint) service->pullBatteryData(reply);
1099 }
1100
1101 static jint
android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv * env,jobject thiz,jstring addrString,jint port)1102 android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
1103 jstring addrString, jint port) {
1104 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1105 if (mp == NULL ) {
1106 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1107 return INVALID_OPERATION;
1108 }
1109
1110 const char *cAddrString = NULL;
1111
1112 if (NULL != addrString) {
1113 cAddrString = env->GetStringUTFChars(addrString, NULL);
1114 if (cAddrString == NULL) { // Out of memory
1115 return NO_MEMORY;
1116 }
1117 }
1118 ALOGV("setRetransmitEndpoint: %s:%d",
1119 cAddrString ? cAddrString : "(null)", port);
1120
1121 status_t ret;
1122 if (cAddrString && (port > 0xFFFF)) {
1123 ret = BAD_VALUE;
1124 } else {
1125 ret = mp->setRetransmitEndpoint(cAddrString,
1126 static_cast<uint16_t>(port));
1127 }
1128
1129 if (NULL != addrString) {
1130 env->ReleaseStringUTFChars(addrString, cAddrString);
1131 }
1132
1133 if (ret == INVALID_OPERATION ) {
1134 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1135 }
1136
1137 return (jint) ret;
1138 }
1139
1140 static void
android_media_MediaPlayer_setNextMediaPlayer(JNIEnv * env,jobject thiz,jobject java_player)1141 android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
1142 {
1143 ALOGV("setNextMediaPlayer");
1144 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
1145 if (thisplayer == NULL) {
1146 jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized");
1147 return;
1148 }
1149 sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player);
1150 if (nextplayer == NULL && java_player != NULL) {
1151 jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized");
1152 return;
1153 }
1154
1155 if (nextplayer == thisplayer) {
1156 jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self");
1157 return;
1158 }
1159 // tie the two players together
1160 process_media_player_call(
1161 env, thiz, thisplayer->setNextMediaPlayer(nextplayer),
1162 "java/lang/IllegalArgumentException",
1163 "setNextMediaPlayer failed." );
1164 ;
1165 }
1166
1167 // Pass through the arguments to the MediaServer player implementation.
android_media_MediaPlayer_applyVolumeShaper(JNIEnv * env,jobject thiz,jobject jconfig,jobject joperation)1168 static jint android_media_MediaPlayer_applyVolumeShaper(JNIEnv *env, jobject thiz,
1169 jobject jconfig, jobject joperation) {
1170 // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1171 const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1172
1173 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1174 if (mp == nullptr) {
1175 return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1176 }
1177
1178 sp<VolumeShaper::Configuration> configuration;
1179 sp<VolumeShaper::Operation> operation;
1180 if (jconfig != nullptr) {
1181 configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1182 env, gVolumeShaperFields, jconfig);
1183 ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1184 }
1185 if (joperation != nullptr) {
1186 operation = VolumeShaperHelper::convertJobjectToOperation(
1187 env, gVolumeShaperFields, joperation);
1188 ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1189 }
1190 VolumeShaper::Status status = mp->applyVolumeShaper(configuration, operation);
1191 if (status == INVALID_OPERATION) {
1192 status = VOLUME_SHAPER_INVALID_OPERATION;
1193 }
1194 return (jint)status; // if status < 0 an error, else a VolumeShaper id
1195 }
1196
1197 // Pass through the arguments to the MediaServer player implementation.
android_media_MediaPlayer_getVolumeShaperState(JNIEnv * env,jobject thiz,jint id)1198 static jobject android_media_MediaPlayer_getVolumeShaperState(JNIEnv *env, jobject thiz,
1199 jint id) {
1200 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1201 if (mp == nullptr) {
1202 return (jobject)nullptr;
1203 }
1204
1205 sp<VolumeShaper::State> state = mp->getVolumeShaperState((int)id);
1206 if (state.get() == nullptr) {
1207 return (jobject)nullptr;
1208 }
1209 return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1210 }
1211
1212 /////////////////////////////////////////////////////////////////////////////////////
1213 // Modular DRM begin
1214
1215 // TODO: investigate if these can be shared with their MediaDrm counterparts
throwDrmStateException(JNIEnv * env,const char * msg,status_t err)1216 static void throwDrmStateException(JNIEnv *env, const char *msg, status_t err)
1217 {
1218 ALOGE("Illegal DRM state exception: %s (%d)", msg, err);
1219
1220 jobject exception = env->NewObject(gStateExceptionFields.classId,
1221 gStateExceptionFields.init, static_cast<int>(err),
1222 env->NewStringUTF(msg));
1223 env->Throw(static_cast<jthrowable>(exception));
1224 }
1225
1226 // TODO: investigate if these can be shared with their MediaDrm counterparts
throwDrmExceptionAsNecessary(JNIEnv * env,status_t err,const char * msg=NULL)1227 static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char *msg = NULL)
1228 {
1229 const char *drmMessage = "Unknown DRM Msg";
1230
1231 switch (err) {
1232 case ERROR_DRM_UNKNOWN:
1233 drmMessage = "General DRM error";
1234 break;
1235 case ERROR_DRM_NO_LICENSE:
1236 drmMessage = "No license";
1237 break;
1238 case ERROR_DRM_LICENSE_EXPIRED:
1239 drmMessage = "License expired";
1240 break;
1241 case ERROR_DRM_SESSION_NOT_OPENED:
1242 drmMessage = "Session not opened";
1243 break;
1244 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
1245 drmMessage = "Not initialized";
1246 break;
1247 case ERROR_DRM_DECRYPT:
1248 drmMessage = "Decrypt error";
1249 break;
1250 case ERROR_DRM_CANNOT_HANDLE:
1251 drmMessage = "Unsupported scheme or data format";
1252 break;
1253 case ERROR_DRM_TAMPER_DETECTED:
1254 drmMessage = "Invalid state";
1255 break;
1256 default:
1257 break;
1258 }
1259
1260 String8 vendorMessage;
1261 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
1262 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
1263 drmMessage = vendorMessage.string();
1264 }
1265
1266 if (err == BAD_VALUE) {
1267 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1268 return true;
1269 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
1270 jniThrowException(env, "android/media/NotProvisionedException", msg);
1271 return true;
1272 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
1273 jniThrowException(env, "android/media/ResourceBusyException", msg);
1274 return true;
1275 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
1276 jniThrowException(env, "android/media/DeniedByServerException", msg);
1277 return true;
1278 } else if (err == DEAD_OBJECT) {
1279 jniThrowException(env, "android/media/MediaDrmResetException",
1280 "mediaserver died");
1281 return true;
1282 } else if (err != OK) {
1283 String8 errbuf;
1284 if (drmMessage != NULL) {
1285 if (msg == NULL) {
1286 msg = drmMessage;
1287 } else {
1288 errbuf = String8::format("%s: %s", msg, drmMessage);
1289 msg = errbuf.string();
1290 }
1291 }
1292 throwDrmStateException(env, msg, err);
1293 return true;
1294 }
1295 return false;
1296 }
1297
JByteArrayToVector(JNIEnv * env,jbyteArray const & byteArray)1298 static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray)
1299 {
1300 Vector<uint8_t> vector;
1301 size_t length = env->GetArrayLength(byteArray);
1302 vector.insertAt((size_t)0, length);
1303 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
1304 return vector;
1305 }
1306
android_media_MediaPlayer_prepareDrm(JNIEnv * env,jobject thiz,jbyteArray uuidObj,jbyteArray drmSessionIdObj)1307 static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
1308 jbyteArray uuidObj, jbyteArray drmSessionIdObj)
1309 {
1310 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1311 if (mp == NULL) {
1312 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1313 return;
1314 }
1315
1316 if (uuidObj == NULL) {
1317 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1318 return;
1319 }
1320
1321 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1322
1323 if (uuid.size() != 16) {
1324 jniThrowException(
1325 env,
1326 "java/lang/IllegalArgumentException",
1327 "invalid UUID size, expected 16 bytes");
1328 return;
1329 }
1330
1331 Vector<uint8_t> drmSessionId = JByteArrayToVector(env, drmSessionIdObj);
1332
1333 if (drmSessionId.size() == 0) {
1334 jniThrowException(
1335 env,
1336 "java/lang/IllegalArgumentException",
1337 "empty drmSessionId");
1338 return;
1339 }
1340
1341 status_t err = mp->prepareDrm(uuid.array(), drmSessionId);
1342 if (err != OK) {
1343 if (err == INVALID_OPERATION) {
1344 jniThrowException(
1345 env,
1346 "java/lang/IllegalStateException",
1347 "The player must be in prepared state.");
1348 } else if (err == ERROR_DRM_CANNOT_HANDLE) {
1349 jniThrowException(
1350 env,
1351 "android/media/UnsupportedSchemeException",
1352 "Failed to instantiate drm object.");
1353 } else {
1354 throwDrmExceptionAsNecessary(env, err, "Failed to prepare DRM scheme");
1355 }
1356 }
1357 }
1358
android_media_MediaPlayer_releaseDrm(JNIEnv * env,jobject thiz)1359 static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
1360 {
1361 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1362 if (mp == NULL ) {
1363 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1364 return;
1365 }
1366
1367 status_t err = mp->releaseDrm();
1368 if (err != OK) {
1369 if (err == INVALID_OPERATION) {
1370 jniThrowException(
1371 env,
1372 "java/lang/IllegalStateException",
1373 "Can not release DRM in an active player state.");
1374 }
1375 }
1376 }
1377 // Modular DRM end
1378 // ----------------------------------------------------------------------------
1379
1380 /////////////////////////////////////////////////////////////////////////////////////
1381 // AudioRouting begin
android_media_MediaPlayer_setOutputDevice(JNIEnv * env,jobject thiz,jint device_id)1382 static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id)
1383 {
1384 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1385 if (mp == NULL) {
1386 return false;
1387 }
1388 return mp->setOutputDevice(device_id) == NO_ERROR;
1389 }
1390
android_media_MediaPlayer_getRoutedDeviceId(JNIEnv * env,jobject thiz)1391 static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
1392 {
1393 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1394 if (mp == NULL) {
1395 return AUDIO_PORT_HANDLE_NONE;
1396 }
1397 return mp->getRoutedDeviceId();
1398 }
1399
android_media_MediaPlayer_enableDeviceCallback(JNIEnv * env,jobject thiz,jboolean enabled)1400 static void android_media_MediaPlayer_enableDeviceCallback(
1401 JNIEnv* env, jobject thiz, jboolean enabled)
1402 {
1403 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1404 if (mp == NULL) {
1405 return;
1406 }
1407
1408 status_t status = mp->enableAudioDeviceCallback(enabled);
1409 if (status != NO_ERROR) {
1410 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1411 ALOGE("enable device callback failed: %d", status);
1412 }
1413 }
1414
1415 // AudioRouting end
1416 // ----------------------------------------------------------------------------
1417
1418 static const JNINativeMethod gMethods[] = {
1419 {
1420 "nativeSetDataSource",
1421 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
1422 "[Ljava/lang/String;)V",
1423 (void *)android_media_MediaPlayer_setDataSourceAndHeaders
1424 },
1425
1426 {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
1427 {"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
1428 {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
1429 {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer_getBufferingParams},
1430 {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer_setBufferingParams},
1431 {"_prepare", "()V", (void *)android_media_MediaPlayer_prepare},
1432 {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
1433 {"_start", "()V", (void *)android_media_MediaPlayer_start},
1434 {"_stop", "()V", (void *)android_media_MediaPlayer_stop},
1435 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
1436 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
1437 {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer_native_getMetrics},
1438 {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
1439 {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
1440 {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams},
1441 {"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer_getSyncParams},
1442 {"_seekTo", "(JI)V", (void *)android_media_MediaPlayer_seekTo},
1443 {"_notifyAt", "(J)V", (void *)android_media_MediaPlayer_notifyAt},
1444 {"_pause", "()V", (void *)android_media_MediaPlayer_pause},
1445 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
1446 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
1447 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
1448 {"_release", "()V", (void *)android_media_MediaPlayer_release},
1449 {"_reset", "()V", (void *)android_media_MediaPlayer_reset},
1450 {"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
1451 {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType},
1452 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
1453 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
1454 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
1455 {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
1456 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
1457 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
1458 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
1459 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
1460 {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
1461 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
1462 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
1463 {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
1464 {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
1465 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
1466 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
1467 {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint},
1468 {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer},
1469 {"native_applyVolumeShaper",
1470 "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1471 (void *)android_media_MediaPlayer_applyVolumeShaper},
1472 {"native_getVolumeShaperState",
1473 "(I)Landroid/media/VolumeShaper$State;",
1474 (void *)android_media_MediaPlayer_getVolumeShaperState},
1475 // Modular DRM
1476 { "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm },
1477 { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm },
1478
1479 // AudioRouting
1480 {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice},
1481 {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId},
1482 {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback},
1483 };
1484
1485 // This function only registers the native methods
register_android_media_MediaPlayer(JNIEnv * env)1486 static int register_android_media_MediaPlayer(JNIEnv *env)
1487 {
1488 return AndroidRuntime::registerNativeMethods(env,
1489 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
1490 }
1491 extern int register_android_media_ImageReader(JNIEnv *env);
1492 extern int register_android_media_ImageWriter(JNIEnv *env);
1493 extern int register_android_media_Crypto(JNIEnv *env);
1494 extern int register_android_media_Drm(JNIEnv *env);
1495 extern int register_android_media_Descrambler(JNIEnv *env);
1496 extern int register_android_media_MediaCodec(JNIEnv *env);
1497 extern int register_android_media_MediaExtractor(JNIEnv *env);
1498 extern int register_android_media_MediaCodecList(JNIEnv *env);
1499 extern int register_android_media_MediaHTTPConnection(JNIEnv *env);
1500 extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
1501 extern int register_android_media_MediaMuxer(JNIEnv *env);
1502 extern int register_android_media_MediaRecorder(JNIEnv *env);
1503 extern int register_android_media_MediaScanner(JNIEnv *env);
1504 extern int register_android_media_MediaSync(JNIEnv *env);
1505 extern int register_android_media_ResampleInputStream(JNIEnv *env);
1506 extern int register_android_media_MediaProfiles(JNIEnv *env);
1507 extern int register_android_mtp_MtpDatabase(JNIEnv *env);
1508 extern int register_android_mtp_MtpDevice(JNIEnv *env);
1509 extern int register_android_mtp_MtpServer(JNIEnv *env);
1510
JNI_OnLoad(JavaVM * vm,void *)1511 jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
1512 {
1513 JNIEnv* env = NULL;
1514 jint result = -1;
1515
1516 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
1517 ALOGE("ERROR: GetEnv failed\n");
1518 goto bail;
1519 }
1520 assert(env != NULL);
1521
1522 if (register_android_media_ImageWriter(env) != JNI_OK) {
1523 ALOGE("ERROR: ImageWriter native registration failed");
1524 goto bail;
1525 }
1526
1527 if (register_android_media_ImageReader(env) < 0) {
1528 ALOGE("ERROR: ImageReader native registration failed");
1529 goto bail;
1530 }
1531
1532 if (register_android_media_MediaPlayer(env) < 0) {
1533 ALOGE("ERROR: MediaPlayer native registration failed\n");
1534 goto bail;
1535 }
1536
1537 if (register_android_media_MediaRecorder(env) < 0) {
1538 ALOGE("ERROR: MediaRecorder native registration failed\n");
1539 goto bail;
1540 }
1541
1542 if (register_android_media_MediaScanner(env) < 0) {
1543 ALOGE("ERROR: MediaScanner native registration failed\n");
1544 goto bail;
1545 }
1546
1547 if (register_android_media_MediaMetadataRetriever(env) < 0) {
1548 ALOGE("ERROR: MediaMetadataRetriever native registration failed\n");
1549 goto bail;
1550 }
1551
1552 if (register_android_media_ResampleInputStream(env) < 0) {
1553 ALOGE("ERROR: ResampleInputStream native registration failed\n");
1554 goto bail;
1555 }
1556
1557 if (register_android_media_MediaProfiles(env) < 0) {
1558 ALOGE("ERROR: MediaProfiles native registration failed");
1559 goto bail;
1560 }
1561
1562 if (register_android_mtp_MtpDatabase(env) < 0) {
1563 ALOGE("ERROR: MtpDatabase native registration failed");
1564 goto bail;
1565 }
1566
1567 if (register_android_mtp_MtpDevice(env) < 0) {
1568 ALOGE("ERROR: MtpDevice native registration failed");
1569 goto bail;
1570 }
1571
1572 if (register_android_mtp_MtpServer(env) < 0) {
1573 ALOGE("ERROR: MtpServer native registration failed");
1574 goto bail;
1575 }
1576
1577 if (register_android_media_MediaCodec(env) < 0) {
1578 ALOGE("ERROR: MediaCodec native registration failed");
1579 goto bail;
1580 }
1581
1582 if (register_android_media_MediaSync(env) < 0) {
1583 ALOGE("ERROR: MediaSync native registration failed");
1584 goto bail;
1585 }
1586
1587 if (register_android_media_MediaExtractor(env) < 0) {
1588 ALOGE("ERROR: MediaCodec native registration failed");
1589 goto bail;
1590 }
1591
1592 if (register_android_media_MediaMuxer(env) < 0) {
1593 ALOGE("ERROR: MediaMuxer native registration failed");
1594 goto bail;
1595 }
1596
1597 if (register_android_media_MediaCodecList(env) < 0) {
1598 ALOGE("ERROR: MediaCodec native registration failed");
1599 goto bail;
1600 }
1601
1602 if (register_android_media_Crypto(env) < 0) {
1603 ALOGE("ERROR: MediaCodec native registration failed");
1604 goto bail;
1605 }
1606
1607 if (register_android_media_Drm(env) < 0) {
1608 ALOGE("ERROR: MediaDrm native registration failed");
1609 goto bail;
1610 }
1611
1612 if (register_android_media_Descrambler(env) < 0) {
1613 ALOGE("ERROR: MediaDescrambler native registration failed");
1614 goto bail;
1615 }
1616
1617 if (register_android_media_MediaHTTPConnection(env) < 0) {
1618 ALOGE("ERROR: MediaHTTPConnection native registration failed");
1619 goto bail;
1620 }
1621
1622 /* success -- return valid version number */
1623 result = JNI_VERSION_1_4;
1624
1625 bail:
1626 return result;
1627 }
1628
1629 // KTHXBYE
1630