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