blob: 95522001d34203c6bd59584e7e5ac75328177c7d [file] [log] [blame]
James Dongc371a022011-04-06 12:16:07 -07001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
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>
Lajos Molnarb3d5fd22015-04-22 13:14:34 -070023#include <media/AudioResamplerPublic.h>
Andreas Huberd2506a52014-01-29 10:32:46 -080024#include <media/IMediaHTTPService.h>
Nicolas Catania20cb94e2009-05-12 23:25:55 -070025#include <media/MediaPlayerInterface.h>
Ray Essick81fbc5b2019-12-07 06:24:59 -080026#include <media/MediaMetricsItem.h>
Dongwon Kangefada5692017-10-09 11:46:39 -070027#include <media/stagefright/foundation/ByteUtils.h> // for FOURCC definition
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028#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"
Orion Hodson329c6122020-06-02 13:22:06 +010035#include <nativehelper/JNIPlatformHelp.h>
Colin Cross082aec62020-08-27 04:12:26 +000036#include <nativehelper/ScopedUtfChars.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037#include "android_runtime/AndroidRuntime.h"
Ted Bonkenburg1ee60112011-07-26 09:51:18 -070038#include "android_runtime/android_view_Surface.h"
Ruben Brunk87eac992013-09-09 17:44:59 -070039#include "android_runtime/Log.h"
The Android Open Source Project4df24232009-03-05 14:34:35 -080040#include "utils/Errors.h" // for status_t
Andreas Huber25643002010-01-28 11:19:57 -080041#include "utils/KeyedVector.h"
42#include "utils/String8.h"
Chris Watkins4eaa2932015-03-20 10:31:42 -070043#include "android_media_MediaDataSource.h"
Ray Essick0e0fee12017-01-25 18:01:56 -080044#include "android_media_MediaMetricsJNI.h"
Wei Jia2d61e2b2015-05-08 15:23:28 -070045#include "android_media_PlaybackParams.h"
46#include "android_media_SyncParams.h"
Andy Hung035d4ec2017-01-24 13:45:02 -080047#include "android_media_VolumeShaper.h"
Jooyung Hancb1e8962019-02-21 14:18:11 +090048#include "android_media_Streams.h"
James Dong79f407c2011-05-05 12:50:04 -070049
Jeff Sharkeyd84e1ce2012-03-06 18:26:19 -080050#include "android_os_Parcel.h"
Nicolas Catania20cb94e2009-05-12 23:25:55 -070051#include "android_util_Binder.h"
52#include <binder/Parcel.h>
Andy McFaddend47f7d82012-12-18 09:48:38 -080053#include <gui/IGraphicBufferProducer.h>
Mathias Agopian8335f1c2012-02-25 18:48:35 -080054#include <gui/Surface.h>
Gloria Wangd211f412011-02-19 18:37:57 -080055#include <binder/IPCThreadState.h>
56#include <binder/IServiceManager.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057
Andreas Huberd2506a52014-01-29 10:32:46 -080058#include "android_util_Binder.h"
Hassan Shojania0b52e952017-01-23 09:06:31 -080059
60// Modular DRM begin
Hassan Shojania0b52e952017-01-23 09:06:31 -080061#define FIND_CLASS(var, className) \
62var = env->FindClass(className); \
63LOG_FATAL_IF(! (var), "Unable to find class " className);
64
Hassan Shojania0b52e952017-01-23 09:06:31 -080065#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
66var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
67LOG_FATAL_IF(! (var), "Unable to find method " fieldName);
68
Hassan Shojania0b52e952017-01-23 09:06:31 -080069struct StateExceptionFields {
70 jmethodID init;
71 jclass classId;
72};
73
Hassan Shojania06b25fb2017-02-06 21:09:42 -080074static StateExceptionFields gStateExceptionFields;
Hassan Shojania0b52e952017-01-23 09:06:31 -080075// Modular DRM end
76
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077// ----------------------------------------------------------------------------
78
79using namespace android;
80
Ivan Lozano330d8762017-08-08 12:51:06 -070081using media::VolumeShaper;
82
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083// ----------------------------------------------------------------------------
84
85struct fields_t {
86 jfieldID context;
Ted Bonkenburg1ee60112011-07-26 09:51:18 -070087 jfieldID surface_texture;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
89 jmethodID post_event;
Andreas Huberd5f9fa52013-05-28 14:39:39 -070090
91 jmethodID proxyConfigGetHost;
92 jmethodID proxyConfigGetPort;
93 jmethodID proxyConfigGetExclusionList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094};
95static fields_t fields;
96
Wei Jia2d61e2b2015-05-08 15:23:28 -070097static PlaybackParams::fields_t gPlaybackParamsFields;
98static SyncParams::fields_t gSyncParamsFields;
Andy Hung035d4ec2017-01-24 13:45:02 -080099static VolumeShaperHelper::fields_t gVolumeShaperFields;
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101static Mutex sLock;
102
103// ----------------------------------------------------------------------------
104// ref-counted object for callbacks
105class JNIMediaPlayerListener: public MediaPlayerListener
106{
107public:
108 JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
109 ~JNIMediaPlayerListener();
Gloria Wang162ee492011-04-11 17:23:27 -0700110 virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111private:
112 JNIMediaPlayerListener();
113 jclass mClass; // Reference to MediaPlayer class
114 jobject mObject; // Weak ref to MediaPlayer Java object to call on
115};
116
117JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
118{
119
120 // Hold onto the MediaPlayer class for use in calling the static method
121 // that posts events to the application thread.
122 jclass clazz = env->GetObjectClass(thiz);
123 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000124 ALOGE("Can't find android/media/MediaPlayer");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 jniThrowException(env, "java/lang/Exception", NULL);
126 return;
127 }
128 mClass = (jclass)env->NewGlobalRef(clazz);
129
130 // We use a weak reference so the MediaPlayer object can be garbage collected.
131 // The reference is only used as a proxy for callbacks.
132 mObject = env->NewGlobalRef(weak_thiz);
133}
134
135JNIMediaPlayerListener::~JNIMediaPlayerListener()
136{
137 // remove global references
138 JNIEnv *env = AndroidRuntime::getJNIEnv();
139 env->DeleteGlobalRef(mObject);
140 env->DeleteGlobalRef(mClass);
141}
142
Gloria Wang162ee492011-04-11 17:23:27 -0700143void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144{
145 JNIEnv *env = AndroidRuntime::getJNIEnv();
Gloria Wang162ee492011-04-11 17:23:27 -0700146 if (obj && obj->dataSize() > 0) {
Insun Kang333c0992012-07-10 12:47:03 +0900147 jobject jParcel = createJavaParcelObject(env);
148 if (jParcel != NULL) {
149 Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
Insun Kang89020972012-05-01 14:13:19 +0900150 nativeParcel->setData(obj->data(), obj->dataSize());
Gloria Wang162ee492011-04-11 17:23:27 -0700151 env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
Insun Kang333c0992012-07-10 12:47:03 +0900152 msg, ext1, ext2, jParcel);
Elliott Hughes99f75212013-11-13 15:10:40 -0800153 env->DeleteLocalRef(jParcel);
Gloria Wang162ee492011-04-11 17:23:27 -0700154 }
155 } else {
156 env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
157 msg, ext1, ext2, NULL);
158 }
Insun Kang89020972012-05-01 14:13:19 +0900159 if (env->ExceptionCheck()) {
160 ALOGW("An exception occurred while notifying an event.");
161 LOGW_EX(env);
162 env->ExceptionClear();
163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164}
165
166// ----------------------------------------------------------------------------
167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
169{
170 Mutex::Autolock l(sLock);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000171 MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 return sp<MediaPlayer>(p);
173}
174
175static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
176{
177 Mutex::Autolock l(sLock);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000178 sp<MediaPlayer> old = (MediaPlayer*)env->GetLongField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 if (player.get()) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800180 player->incStrong((void*)setMediaPlayer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 }
182 if (old != 0) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800183 old->decStrong((void*)setMediaPlayer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000185 env->SetLongField(thiz, fields.context, (jlong)player.get());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 return old;
187}
188
Nicolas Catania32f82772009-06-11 16:33:49 -0700189// If exception is NULL and opStatus is not OK, this method sends an error
190// event to the client application; otherwise, if exception is not NULL and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191// opStatus is not OK, this method throws the given exception to the client
192// application.
193static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message)
194{
195 if (exception == NULL) { // Don't throw exception. Instead, send an event.
196 if (opStatus != (status_t) OK) {
197 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
198 if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0);
199 }
200 } else { // Throw exception!
201 if ( opStatus == (status_t) INVALID_OPERATION ) {
202 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700203 } else if ( opStatus == (status_t) BAD_VALUE ) {
204 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
Dave Burkefc301b02011-08-30 14:39:17 +0100205 } else if ( opStatus == (status_t) PERMISSION_DENIED ) {
206 jniThrowException(env, "java/lang/SecurityException", NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 } else if ( opStatus != (status_t) OK ) {
208 if (strlen(message) > 230) {
209 // if the message is too long, don't bother displaying the status code
210 jniThrowException( env, exception, message);
211 } else {
212 char msg[256];
213 // append the status code to the message
214 sprintf(msg, "%s: status=0x%X", message, opStatus);
215 jniThrowException( env, exception, msg);
216 }
217 }
218 }
219}
220
221static void
Andreas Huber25643002010-01-28 11:19:57 -0800222android_media_MediaPlayer_setDataSourceAndHeaders(
Andreas Huberd2506a52014-01-29 10:32:46 -0800223 JNIEnv *env, jobject thiz, jobject httpServiceBinderObj, jstring path,
James Dong17524dc2011-05-04 13:41:58 -0700224 jobjectArray keys, jobjectArray values) {
225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
227 if (mp == NULL ) {
228 jniThrowException(env, "java/lang/IllegalStateException", NULL);
229 return;
230 }
231
232 if (path == NULL) {
233 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
234 return;
235 }
236
James Dongc371a022011-04-06 12:16:07 -0700237 const char *tmp = env->GetStringUTFChars(path, NULL);
238 if (tmp == NULL) { // Out of memory
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 return;
240 }
Steve Block71f2cf12011-10-20 11:56:00 +0100241 ALOGV("setDataSource: path %s", tmp);
Andreas Huber25643002010-01-28 11:19:57 -0800242
James Dongc371a022011-04-06 12:16:07 -0700243 String8 pathStr(tmp);
244 env->ReleaseStringUTFChars(path, tmp);
245 tmp = NULL;
246
James Dong17524dc2011-05-04 13:41:58 -0700247 // We build a KeyedVector out of the key and val arrays
Andreas Huber25643002010-01-28 11:19:57 -0800248 KeyedVector<String8, String8> headersVector;
James Dong79f407c2011-05-05 12:50:04 -0700249 if (!ConvertKeyValueArraysToKeyedVector(
250 env, keys, values, &headersVector)) {
251 return;
Andreas Huber25643002010-01-28 11:19:57 -0800252 }
253
Andreas Huberd2506a52014-01-29 10:32:46 -0800254 sp<IMediaHTTPService> httpService;
255 if (httpServiceBinderObj != NULL) {
256 sp<IBinder> binder = ibinderForJavaObject(env, httpServiceBinderObj);
257 httpService = interface_cast<IMediaHTTPService>(binder);
258 }
259
Andreas Huber25643002010-01-28 11:19:57 -0800260 status_t opStatus =
261 mp->setDataSource(
Andreas Huberd2506a52014-01-29 10:32:46 -0800262 httpService,
James Dongc371a022011-04-06 12:16:07 -0700263 pathStr,
James Dong79f407c2011-05-05 12:50:04 -0700264 headersVector.size() > 0? &headersVector : NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265
Andreas Huber25643002010-01-28 11:19:57 -0800266 process_media_player_call(
267 env, thiz, opStatus, "java/io/IOException",
268 "setDataSource failed." );
269}
270
271static void
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
273{
274 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
275 if (mp == NULL ) {
276 jniThrowException(env, "java/lang/IllegalStateException", NULL);
277 return;
278 }
279
280 if (fileDescriptor == NULL) {
281 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
282 return;
283 }
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700284 int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
Steve Block71f2cf12011-10-20 11:56:00 +0100285 ALOGV("setDataSourceFD: fd %d", fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
287}
288
Chris Watkins4eaa2932015-03-20 10:31:42 -0700289static void
290android_media_MediaPlayer_setDataSourceCallback(JNIEnv *env, jobject thiz, jobject dataSource)
291{
292 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
293 if (mp == NULL ) {
294 jniThrowException(env, "java/lang/IllegalStateException", NULL);
295 return;
296 }
297
298 if (dataSource == NULL) {
299 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
300 return;
301 }
302 sp<IDataSource> callbackDataSource = new JMediaDataSource(env, dataSource);
303 process_media_player_call(env, thiz, mp->setDataSource(callbackDataSource), "java/lang/RuntimeException", "setDataSourceCallback failed." );
304}
305
Andy McFaddend47f7d82012-12-18 09:48:38 -0800306static sp<IGraphicBufferProducer>
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700307getVideoSurfaceTexture(JNIEnv* env, jobject thiz) {
Ashok Bhat075e9a12014-01-06 13:45:09 +0000308 IGraphicBufferProducer * const p = (IGraphicBufferProducer*)env->GetLongField(thiz, fields.surface_texture);
Andy McFaddend47f7d82012-12-18 09:48:38 -0800309 return sp<IGraphicBufferProducer>(p);
Dave Sparks8b0b1742009-05-29 09:01:20 -0700310}
311
312static void
Gloria Wangd59310d2011-09-14 13:59:45 -0700313decVideoSurfaceRef(JNIEnv *env, jobject thiz)
314{
Gloria Wange828beb2011-09-15 15:28:43 -0700315 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
316 if (mp == NULL) {
317 return;
318 }
319
Andy McFaddend47f7d82012-12-18 09:48:38 -0800320 sp<IGraphicBufferProducer> old_st = getVideoSurfaceTexture(env, thiz);
Gloria Wangd59310d2011-09-14 13:59:45 -0700321 if (old_st != NULL) {
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800322 old_st->decStrong((void*)decVideoSurfaceRef);
Gloria Wangd59310d2011-09-14 13:59:45 -0700323 }
324}
325
326static void
James Dong43ef9132011-08-12 11:33:27 -0700327setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface, jboolean mediaPlayerMustBeAlive)
Dave Sparks8b0b1742009-05-29 09:01:20 -0700328{
329 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
James Dong43ef9132011-08-12 11:33:27 -0700330 if (mp == NULL) {
331 if (mediaPlayerMustBeAlive) {
332 jniThrowException(env, "java/lang/IllegalStateException", NULL);
333 }
Dave Sparks8b0b1742009-05-29 09:01:20 -0700334 return;
335 }
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700336
Gloria Wangd59310d2011-09-14 13:59:45 -0700337 decVideoSurfaceRef(env, thiz);
338
Andy McFaddend47f7d82012-12-18 09:48:38 -0800339 sp<IGraphicBufferProducer> new_st;
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700340 if (jsurface) {
Jeff Brown64a55af2012-08-26 02:47:39 -0700341 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
Jamie Gennisf76afc82011-10-14 19:06:55 -0700342 if (surface != NULL) {
Mathias Agopian52800612013-02-14 17:11:20 -0800343 new_st = surface->getIGraphicBufferProducer();
James Dong097922b9c2012-10-04 09:16:40 -0700344 if (new_st == NULL) {
345 jniThrowException(env, "java/lang/IllegalArgumentException",
346 "The surface does not have a binding SurfaceTexture!");
347 return;
348 }
Mathias Agopianb1d90c82013-03-06 17:45:42 -0800349 new_st->incStrong((void*)decVideoSurfaceRef);
Jamie Gennisf76afc82011-10-14 19:06:55 -0700350 } else {
351 jniThrowException(env, "java/lang/IllegalArgumentException",
352 "The surface has been released");
353 return;
354 }
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700355 }
Gloria Wangd59310d2011-09-14 13:59:45 -0700356
Ashok Bhat075e9a12014-01-06 13:45:09 +0000357 env->SetLongField(thiz, fields.surface_texture, (jlong)new_st.get());
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700358
359 // This will fail if the media player has not been initialized yet. This
360 // can be the case if setDisplay() on MediaPlayer.java has been called
361 // before setDataSource(). The redundant call to setVideoSurfaceTexture()
362 // in prepare/prepareAsync covers for this case.
363 mp->setVideoSurfaceTexture(new_st);
Dave Sparks8b0b1742009-05-29 09:01:20 -0700364}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365
366static void
James Dong43ef9132011-08-12 11:33:27 -0700367android_media_MediaPlayer_setVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface)
368{
369 setVideoSurface(env, thiz, jsurface, true /* mediaPlayerMustBeAlive */);
370}
371
Vlad Popa66824a32022-08-12 16:05:05 +0200372static jint
373android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz, jobject piidParcel)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374{
375 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
Vlad Popa66824a32022-08-12 16:05:05 +0200376 if (mp == nullptr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Vlad Popa66824a32022-08-12 16:05:05 +0200378 return UNKNOWN_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700380
381 // Handle the case where the display surface was set before the mp was
382 // initialized. We try again to make it stick.
Andy McFaddend47f7d82012-12-18 09:48:38 -0800383 sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700384 mp->setVideoSurfaceTexture(st);
385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
Vlad Popa66824a32022-08-12 16:05:05 +0200387
388 // update the piid
389 Parcel *request = parcelForJavaObject(env, piidParcel);
390 auto reply = std::make_unique<Parcel>();
391 return static_cast<jint>(mp->invoke(*request, reply.get()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392}
393
Vlad Popa66824a32022-08-12 16:05:05 +0200394static jint
395android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz, jobject piidParcel)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396{
397 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
Vlad Popa66824a32022-08-12 16:05:05 +0200398 if (mp == nullptr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Vlad Popa66824a32022-08-12 16:05:05 +0200400 return UNKNOWN_ERROR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700402
403 // Handle the case where the display surface was set before the mp was
404 // initialized. We try again to make it stick.
Andy McFaddend47f7d82012-12-18 09:48:38 -0800405 sp<IGraphicBufferProducer> st = getVideoSurfaceTexture(env, thiz);
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700406 mp->setVideoSurfaceTexture(st);
407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." );
Vlad Popa66824a32022-08-12 16:05:05 +0200409
410 // update the piid
411 Parcel *request = parcelForJavaObject(env, piidParcel);
412 auto reply = std::make_unique<Parcel>();
413 return static_cast<jint>(mp->invoke(*request, reply.get()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414}
415
416static void
417android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
418{
Steve Block71f2cf12011-10-20 11:56:00 +0100419 ALOGV("start");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
421 if (mp == NULL ) {
422 jniThrowException(env, "java/lang/IllegalStateException", NULL);
423 return;
424 }
425 process_media_player_call( env, thiz, mp->start(), NULL, NULL );
426}
427
428static void
429android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz)
430{
Steve Block71f2cf12011-10-20 11:56:00 +0100431 ALOGV("stop");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
433 if (mp == NULL ) {
434 jniThrowException(env, "java/lang/IllegalStateException", NULL);
435 return;
436 }
Nicolas Catania32f82772009-06-11 16:33:49 -0700437 process_media_player_call( env, thiz, mp->stop(), NULL, NULL );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438}
439
440static void
441android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz)
442{
Steve Block71f2cf12011-10-20 11:56:00 +0100443 ALOGV("pause");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
445 if (mp == NULL ) {
446 jniThrowException(env, "java/lang/IllegalStateException", NULL);
447 return;
448 }
449 process_media_player_call( env, thiz, mp->pause(), NULL, NULL );
450}
451
452static jboolean
453android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
454{
455 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
456 if (mp == NULL ) {
457 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000458 return JNI_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800460 const jboolean is_playing = mp->isPlaying();
461
Steve Block71f2cf12011-10-20 11:56:00 +0100462 ALOGV("isPlaying: %d", is_playing);
The Android Open Source Project4df24232009-03-05 14:34:35 -0800463 return is_playing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464}
465
466static void
Wei Jia2d61e2b2015-05-08 15:23:28 -0700467android_media_MediaPlayer_setPlaybackParams(JNIEnv *env, jobject thiz, jobject params)
Wei Jiad93fcf42015-02-09 16:05:53 -0800468{
469 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
470 if (mp == NULL) {
471 jniThrowException(env, "java/lang/IllegalStateException", NULL);
472 return;
473 }
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700474
Wei Jia2d61e2b2015-05-08 15:23:28 -0700475 PlaybackParams pbp;
476 pbp.fillFromJobject(env, gPlaybackParamsFields, params);
477 ALOGV("setPlaybackParams: %d:%f %d:%f %d:%u %d:%u",
478 pbp.speedSet, pbp.audioRate.mSpeed,
479 pbp.pitchSet, pbp.audioRate.mPitch,
480 pbp.audioFallbackModeSet, pbp.audioRate.mFallbackMode,
481 pbp.audioStretchModeSet, pbp.audioRate.mStretchMode);
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700482
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700483 AudioPlaybackRate rate;
484 status_t err = mp->getPlaybackSettings(&rate);
485 if (err == OK) {
486 bool updatedRate = false;
Wei Jia2d61e2b2015-05-08 15:23:28 -0700487 if (pbp.speedSet) {
488 rate.mSpeed = pbp.audioRate.mSpeed;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700489 updatedRate = true;
490 }
Wei Jia2d61e2b2015-05-08 15:23:28 -0700491 if (pbp.pitchSet) {
492 rate.mPitch = pbp.audioRate.mPitch;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700493 updatedRate = true;
494 }
Wei Jia2d61e2b2015-05-08 15:23:28 -0700495 if (pbp.audioFallbackModeSet) {
496 rate.mFallbackMode = pbp.audioRate.mFallbackMode;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700497 updatedRate = true;
498 }
Wei Jia2d61e2b2015-05-08 15:23:28 -0700499 if (pbp.audioStretchModeSet) {
500 rate.mStretchMode = pbp.audioRate.mStretchMode;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700501 updatedRate = true;
502 }
503 if (updatedRate) {
504 err = mp->setPlaybackSettings(rate);
505 }
506 }
507 process_media_player_call(
508 env, thiz, err,
509 "java/lang/IllegalStateException", "unexpected error");
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700510}
511
512static jobject
Wei Jia2d61e2b2015-05-08 15:23:28 -0700513android_media_MediaPlayer_getPlaybackParams(JNIEnv *env, jobject thiz)
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700514{
515 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
516 if (mp == NULL) {
517 jniThrowException(env, "java/lang/IllegalStateException", NULL);
518 return NULL;
519 }
520
Wei Jia2d61e2b2015-05-08 15:23:28 -0700521 PlaybackParams pbp;
522 AudioPlaybackRate &audioRate = pbp.audioRate;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700523 process_media_player_call(
524 env, thiz, mp->getPlaybackSettings(&audioRate),
525 "java/lang/IllegalStateException", "unexpected error");
Dongwon Kang44801272018-05-23 17:38:35 -0700526 if (env->ExceptionCheck()) {
527 return nullptr;
528 }
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700529 ALOGV("getPlaybackSettings: %f %f %d %d",
530 audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
531
Wei Jia2d61e2b2015-05-08 15:23:28 -0700532 pbp.speedSet = true;
533 pbp.pitchSet = true;
534 pbp.audioFallbackModeSet = true;
535 pbp.audioStretchModeSet = true;
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700536
Wei Jia2d61e2b2015-05-08 15:23:28 -0700537 return pbp.asJobject(env, gPlaybackParamsFields);
Wei Jiad93fcf42015-02-09 16:05:53 -0800538}
539
540static void
Wei Jia2d61e2b2015-05-08 15:23:28 -0700541android_media_MediaPlayer_setSyncParams(JNIEnv *env, jobject thiz, jobject params)
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700542{
543 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
544 if (mp == NULL) {
545 jniThrowException(env, "java/lang/IllegalStateException", NULL);
546 return;
547 }
548
Wei Jia2d61e2b2015-05-08 15:23:28 -0700549 SyncParams scp;
550 scp.fillFromJobject(env, gSyncParamsFields, params);
551 ALOGV("setSyncParams: %d:%d %d:%d %d:%f %d:%f",
552 scp.syncSourceSet, scp.sync.mSource,
553 scp.audioAdjustModeSet, scp.sync.mAudioAdjustMode,
554 scp.toleranceSet, scp.sync.mTolerance,
555 scp.frameRateSet, scp.frameRate);
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700556
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700557 AVSyncSettings avsync;
558 float videoFrameRate;
559 status_t err = mp->getSyncSettings(&avsync, &videoFrameRate);
560 if (err == OK) {
Wei Jia2d61e2b2015-05-08 15:23:28 -0700561 bool updatedSync = scp.frameRateSet;
562 if (scp.syncSourceSet) {
563 avsync.mSource = scp.sync.mSource;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700564 updatedSync = true;
565 }
Wei Jia2d61e2b2015-05-08 15:23:28 -0700566 if (scp.audioAdjustModeSet) {
567 avsync.mAudioAdjustMode = scp.sync.mAudioAdjustMode;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700568 updatedSync = true;
569 }
Wei Jia2d61e2b2015-05-08 15:23:28 -0700570 if (scp.toleranceSet) {
571 avsync.mTolerance = scp.sync.mTolerance;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700572 updatedSync = true;
573 }
574 if (updatedSync) {
Wei Jia2d61e2b2015-05-08 15:23:28 -0700575 err = mp->setSyncSettings(avsync, scp.frameRateSet ? scp.frameRate : -1.f);
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700576 }
577 }
578 process_media_player_call(
579 env, thiz, err,
580 "java/lang/IllegalStateException", "unexpected error");
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700581}
582
583static jobject
Wei Jia2d61e2b2015-05-08 15:23:28 -0700584android_media_MediaPlayer_getSyncParams(JNIEnv *env, jobject thiz)
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700585{
586 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
587 if (mp == NULL) {
588 jniThrowException(env, "java/lang/IllegalStateException", NULL);
589 return NULL;
590 }
591
Wei Jia2d61e2b2015-05-08 15:23:28 -0700592 SyncParams scp;
593 scp.frameRate = -1.f;
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700594 process_media_player_call(
Wei Jia2d61e2b2015-05-08 15:23:28 -0700595 env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700596 "java/lang/IllegalStateException", "unexpected error");
Dongwon Kang44801272018-05-23 17:38:35 -0700597 if (env->ExceptionCheck()) {
598 return nullptr;
599 }
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700600
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700601 ALOGV("getSyncSettings: %d %d %f %f",
Wei Jia2d61e2b2015-05-08 15:23:28 -0700602 scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700603
Alice Kuoc2c679d2020-07-30 16:14:48 +0000604 // check params
Wei Jia2d61e2b2015-05-08 15:23:28 -0700605 if (scp.sync.mSource >= AVSYNC_SOURCE_MAX
606 || scp.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
607 || scp.sync.mTolerance < 0.f
608 || scp.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
Lajos Molnar05ebffe2015-04-29 20:41:19 -0700609 jniThrowException(env, "java/lang/IllegalStateException", NULL);
610 return NULL;
611 }
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700612
Wei Jia2d61e2b2015-05-08 15:23:28 -0700613 scp.syncSourceSet = true;
614 scp.audioAdjustModeSet = true;
615 scp.toleranceSet = true;
616 scp.frameRateSet = scp.frameRate >= 0.f;
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700617
Wei Jia2d61e2b2015-05-08 15:23:28 -0700618 return scp.asJobject(env, gSyncParamsFields);
Lajos Molnarc98f58e2015-04-22 19:28:53 -0700619}
620
621static void
Wei Jiabebeaf92017-04-19 16:22:10 -0700622android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jlong msec, jint mode)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623{
624 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
625 if (mp == NULL ) {
626 jniThrowException(env, "java/lang/IllegalStateException", NULL);
627 return;
628 }
Wei Jiabebeaf92017-04-19 16:22:10 -0700629 ALOGV("seekTo: %lld(msec), mode=%d", (long long)msec, mode);
630 process_media_player_call( env, thiz, mp->seekTo((int)msec, (MediaPlayerSeekMode)mode), NULL, NULL );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631}
632
Wei Jiac02f09d2017-09-13 18:19:48 -0700633static void
634android_media_MediaPlayer_notifyAt(JNIEnv *env, jobject thiz, jlong mediaTimeUs)
635{
636 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
637 if (mp == NULL) {
638 jniThrowException(env, "java/lang/IllegalStateException", NULL);
639 return;
640 }
641 ALOGV("notifyAt: %lld", (long long)mediaTimeUs);
642 process_media_player_call( env, thiz, mp->notifyAt((int64_t)mediaTimeUs), NULL, NULL );
643}
644
Ashok Bhat075e9a12014-01-06 13:45:09 +0000645static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz)
647{
648 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
649 if (mp == NULL ) {
650 jniThrowException(env, "java/lang/IllegalStateException", NULL);
651 return 0;
652 }
653 int w;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800654 if (0 != mp->getVideoWidth(&w)) {
Steve Block3762c312012-01-06 19:20:56 +0000655 ALOGE("getVideoWidth failed");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800656 w = 0;
657 }
Steve Block71f2cf12011-10-20 11:56:00 +0100658 ALOGV("getVideoWidth: %d", w);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000659 return (jint) w;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660}
661
Ashok Bhat075e9a12014-01-06 13:45:09 +0000662static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz)
664{
665 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
666 if (mp == NULL ) {
667 jniThrowException(env, "java/lang/IllegalStateException", NULL);
668 return 0;
669 }
670 int h;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800671 if (0 != mp->getVideoHeight(&h)) {
Steve Block3762c312012-01-06 19:20:56 +0000672 ALOGE("getVideoHeight failed");
The Android Open Source Project4df24232009-03-05 14:34:35 -0800673 h = 0;
674 }
Steve Block71f2cf12011-10-20 11:56:00 +0100675 ALOGV("getVideoHeight: %d", h);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000676 return (jint) h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677}
678
Ray Essick0e0fee12017-01-25 18:01:56 -0800679static jobject
Ray Essickf2d0e402017-03-09 10:17:51 -0800680android_media_MediaPlayer_native_getMetrics(JNIEnv *env, jobject thiz)
Ray Essick0e0fee12017-01-25 18:01:56 -0800681{
682 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
683 if (mp == NULL ) {
684 jniThrowException(env, "java/lang/IllegalStateException", NULL);
685 return 0;
686 }
687
688 Parcel p;
689 int key = FOURCC('m','t','r','X');
690 status_t status = mp->getParameter(key, &p);
691 if (status != OK) {
692 ALOGD("getMetrics() failed: %d", status);
693 return (jobject) NULL;
694 }
695
Ray Essick81fbc5b2019-12-07 06:24:59 -0800696 std::unique_ptr<mediametrics::Item> item(mediametrics::Item::create());
Ray Essick0e0fee12017-01-25 18:01:56 -0800697 item->readFromParcel(p);
Ray Essicke9b9c982019-01-28 20:34:42 -0800698 jobject mybundle = MediaMetricsJNI::writeMetricsToBundle(env, item.get(), NULL);
Ray Essick0e0fee12017-01-25 18:01:56 -0800699
700 return mybundle;
701}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702
Ashok Bhat075e9a12014-01-06 13:45:09 +0000703static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz)
705{
706 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
707 if (mp == NULL ) {
708 jniThrowException(env, "java/lang/IllegalStateException", NULL);
709 return 0;
710 }
711 int msec;
712 process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL );
Steve Block71f2cf12011-10-20 11:56:00 +0100713 ALOGV("getCurrentPosition: %d (msec)", msec);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000714 return (jint) msec;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715}
716
Ashok Bhat075e9a12014-01-06 13:45:09 +0000717static jint
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz)
719{
720 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
721 if (mp == NULL ) {
722 jniThrowException(env, "java/lang/IllegalStateException", NULL);
723 return 0;
724 }
725 int msec;
726 process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL );
Steve Block71f2cf12011-10-20 11:56:00 +0100727 ALOGV("getDuration: %d (msec)", msec);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000728 return (jint) msec;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729}
730
731static void
732android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz)
733{
Steve Block71f2cf12011-10-20 11:56:00 +0100734 ALOGV("reset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
736 if (mp == NULL ) {
737 jniThrowException(env, "java/lang/IllegalStateException", NULL);
738 return;
739 }
740 process_media_player_call( env, thiz, mp->reset(), NULL, NULL );
741}
742
743static void
Ashok Bhat075e9a12014-01-06 13:45:09 +0000744android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, jint streamtype)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745{
Steve Block71f2cf12011-10-20 11:56:00 +0100746 ALOGV("setAudioStreamType: %d", streamtype);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
748 if (mp == NULL ) {
749 jniThrowException(env, "java/lang/IllegalStateException", NULL);
750 return;
751 }
Glenn Kastenbc1d77b2012-01-12 16:38:12 -0800752 process_media_player_call( env, thiz, mp->setAudioStreamType((audio_stream_type_t) streamtype) , NULL, NULL );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753}
754
John Spurlock1af30c72014-03-10 08:33:35 -0400755static jint
756android_media_MediaPlayer_getAudioStreamType(JNIEnv *env, jobject thiz)
757{
758 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
759 if (mp == NULL ) {
760 jniThrowException(env, "java/lang/IllegalStateException", NULL);
761 return 0;
762 }
763 audio_stream_type_t streamtype;
764 process_media_player_call( env, thiz, mp->getAudioStreamType(&streamtype), NULL, NULL );
765 ALOGV("getAudioStreamType: %d (streamtype)", streamtype);
766 return (jint) streamtype;
767}
768
Jean-Michel Trivi8df982d2014-06-26 12:05:16 -0700769static jboolean
770android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request)
771{
772 ALOGV("setParameter: key %d", key);
773 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
774 if (mp == NULL ) {
775 jniThrowException(env, "java/lang/IllegalStateException", NULL);
776 return false;
777 }
778
779 Parcel *request = parcelForJavaObject(env, java_request);
780 status_t err = mp->setParameter(key, *request);
781 if (err == OK) {
782 return true;
783 } else {
784 return false;
785 }
786}
787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788static void
789android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping)
790{
Steve Block71f2cf12011-10-20 11:56:00 +0100791 ALOGV("setLooping: %d", looping);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
793 if (mp == NULL ) {
794 jniThrowException(env, "java/lang/IllegalStateException", NULL);
795 return;
796 }
797 process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL );
798}
799
800static jboolean
801android_media_MediaPlayer_isLooping(JNIEnv *env, jobject thiz)
802{
Steve Block71f2cf12011-10-20 11:56:00 +0100803 ALOGV("isLooping");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
805 if (mp == NULL ) {
806 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000807 return JNI_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000809 return mp->isLooping() ? JNI_TRUE : JNI_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810}
811
812static void
Ashok Bhat075e9a12014-01-06 13:45:09 +0000813android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolume, jfloat rightVolume)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814{
Ashok Bhat075e9a12014-01-06 13:45:09 +0000815 ALOGV("setVolume: left %f right %f", (float) leftVolume, (float) rightVolume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
817 if (mp == NULL ) {
818 jniThrowException(env, "java/lang/IllegalStateException", NULL);
819 return;
820 }
Ashok Bhat075e9a12014-01-06 13:45:09 +0000821 process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL );
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822}
823
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700824// Sends the request and reply parcels to the media player via the
825// binder interface.
826static jint
827android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz,
828 jobject java_request, jobject java_reply)
829{
830 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
831 if (media_player == NULL ) {
832 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700833 return UNKNOWN_ERROR;
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700834 }
835
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700836 Parcel *request = parcelForJavaObject(env, java_request);
837 Parcel *reply = parcelForJavaObject(env, java_reply);
838
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700839 // Don't use process_media_player_call which use the async loop to
840 // report errors, instead returns the status.
Ashok Bhat075e9a12014-01-06 13:45:09 +0000841 return (jint) media_player->invoke(*request, reply);
Nicolas Catania20cb94e2009-05-12 23:25:55 -0700842}
843
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700844// Sends the new filter to the client.
845static jint
846android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
847{
848 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
849 if (media_player == NULL ) {
850 jniThrowException(env, "java/lang/IllegalStateException", NULL);
851 return UNKNOWN_ERROR;
852 }
853
854 Parcel *filter = parcelForJavaObject(env, request);
855
Nicolas Catania5d55c712009-07-09 09:21:33 -0700856 if (filter == NULL ) {
857 jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
858 return UNKNOWN_ERROR;
859 }
860
Ashok Bhat075e9a12014-01-06 13:45:09 +0000861 return (jint) media_player->setMetadataFilter(*filter);
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700862}
863
Nicolas Catania5d55c712009-07-09 09:21:33 -0700864static jboolean
865android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
866 jboolean apply_filter, jobject reply)
867{
868 sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
869 if (media_player == NULL ) {
870 jniThrowException(env, "java/lang/IllegalStateException", NULL);
Ashok Bhat075e9a12014-01-06 13:45:09 +0000871 return JNI_FALSE;
Nicolas Catania5d55c712009-07-09 09:21:33 -0700872 }
873
874 Parcel *metadata = parcelForJavaObject(env, reply);
875
876 if (metadata == NULL ) {
877 jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
Ashok Bhat075e9a12014-01-06 13:45:09 +0000878 return JNI_FALSE;
Nicolas Catania5d55c712009-07-09 09:21:33 -0700879 }
880
881 metadata->freeData();
882 // On return metadata is positioned at the beginning of the
883 // metadata. Note however that the parcel actually starts with the
884 // return code so you should not rewind the parcel using
885 // setDataPosition(0).
Ashok Bhat075e9a12014-01-06 13:45:09 +0000886 if (media_player->getMetadata(update_only, apply_filter, metadata) == OK) {
887 return JNI_TRUE;
888 } else {
889 return JNI_FALSE;
890 }
Nicolas Catania5d55c712009-07-09 09:21:33 -0700891}
892
Marco Nelissen4935d052009-08-03 11:12:58 -0700893// This function gets some field IDs, which in turn causes class initialization.
894// It is called from a static block in MediaPlayer, which won't run until the
895// first time an instance of this class is used.
896static void
897android_media_MediaPlayer_native_init(JNIEnv *env)
898{
899 jclass clazz;
900
901 clazz = env->FindClass("android/media/MediaPlayer");
902 if (clazz == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700903 return;
904 }
905
Ashok Bhat075e9a12014-01-06 13:45:09 +0000906 fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
Marco Nelissen4935d052009-08-03 11:12:58 -0700907 if (fields.context == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700908 return;
909 }
910
911 fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
912 "(Ljava/lang/Object;IIILjava/lang/Object;)V");
913 if (fields.post_event == NULL) {
Marco Nelissen4935d052009-08-03 11:12:58 -0700914 return;
915 }
916
Ashok Bhat075e9a12014-01-06 13:45:09 +0000917 fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
Ted Bonkenburg1ee60112011-07-26 09:51:18 -0700918 if (fields.surface_texture == NULL) {
Glenn Kastencc562a32011-02-08 17:26:17 -0800919 return;
920 }
Andreas Huberd5f9fa52013-05-28 14:39:39 -0700921
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700922 env->DeleteLocalRef(clazz);
923
Selim Gurun5ba69be2014-05-07 15:04:40 -0700924 clazz = env->FindClass("android/net/ProxyInfo");
Andreas Huberd5f9fa52013-05-28 14:39:39 -0700925 if (clazz == NULL) {
926 return;
927 }
928
929 fields.proxyConfigGetHost =
930 env->GetMethodID(clazz, "getHost", "()Ljava/lang/String;");
931
932 fields.proxyConfigGetPort =
933 env->GetMethodID(clazz, "getPort", "()I");
934
935 fields.proxyConfigGetExclusionList =
Selim Gurun5ba69be2014-05-07 15:04:40 -0700936 env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
Lajos Molnarb3d5fd22015-04-22 13:14:34 -0700937
938 env->DeleteLocalRef(clazz);
939
Hassan Shojania0b52e952017-01-23 09:06:31 -0800940 // Modular DRM
Hassan Shojania0b52e952017-01-23 09:06:31 -0800941 FIND_CLASS(clazz, "android/media/MediaDrm$MediaDrmStateException");
942 if (clazz) {
Hassan Shojania06b25fb2017-02-06 21:09:42 -0800943 GET_METHOD_ID(gStateExceptionFields.init, clazz, "<init>", "(ILjava/lang/String;)V");
944 gStateExceptionFields.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
Hassan Shojania0b52e952017-01-23 09:06:31 -0800945
946 env->DeleteLocalRef(clazz);
947 } else {
Hassan Shojania06b25fb2017-02-06 21:09:42 -0800948 ALOGE("JNI android_media_MediaPlayer_native_init couldn't "
Hassan Shojania0b52e952017-01-23 09:06:31 -0800949 "get clazz android/media/MediaDrm$MediaDrmStateException");
950 }
951
Wei Jia2d61e2b2015-05-08 15:23:28 -0700952 gPlaybackParamsFields.init(env);
953 gSyncParamsFields.init(env);
Andy Hung035d4ec2017-01-24 13:45:02 -0800954 gVolumeShaperFields.init(env);
Marco Nelissen4935d052009-08-03 11:12:58 -0700955}
Nicolas Cataniab2c69392009-07-08 08:57:42 -0700956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957static void
Colin Cross082aec62020-08-27 04:12:26 +0000958android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
Jan Sebechlebsky0bbdb712023-01-09 14:29:19 +0100959 jobject jAttributionSource,
960 jint jAudioSessionId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961{
Steve Block71f2cf12011-10-20 11:56:00 +0100962 ALOGV("native_setup");
Philip P. Moltmannfece2432020-07-17 16:39:54 -0700963
Svet Ganov2eebf922021-05-20 15:09:08 +0000964 Parcel* parcel = parcelForJavaObject(env, jAttributionSource);
965 android::content::AttributionSourceState attributionSource;
966 attributionSource.readFromParcel(parcel);
Jan Sebechlebsky0bbdb712023-01-09 14:29:19 +0100967 sp<MediaPlayer> mp = sp<MediaPlayer>::make(
968 attributionSource, static_cast<audio_session_t>(jAudioSessionId));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 if (mp == NULL) {
970 jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
971 return;
972 }
973
974 // create new listener and give it to MediaPlayer
975 sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
976 mp->setListener(listener);
977
978 // Stow our new C++ MediaPlayer in an opaque field in the Java object.
979 setMediaPlayer(env, thiz, mp);
980}
981
982static void
983android_media_MediaPlayer_release(JNIEnv *env, jobject thiz)
984{
Steve Block71f2cf12011-10-20 11:56:00 +0100985 ALOGV("release");
Gloria Wangd59310d2011-09-14 13:59:45 -0700986 decVideoSurfaceRef(env, thiz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0);
988 if (mp != NULL) {
989 // this prevents native callbacks after the object is released
990 mp->setListener(0);
991 mp->disconnect();
992 }
993}
994
995static void
996android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz)
997{
Steve Block71f2cf12011-10-20 11:56:00 +0100998 ALOGV("native_finalize");
Marco Nelissen8dc208472011-09-28 09:21:11 -0700999 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1000 if (mp != NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +00001001 ALOGW("MediaPlayer finalized without being released");
Marco Nelissen8dc208472011-09-28 09:21:11 -07001002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 android_media_MediaPlayer_release(env, thiz);
1004}
1005
Glenn Kasten33b84042016-03-08 12:02:55 -08001006static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz,
1007 jint sessionId) {
Steve Block71f2cf12011-10-20 11:56:00 +01001008 ALOGV("set_session_id(): %d", sessionId);
Eric Laurent619346f2010-06-21 09:27:30 -07001009 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1010 if (mp == NULL ) {
1011 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1012 return;
1013 }
Glenn Kasten33b84042016-03-08 12:02:55 -08001014 process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL,
1015 NULL);
Eric Laurent619346f2010-06-21 09:27:30 -07001016}
1017
1018static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
Steve Block71f2cf12011-10-20 11:56:00 +01001019 ALOGV("get_session_id()");
Eric Laurent619346f2010-06-21 09:27:30 -07001020 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1021 if (mp == NULL ) {
1022 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1023 return 0;
1024 }
1025
Ashok Bhat075e9a12014-01-06 13:45:09 +00001026 return (jint) mp->getAudioSessionId();
Eric Laurent619346f2010-06-21 09:27:30 -07001027}
1028
Eric Laurent7070b362010-07-16 07:43:46 -07001029static void
1030android_media_MediaPlayer_setAuxEffectSendLevel(JNIEnv *env, jobject thiz, jfloat level)
1031{
Steve Block71f2cf12011-10-20 11:56:00 +01001032 ALOGV("setAuxEffectSendLevel: level %f", level);
Eric Laurent7070b362010-07-16 07:43:46 -07001033 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1034 if (mp == NULL ) {
1035 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1036 return;
1037 }
1038 process_media_player_call( env, thiz, mp->setAuxEffectSendLevel(level), NULL, NULL );
1039}
1040
1041static void android_media_MediaPlayer_attachAuxEffect(JNIEnv *env, jobject thiz, jint effectId) {
Steve Block71f2cf12011-10-20 11:56:00 +01001042 ALOGV("attachAuxEffect(): %d", effectId);
Eric Laurent7070b362010-07-16 07:43:46 -07001043 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->attachAuxEffect(effectId), NULL, NULL );
1049}
1050
Gloria Wangd211f412011-02-19 18:37:57 -08001051static jint
Andreas Huberd2506a52014-01-29 10:32:46 -08001052android_media_MediaPlayer_pullBatteryData(
1053 JNIEnv *env, jobject /* thiz */, jobject java_reply)
Gloria Wangd211f412011-02-19 18:37:57 -08001054{
1055 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.player"));
1056 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1057 if (service.get() == NULL) {
1058 jniThrowException(env, "java/lang/RuntimeException", "cannot get MediaPlayerService");
1059 return UNKNOWN_ERROR;
1060 }
1061
1062 Parcel *reply = parcelForJavaObject(env, java_reply);
1063
Ashok Bhat075e9a12014-01-06 13:45:09 +00001064 return (jint) service->pullBatteryData(reply);
Gloria Wangd211f412011-02-19 18:37:57 -08001065}
1066
John Grossman720aa282012-02-22 15:38:35 -08001067static jint
1068android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz,
1069 jstring addrString, jint port) {
1070 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1071 if (mp == NULL ) {
1072 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1073 return INVALID_OPERATION;
1074 }
1075
1076 const char *cAddrString = NULL;
1077
1078 if (NULL != addrString) {
1079 cAddrString = env->GetStringUTFChars(addrString, NULL);
1080 if (cAddrString == NULL) { // Out of memory
1081 return NO_MEMORY;
1082 }
1083 }
1084 ALOGV("setRetransmitEndpoint: %s:%d",
1085 cAddrString ? cAddrString : "(null)", port);
1086
1087 status_t ret;
1088 if (cAddrString && (port > 0xFFFF)) {
1089 ret = BAD_VALUE;
1090 } else {
1091 ret = mp->setRetransmitEndpoint(cAddrString,
1092 static_cast<uint16_t>(port));
1093 }
1094
1095 if (NULL != addrString) {
1096 env->ReleaseStringUTFChars(addrString, cAddrString);
1097 }
1098
1099 if (ret == INVALID_OPERATION ) {
1100 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1101 }
1102
Ashok Bhat075e9a12014-01-06 13:45:09 +00001103 return (jint) ret;
John Grossman720aa282012-02-22 15:38:35 -08001104}
1105
Marco Nelissen84b83202012-02-28 16:07:44 -08001106static void
1107android_media_MediaPlayer_setNextMediaPlayer(JNIEnv *env, jobject thiz, jobject java_player)
1108{
1109 ALOGV("setNextMediaPlayer");
1110 sp<MediaPlayer> thisplayer = getMediaPlayer(env, thiz);
1111 if (thisplayer == NULL) {
1112 jniThrowException(env, "java/lang/IllegalStateException", "This player not initialized");
1113 return;
1114 }
1115 sp<MediaPlayer> nextplayer = (java_player == NULL) ? NULL : getMediaPlayer(env, java_player);
1116 if (nextplayer == NULL && java_player != NULL) {
1117 jniThrowException(env, "java/lang/IllegalStateException", "That player not initialized");
1118 return;
1119 }
1120
1121 if (nextplayer == thisplayer) {
1122 jniThrowException(env, "java/lang/IllegalArgumentException", "Next player can't be self");
1123 return;
1124 }
1125 // tie the two players together
1126 process_media_player_call(
1127 env, thiz, thisplayer->setNextMediaPlayer(nextplayer),
1128 "java/lang/IllegalArgumentException",
1129 "setNextMediaPlayer failed." );
1130 ;
1131}
1132
Andy Hung035d4ec2017-01-24 13:45:02 -08001133// Pass through the arguments to the MediaServer player implementation.
1134static jint android_media_MediaPlayer_applyVolumeShaper(JNIEnv *env, jobject thiz,
1135 jobject jconfig, jobject joperation) {
1136 // NOTE: hard code here to prevent platform issues. Must match VolumeShaper.java
1137 const int VOLUME_SHAPER_INVALID_OPERATION = -38;
1138
1139 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1140 if (mp == nullptr) {
1141 return (jint)VOLUME_SHAPER_INVALID_OPERATION;
1142 }
1143
1144 sp<VolumeShaper::Configuration> configuration;
1145 sp<VolumeShaper::Operation> operation;
1146 if (jconfig != nullptr) {
1147 configuration = VolumeShaperHelper::convertJobjectToConfiguration(
1148 env, gVolumeShaperFields, jconfig);
1149 ALOGV("applyVolumeShaper configuration: %s", configuration->toString().c_str());
1150 }
1151 if (joperation != nullptr) {
1152 operation = VolumeShaperHelper::convertJobjectToOperation(
1153 env, gVolumeShaperFields, joperation);
1154 ALOGV("applyVolumeShaper operation: %s", operation->toString().c_str());
1155 }
1156 VolumeShaper::Status status = mp->applyVolumeShaper(configuration, operation);
1157 if (status == INVALID_OPERATION) {
1158 status = VOLUME_SHAPER_INVALID_OPERATION;
1159 }
1160 return (jint)status; // if status < 0 an error, else a VolumeShaper id
1161}
1162
1163// Pass through the arguments to the MediaServer player implementation.
1164static jobject android_media_MediaPlayer_getVolumeShaperState(JNIEnv *env, jobject thiz,
1165 jint id) {
1166 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1167 if (mp == nullptr) {
1168 return (jobject)nullptr;
1169 }
1170
1171 sp<VolumeShaper::State> state = mp->getVolumeShaperState((int)id);
1172 if (state.get() == nullptr) {
1173 return (jobject)nullptr;
1174 }
1175 return VolumeShaperHelper::convertStateToJobject(env, gVolumeShaperFields, state);
1176}
1177
Hassan Shojania0b52e952017-01-23 09:06:31 -08001178/////////////////////////////////////////////////////////////////////////////////////
1179// Modular DRM begin
1180
1181// TODO: investigate if these can be shared with their MediaDrm counterparts
1182static void throwDrmStateException(JNIEnv *env, const char *msg, status_t err)
1183{
1184 ALOGE("Illegal DRM state exception: %s (%d)", msg, err);
1185
Hassan Shojania06b25fb2017-02-06 21:09:42 -08001186 jobject exception = env->NewObject(gStateExceptionFields.classId,
1187 gStateExceptionFields.init, static_cast<int>(err),
Hassan Shojania0b52e952017-01-23 09:06:31 -08001188 env->NewStringUTF(msg));
1189 env->Throw(static_cast<jthrowable>(exception));
1190}
1191
1192// TODO: investigate if these can be shared with their MediaDrm counterparts
1193static bool throwDrmExceptionAsNecessary(JNIEnv *env, status_t err, const char *msg = NULL)
1194{
1195 const char *drmMessage = "Unknown DRM Msg";
1196
1197 switch (err) {
1198 case ERROR_DRM_UNKNOWN:
1199 drmMessage = "General DRM error";
1200 break;
1201 case ERROR_DRM_NO_LICENSE:
1202 drmMessage = "No license";
1203 break;
1204 case ERROR_DRM_LICENSE_EXPIRED:
1205 drmMessage = "License expired";
1206 break;
1207 case ERROR_DRM_SESSION_NOT_OPENED:
1208 drmMessage = "Session not opened";
1209 break;
1210 case ERROR_DRM_DECRYPT_UNIT_NOT_INITIALIZED:
1211 drmMessage = "Not initialized";
1212 break;
1213 case ERROR_DRM_DECRYPT:
1214 drmMessage = "Decrypt error";
1215 break;
1216 case ERROR_DRM_CANNOT_HANDLE:
1217 drmMessage = "Unsupported scheme or data format";
1218 break;
1219 case ERROR_DRM_TAMPER_DETECTED:
1220 drmMessage = "Invalid state";
1221 break;
1222 default:
1223 break;
1224 }
1225
1226 String8 vendorMessage;
1227 if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
1228 vendorMessage = String8::format("DRM vendor-defined error: %d", err);
1229 drmMessage = vendorMessage.string();
1230 }
1231
1232 if (err == BAD_VALUE) {
1233 jniThrowException(env, "java/lang/IllegalArgumentException", msg);
1234 return true;
1235 } else if (err == ERROR_DRM_NOT_PROVISIONED) {
1236 jniThrowException(env, "android/media/NotProvisionedException", msg);
1237 return true;
1238 } else if (err == ERROR_DRM_RESOURCE_BUSY) {
1239 jniThrowException(env, "android/media/ResourceBusyException", msg);
1240 return true;
1241 } else if (err == ERROR_DRM_DEVICE_REVOKED) {
1242 jniThrowException(env, "android/media/DeniedByServerException", msg);
1243 return true;
1244 } else if (err == DEAD_OBJECT) {
1245 jniThrowException(env, "android/media/MediaDrmResetException",
1246 "mediaserver died");
1247 return true;
1248 } else if (err != OK) {
1249 String8 errbuf;
1250 if (drmMessage != NULL) {
1251 if (msg == NULL) {
1252 msg = drmMessage;
1253 } else {
1254 errbuf = String8::format("%s: %s", msg, drmMessage);
1255 msg = errbuf.string();
1256 }
1257 }
1258 throwDrmStateException(env, msg, err);
1259 return true;
1260 }
1261 return false;
1262}
1263
Hassan Shojania0b52e952017-01-23 09:06:31 -08001264static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray)
1265{
1266 Vector<uint8_t> vector;
1267 size_t length = env->GetArrayLength(byteArray);
1268 vector.insertAt((size_t)0, length);
1269 env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
1270 return vector;
1271}
1272
Hassan Shojania0b52e952017-01-23 09:06:31 -08001273static void android_media_MediaPlayer_prepareDrm(JNIEnv *env, jobject thiz,
Hassan Shojania06b25fb2017-02-06 21:09:42 -08001274 jbyteArray uuidObj, jbyteArray drmSessionIdObj)
Hassan Shojania0b52e952017-01-23 09:06:31 -08001275{
1276 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1277 if (mp == NULL) {
1278 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1279 return;
1280 }
1281
1282 if (uuidObj == NULL) {
1283 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
1284 return;
1285 }
1286
1287 Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
1288
1289 if (uuid.size() != 16) {
1290 jniThrowException(
1291 env,
1292 "java/lang/IllegalArgumentException",
1293 "invalid UUID size, expected 16 bytes");
1294 return;
1295 }
1296
Hassan Shojania06b25fb2017-02-06 21:09:42 -08001297 Vector<uint8_t> drmSessionId = JByteArrayToVector(env, drmSessionIdObj);
1298
1299 if (drmSessionId.size() == 0) {
1300 jniThrowException(
1301 env,
1302 "java/lang/IllegalArgumentException",
1303 "empty drmSessionId");
1304 return;
1305 }
1306
1307 status_t err = mp->prepareDrm(uuid.array(), drmSessionId);
Hassan Shojania0b52e952017-01-23 09:06:31 -08001308 if (err != OK) {
1309 if (err == INVALID_OPERATION) {
1310 jniThrowException(
1311 env,
1312 "java/lang/IllegalStateException",
Hassan Shojania06b25fb2017-02-06 21:09:42 -08001313 "The player must be in prepared state.");
Hassan Shojania0b52e952017-01-23 09:06:31 -08001314 } else if (err == ERROR_DRM_CANNOT_HANDLE) {
1315 jniThrowException(
1316 env,
1317 "android/media/UnsupportedSchemeException",
1318 "Failed to instantiate drm object.");
1319 } else {
1320 throwDrmExceptionAsNecessary(env, err, "Failed to prepare DRM scheme");
1321 }
1322 }
1323}
1324
1325static void android_media_MediaPlayer_releaseDrm(JNIEnv *env, jobject thiz)
1326{
1327 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1328 if (mp == NULL ) {
1329 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1330 return;
1331 }
1332
1333 status_t err = mp->releaseDrm();
1334 if (err != OK) {
1335 if (err == INVALID_OPERATION) {
1336 jniThrowException(
1337 env,
1338 "java/lang/IllegalStateException",
Hassan Shojania06b25fb2017-02-06 21:09:42 -08001339 "Can not release DRM in an active player state.");
Hassan Shojania0b52e952017-01-23 09:06:31 -08001340 }
1341 }
1342}
Hassan Shojania0b52e952017-01-23 09:06:31 -08001343// Modular DRM end
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344// ----------------------------------------------------------------------------
1345
jiabin6e5a6282017-10-06 09:34:23 -07001346/////////////////////////////////////////////////////////////////////////////////////
1347// AudioRouting begin
1348static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id)
1349{
1350 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1351 if (mp == NULL) {
1352 return false;
1353 }
1354 return mp->setOutputDevice(device_id) == NO_ERROR;
1355}
1356
1357static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
1358{
1359 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1360 if (mp == NULL) {
1361 return AUDIO_PORT_HANDLE_NONE;
1362 }
1363 return mp->getRoutedDeviceId();
1364}
1365
1366static void android_media_MediaPlayer_enableDeviceCallback(
1367 JNIEnv* env, jobject thiz, jboolean enabled)
1368{
1369 sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
1370 if (mp == NULL) {
1371 return;
1372 }
1373
1374 status_t status = mp->enableAudioDeviceCallback(enabled);
1375 if (status != NO_ERROR) {
1376 jniThrowException(env, "java/lang/IllegalStateException", NULL);
1377 ALOGE("enable device callback failed: %d", status);
1378 }
1379}
1380
1381// AudioRouting end
1382// ----------------------------------------------------------------------------
1383
Daniel Micay76f6a862015-09-19 17:31:01 -04001384static const JNINativeMethod gMethods[] = {
James Dong17524dc2011-05-04 13:41:58 -07001385 {
Andreas Huberd2506a52014-01-29 10:32:46 -08001386 "nativeSetDataSource",
1387 "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
1388 "[Ljava/lang/String;)V",
James Dong17524dc2011-05-04 13:41:58 -07001389 (void *)android_media_MediaPlayer_setDataSourceAndHeaders
1390 },
1391
Chris Watkins4eaa2932015-03-20 10:31:42 -07001392 {"_setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
1393 {"_setDataSource", "(Landroid/media/MediaDataSource;)V",(void *)android_media_MediaPlayer_setDataSourceCallback },
Ted Bonkenburg1ee60112011-07-26 09:51:18 -07001394 {"_setVideoSurface", "(Landroid/view/Surface;)V", (void *)android_media_MediaPlayer_setVideoSurface},
Vlad Popa66824a32022-08-12 16:05:05 +02001395 {"_prepare", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_prepare},
1396 {"_prepareAsync", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_prepareAsync},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 {"_start", "()V", (void *)android_media_MediaPlayer_start},
1398 {"_stop", "()V", (void *)android_media_MediaPlayer_stop},
1399 {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
1400 {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
Ray Essick10353e32017-04-14 10:22:55 -07001401 {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaPlayer_native_getMetrics},
Wei Jia2d61e2b2015-05-08 15:23:28 -07001402 {"setPlaybackParams", "(Landroid/media/PlaybackParams;)V", (void *)android_media_MediaPlayer_setPlaybackParams},
1403 {"getPlaybackParams", "()Landroid/media/PlaybackParams;", (void *)android_media_MediaPlayer_getPlaybackParams},
1404 {"setSyncParams", "(Landroid/media/SyncParams;)V", (void *)android_media_MediaPlayer_setSyncParams},
1405 {"getSyncParams", "()Landroid/media/SyncParams;", (void *)android_media_MediaPlayer_getSyncParams},
Wei Jiabebeaf92017-04-19 16:22:10 -07001406 {"_seekTo", "(JI)V", (void *)android_media_MediaPlayer_seekTo},
Wei Jiac02f09d2017-09-13 18:19:48 -07001407 {"_notifyAt", "(J)V", (void *)android_media_MediaPlayer_notifyAt},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 {"_pause", "()V", (void *)android_media_MediaPlayer_pause},
1409 {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
1410 {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
1411 {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
1412 {"_release", "()V", (void *)android_media_MediaPlayer_release},
1413 {"_reset", "()V", (void *)android_media_MediaPlayer_reset},
John Spurlock1af30c72014-03-10 08:33:35 -04001414 {"_setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
1415 {"_getAudioStreamType", "()I", (void *)android_media_MediaPlayer_getAudioStreamType},
Jean-Michel Trivi8df982d2014-06-26 12:05:16 -07001416 {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
1418 {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping},
John Spurlock1af30c72014-03-10 08:33:35 -04001419 {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
Nicolas Catania20cb94e2009-05-12 23:25:55 -07001420 {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
Nicolas Cataniab2c69392009-07-08 08:57:42 -07001421 {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_setMetadataFilter},
Nicolas Catania5d55c712009-07-09 09:21:33 -07001422 {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_getMetadata},
Marco Nelissen4935d052009-08-03 11:12:58 -07001423 {"native_init", "()V", (void *)android_media_MediaPlayer_native_init},
Jan Sebechlebsky0bbdb712023-01-09 14:29:19 +01001424 {"native_setup",
1425 "(Ljava/lang/Object;Landroid/os/Parcel;I)V",
1426 (void *)android_media_MediaPlayer_native_setup},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
Eric Laurent619346f2010-06-21 09:27:30 -07001428 {"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
Eric Laurent53945a42021-01-29 21:24:08 +01001429 {"native_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
John Spurlock1af30c72014-03-10 08:33:35 -04001430 {"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
Eric Laurent7070b362010-07-16 07:43:46 -07001431 {"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
Gloria Wangd211f412011-02-19 18:37:57 -08001432 {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
John Grossman720aa282012-02-22 15:38:35 -08001433 {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint},
Marco Nelissen84b83202012-02-28 16:07:44 -08001434 {"setNextMediaPlayer", "(Landroid/media/MediaPlayer;)V", (void *)android_media_MediaPlayer_setNextMediaPlayer},
Andy Hung035d4ec2017-01-24 13:45:02 -08001435 {"native_applyVolumeShaper",
1436 "(Landroid/media/VolumeShaper$Configuration;Landroid/media/VolumeShaper$Operation;)I",
1437 (void *)android_media_MediaPlayer_applyVolumeShaper},
1438 {"native_getVolumeShaperState",
1439 "(I)Landroid/media/VolumeShaper$State;",
1440 (void *)android_media_MediaPlayer_getVolumeShaperState},
Hassan Shojania0b52e952017-01-23 09:06:31 -08001441 // Modular DRM
Hassan Shojania06b25fb2017-02-06 21:09:42 -08001442 { "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm },
Hassan Shojania0b52e952017-01-23 09:06:31 -08001443 { "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm },
jiabin6e5a6282017-10-06 09:34:23 -07001444
1445 // AudioRouting
1446 {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice},
1447 {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId},
1448 {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449};
1450
Marco Nelissen4935d052009-08-03 11:12:58 -07001451// This function only registers the native methods
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452static int register_android_media_MediaPlayer(JNIEnv *env)
1453{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 return AndroidRuntime::registerNativeMethods(env,
1455 "android/media/MediaPlayer", gMethods, NELEM(gMethods));
1456}
Zhijun He212e78d2013-06-07 11:36:23 -07001457extern int register_android_media_ImageReader(JNIEnv *env);
Zhijun Hef6a09e52015-02-24 18:12:23 -08001458extern int register_android_media_ImageWriter(JNIEnv *env);
Marco Nelissen5ff11732019-10-17 08:55:52 -07001459extern int register_android_media_JetPlayer(JNIEnv *env);
Andreas Huber8240d922012-04-04 14:06:32 -07001460extern int register_android_media_Crypto(JNIEnv *env);
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001461extern int register_android_media_Drm(JNIEnv *env);
Chong Zhangd5927ae2017-01-03 11:07:18 -08001462extern int register_android_media_Descrambler(JNIEnv *env);
Andreas Huber88572f72012-02-21 11:47:18 -08001463extern int register_android_media_MediaCodec(JNIEnv *env);
1464extern int register_android_media_MediaExtractor(JNIEnv *env);
Andreas Huber5a04bf32012-03-29 16:41:38 -07001465extern int register_android_media_MediaCodecList(JNIEnv *env);
Andreas Huberd2506a52014-01-29 10:32:46 -08001466extern int register_android_media_MediaHTTPConnection(JNIEnv *env);
Andreas Huberbfb9fb12009-12-03 11:31:19 -08001467extern int register_android_media_MediaMetadataRetriever(JNIEnv *env);
ztenghui68ccf102013-02-13 14:07:02 -08001468extern int register_android_media_MediaMuxer(JNIEnv *env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469extern int register_android_media_MediaRecorder(JNIEnv *env);
Wei Jia071a8b72015-03-09 16:38:25 -07001470extern int register_android_media_MediaSync(JNIEnv *env);
Sally Qiaba398d2021-12-06 16:37:50 -08001471extern int register_android_media_PublicFormatUtils(JNIEnv *env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472extern int register_android_media_ResampleInputStream(JNIEnv *env);
James Dongc3711942010-01-19 17:45:38 -08001473extern int register_android_media_MediaProfiles(JNIEnv *env);
Mike Lockwood0cd01362010-12-30 11:54:33 -05001474extern int register_android_mtp_MtpDatabase(JNIEnv *env);
Mike Lockwood8182e722010-12-30 15:38:45 -05001475extern int register_android_mtp_MtpDevice(JNIEnv *env);
Mike Lockwood0cd01362010-12-30 11:54:33 -05001476extern int register_android_mtp_MtpServer(JNIEnv *env);
Andreas Huberbfb9fb12009-12-03 11:31:19 -08001477
Andreas Huberd2506a52014-01-29 10:32:46 -08001478jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479{
1480 JNIEnv* env = NULL;
1481 jint result = -1;
1482
1483 if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
Steve Block3762c312012-01-06 19:20:56 +00001484 ALOGE("ERROR: GetEnv failed\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 goto bail;
1486 }
1487 assert(env != NULL);
1488
Zhijun Hef6a09e52015-02-24 18:12:23 -08001489 if (register_android_media_ImageWriter(env) != JNI_OK) {
1490 ALOGE("ERROR: ImageWriter native registration failed");
1491 goto bail;
1492 }
1493
Zhijun He212e78d2013-06-07 11:36:23 -07001494 if (register_android_media_ImageReader(env) < 0) {
1495 ALOGE("ERROR: ImageReader native registration failed");
1496 goto bail;
1497 }
1498
Marco Nelissen5ff11732019-10-17 08:55:52 -07001499 if (register_android_media_JetPlayer(env) < 0) {
1500 ALOGE("ERROR: JetPlayer native registration failed");
1501 goto bail;
1502 }
1503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 if (register_android_media_MediaPlayer(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001505 ALOGE("ERROR: MediaPlayer native registration failed\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 goto bail;
1507 }
1508
1509 if (register_android_media_MediaRecorder(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001510 ALOGE("ERROR: MediaRecorder native registration failed\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 goto bail;
1512 }
1513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 if (register_android_media_MediaMetadataRetriever(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001515 ALOGE("ERROR: MediaMetadataRetriever native registration failed\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 goto bail;
1517 }
1518
Sally Qiaba398d2021-12-06 16:37:50 -08001519 if (register_android_media_PublicFormatUtils(env) < 0) {
1520 ALOGE("ERROR: PublicFormatUtils native registration failed\n");
1521 goto bail;
1522 }
1523
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 if (register_android_media_ResampleInputStream(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001525 ALOGE("ERROR: ResampleInputStream native registration failed\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 goto bail;
1527 }
1528
James Dongc3711942010-01-19 17:45:38 -08001529 if (register_android_media_MediaProfiles(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001530 ALOGE("ERROR: MediaProfiles native registration failed");
James Dongc3711942010-01-19 17:45:38 -08001531 goto bail;
1532 }
1533
Mike Lockwood0cd01362010-12-30 11:54:33 -05001534 if (register_android_mtp_MtpDatabase(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001535 ALOGE("ERROR: MtpDatabase native registration failed");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001536 goto bail;
1537 }
1538
Mike Lockwood8182e722010-12-30 15:38:45 -05001539 if (register_android_mtp_MtpDevice(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001540 ALOGE("ERROR: MtpDevice native registration failed");
Mike Lockwood8182e722010-12-30 15:38:45 -05001541 goto bail;
1542 }
1543
Mike Lockwood0cd01362010-12-30 11:54:33 -05001544 if (register_android_mtp_MtpServer(env) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001545 ALOGE("ERROR: MtpServer native registration failed");
Mike Lockwood81ea83d2010-06-30 17:49:41 -04001546 goto bail;
1547 }
1548
Andreas Huber88572f72012-02-21 11:47:18 -08001549 if (register_android_media_MediaCodec(env) < 0) {
1550 ALOGE("ERROR: MediaCodec native registration failed");
1551 goto bail;
1552 }
1553
Wei Jia071a8b72015-03-09 16:38:25 -07001554 if (register_android_media_MediaSync(env) < 0) {
1555 ALOGE("ERROR: MediaSync native registration failed");
1556 goto bail;
1557 }
1558
Andreas Huber88572f72012-02-21 11:47:18 -08001559 if (register_android_media_MediaExtractor(env) < 0) {
1560 ALOGE("ERROR: MediaCodec native registration failed");
1561 goto bail;
1562 }
1563
ztenghui68ccf102013-02-13 14:07:02 -08001564 if (register_android_media_MediaMuxer(env) < 0) {
1565 ALOGE("ERROR: MediaMuxer native registration failed");
1566 goto bail;
1567 }
1568
Andreas Huber5a04bf32012-03-29 16:41:38 -07001569 if (register_android_media_MediaCodecList(env) < 0) {
1570 ALOGE("ERROR: MediaCodec native registration failed");
1571 goto bail;
1572 }
1573
Andreas Huber8240d922012-04-04 14:06:32 -07001574 if (register_android_media_Crypto(env) < 0) {
1575 ALOGE("ERROR: MediaCodec native registration failed");
1576 goto bail;
1577 }
1578
Jeff Tinker8a0c80f2013-02-08 10:20:44 -08001579 if (register_android_media_Drm(env) < 0) {
1580 ALOGE("ERROR: MediaDrm native registration failed");
1581 goto bail;
1582 }
1583
Chong Zhangd5927ae2017-01-03 11:07:18 -08001584 if (register_android_media_Descrambler(env) < 0) {
1585 ALOGE("ERROR: MediaDescrambler native registration failed");
1586 goto bail;
1587 }
1588
Andreas Huberd2506a52014-01-29 10:32:46 -08001589 if (register_android_media_MediaHTTPConnection(env) < 0) {
1590 ALOGE("ERROR: MediaHTTPConnection native registration failed");
1591 goto bail;
1592 }
1593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 /* success -- return valid version number */
1595 result = JNI_VERSION_1_4;
1596
1597bail:
1598 return result;
1599}
1600
1601// KTHXBYE