Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -683,6 +683,7 @@ java_defaults { static_libs: [ "framework-protos", "mediaplayer2-protos", "android.hidl.base-V1.0-java", "android.hardware.cas-V1.0-java", "android.hardware.contexthub-V1.0-java", Loading media/java/android/media/MediaPlayer2.java +0 −16 Original line number Diff line number Diff line Loading @@ -772,22 +772,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener return null; } /** * Invoke a generic method on the native player using opaque * parcels for the request and reply. Both payloads' format is a * convention between the java caller and the native player. * Must be called after setDataSource to make sure a native player * exists. On failure, a RuntimeException is thrown. * * @param request Parcel with the data for the extension. The * caller must use {@link #newRequest()} to get one. * * @param reply Output parcel with the data returned by the * native player. * {@hide} */ public void invoke(Parcel request, Parcel reply) { } /** * Insert a task in the command queue to help the client to identify whether a batch * of commands has been finished. When this command is processed, a notification Loading media/java/android/media/MediaPlayer2Impl.java +85 −106 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.media.MediaPlayer2Proto; import android.media.MediaPlayer2Proto.PlayerMessage; import android.media.MediaPlayer2Proto.Value; import android.media.SubtitleController.Anchor; import android.media.SubtitleTrack.RenderingWidget; import android.net.Uri; Loading @@ -49,6 +52,7 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.widget.VideoView; import com.android.framework.protobuf.InvalidProtocolBufferException; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; Loading @@ -72,6 +76,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; Loading Loading @@ -555,28 +560,30 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } /** * Invoke a generic method on the native player using opaque * parcels for the request and reply. Both payloads' format is a * Invoke a generic method on the native player using opaque protocol * buffer message for the request and reply. Both payloads' format is a * convention between the java caller and the native player. * Must be called after setDataSource or setPlaylist to make sure a native player * exists. On failure, a RuntimeException is thrown. * * @param request Parcel with the data for the extension. The * @param request PlayerMessage for the extension. The * caller must use {@link #newRequest()} to get one. * * @param reply Output parcel with the data returned by the * @return PlayerMessage with the data returned by the * native player. * {@hide} */ @Override public void invoke(Parcel request, Parcel reply) { int retcode = native_invoke(request, reply); reply.setDataPosition(0); if (retcode != 0) { throw new RuntimeException("failure code: " + retcode); private PlayerMessage invoke(PlayerMessage msg) { byte[] ret = _invoke(msg.toByteArray()); if (ret == null) { return null; } try { return PlayerMessage.parseFrom(ret); } catch (InvalidProtocolBufferException e) { return null; } } private native byte[] _invoke(byte[] request); @Override public void notifyWhenCommandLabelReached(Object label) { addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) { Loading Loading @@ -683,16 +690,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { final String msg = "Scaling mode " + mode + " is not supported"; throw new IllegalArgumentException(msg); } Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE); request.writeInt(mode); invoke(request, reply); } finally { request.recycle(); reply.recycle(); } PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder() .setInt32Value(INVOKE_ID_SET_VIDEO_SCALE_MODE)) .addValues(Value.newBuilder().setInt32Value(mode)) .build(); invoke(request); } }); } Loading Loading @@ -1798,14 +1801,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void _setAuxEffectSendLevel(float level); /* * @param request Parcel destinated to the media player. * @param reply[out] Parcel that will contain the reply. * @return The status code. */ private native final int native_invoke(Parcel request, Parcel reply); /* * @param update_only If true fetch only the set of metadata that have * changed since the last invocation of getMetadata. Loading Loading @@ -1886,18 +1881,18 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { final int mTrackType; final MediaFormat mFormat; TrackInfoImpl(Parcel in) { mTrackType = in.readInt(); // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat TrackInfoImpl(Iterator<Value> in) { mTrackType = in.next().getInt32Value(); // TODO: build the full MediaFormat; currently we are using createSubtitleFormat // even for audio/video tracks, meaning we only set the mime and language. String mime = in.readString(); String language = in.readString(); String mime = in.next().getStringValue(); String language = in.next().getStringValue(); mFormat = MediaFormat.createSubtitleFormat(mime, language); if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) { mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value()); mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value()); mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value()); } } Loading Loading @@ -1952,23 +1947,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { out.append("}"); return out.toString(); } /** * Used to read a TrackInfoImpl from a Parcel. */ /* package private */ static final Parcelable.Creator<TrackInfoImpl> CREATOR = new Parcelable.Creator<TrackInfoImpl>() { @Override public TrackInfoImpl createFromParcel(Parcel in) { return new TrackInfoImpl(in); } @Override public TrackInfoImpl[] newArray(int size) { return new TrackInfoImpl[size]; } }; }; // We would like domain specific classes with more informative names than the `first` and `second` Loading Loading @@ -2010,17 +1988,23 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException { Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(INVOKE_ID_GET_TRACK_INFO); invoke(request, reply); TrackInfoImpl trackInfo[] = reply.createTypedArray(TrackInfoImpl.CREATOR); return trackInfo; } finally { request.recycle(); reply.recycle(); PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_TRACK_INFO)) .build(); PlayerMessage response = invoke(request); if (response == null) { return null; } Iterator<Value> in = response.getValuesList().iterator(); int size = in.next().getInt32Value(); if (size == 0) { return null; } TrackInfoImpl trackInfo[] = new TrackInfoImpl[size]; for (int i = 0; i < size; ++i) { trackInfo[i] = new TrackInfoImpl(in); } return trackInfo; } /* Loading Loading @@ -2481,13 +2465,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(INVOKE_ID_GET_SELECTED_TRACK); request.writeInt(trackType); invoke(request, reply); int inbandTrackIndex = reply.readInt(); PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK)) .addValues(Value.newBuilder().setInt32Value(trackType)) .build(); PlayerMessage response = invoke(request); if (response == null) { return -1; } int inbandTrackIndex = response.getValues(0).getInt32Value(); synchronized (mIndexTrackPairs) { for (int i = 0; i < mIndexTrackPairs.size(); i++) { Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i); Loading @@ -2497,10 +2483,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } return -1; } finally { request.recycle(); reply.recycle(); } } /** Loading Loading @@ -2617,16 +2599,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private void selectOrDeselectInbandTrack(int index, boolean select) throws IllegalStateException { Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK); request.writeInt(index); invoke(request, reply); } finally { request.recycle(); reply.recycle(); } PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder().setInt32Value( select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK)) .addValues(Value.newBuilder().setInt32Value(index)) .build(); invoke(request); } // Have to declare protected for finalize() since it is protected Loading Loading @@ -2935,20 +2913,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_INFO: { synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { cb.first.execute(() -> cb.second.onInfo( mMediaPlayer, dsd, what, extra)); } } switch (msg.arg1) { case MEDIA_INFO_DATA_SOURCE_START: if (isCurrentSrcId) { prepareNextDataSource(); } break; case MEDIA_INFO_VIDEO_TRACK_LAGGING: Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")"); break; Loading Loading @@ -2980,6 +2945,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } break; } synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { cb.first.execute(() -> cb.second.onInfo( mMediaPlayer, dsd, what, extra)); } } if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) { if (isCurrentSrcId) { prepareNextDataSource(); } } // No real default action so far. return; } Loading media/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -133,8 +133,10 @@ cc_library_shared { "libmediaextractor", "libmediametrics", "libmediaplayer2", "libmediaplayer2-protos", "libmediautils", "libnetd_client", "libprotobuf-cpp-lite", "libstagefright_esds", "libstagefright_foundation", "libstagefright_httplive", Loading media/jni/android_media_MediaPlayer2.cpp +36 −15 Original line number Diff line number Diff line Loading @@ -56,6 +56,10 @@ #include "android_util_Binder.h" #include <binder/Parcel.h> #include "mediaplayer2.pb.h" using android::media::MediaPlayer2Proto::PlayerMessage; // Modular DRM begin #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ Loading Loading @@ -196,6 +200,11 @@ void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2, if (obj && obj->dataSize() > 0) { jobject jParcel = createJavaParcelObject(env); if (jParcel != NULL) { // TODO: replace the following Parcel usages with proto. // 1. MEDIA_DRM_INFO : DrmInfo // 2. MEDIA_TIMED_TEXT : TimedText // 2. MEDIA_SUBTITLE_DATA : SubtitleData // 4. MEDIA_META_DATA : TimedMetaData Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, Loading Loading @@ -911,6 +920,9 @@ android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, job return false; } // TODO: parcelForJavaObject() shouldn't be used since it's dependent on // framework's Parcel implementation. This setParameter() is used // only with AudioAttribute. Can this be used as jobject with JAudioTrack? Parcel *request = parcelForJavaObject(env, java_request); status_t err = mp->setParameter(key, *request); if (err == OK) { Loading Loading @@ -978,26 +990,35 @@ android_media_MediaPlayer2_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolum process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL ); } // Sends the request and reply parcels to the media player via the // binder interface. static jint android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jobject java_request, jobject java_reply) { static jbyteArray android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jbyteArray requestData) { sp<MediaPlayer2> media_player = getMediaPlayer(env, thiz); if (media_player == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return UNKNOWN_ERROR; return NULL; } Parcel *request = parcelForJavaObject(env, java_request); Parcel *reply = parcelForJavaObject(env, java_reply); // Get the byte[] pointer and data length. jbyte* pData = env->GetByteArrayElements(requestData, NULL); jsize pDataLen = env->GetArrayLength(requestData); // Deserialize from the byte stream. PlayerMessage request; PlayerMessage response; request.ParseFromArray(pData, pDataLen); media_player->invoke(request, &response); int size = response.ByteSize(); jbyte* temp = new jbyte[size]; response.SerializeToArray(temp, size); request->setDataPosition(0); // return the response as a byte array. jbyteArray out = env->NewByteArray(size); env->SetByteArrayRegion(out, 0, size, temp); delete[] temp; // Don't use process_media_player_call which use the async loop to // report errors, instead returns the status. return (jint) media_player->invoke(*request, reply); return out; } // Sends the new filter to the client. Loading Loading @@ -1512,7 +1533,7 @@ static const JNINativeMethod gMethods[] = { {"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping}, {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer2_setVolume}, {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer2_invoke}, {"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke}, {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer2_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer2_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer2_native_init}, Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -683,6 +683,7 @@ java_defaults { static_libs: [ "framework-protos", "mediaplayer2-protos", "android.hidl.base-V1.0-java", "android.hardware.cas-V1.0-java", "android.hardware.contexthub-V1.0-java", Loading
media/java/android/media/MediaPlayer2.java +0 −16 Original line number Diff line number Diff line Loading @@ -772,22 +772,6 @@ public abstract class MediaPlayer2 implements SubtitleController.Listener return null; } /** * Invoke a generic method on the native player using opaque * parcels for the request and reply. Both payloads' format is a * convention between the java caller and the native player. * Must be called after setDataSource to make sure a native player * exists. On failure, a RuntimeException is thrown. * * @param request Parcel with the data for the extension. The * caller must use {@link #newRequest()} to get one. * * @param reply Output parcel with the data returned by the * native player. * {@hide} */ public void invoke(Parcel request, Parcel reply) { } /** * Insert a task in the command queue to help the client to identify whether a batch * of commands has been finished. When this command is processed, a notification Loading
media/java/android/media/MediaPlayer2Impl.java +85 −106 Original line number Diff line number Diff line Loading @@ -25,6 +25,9 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; import android.graphics.SurfaceTexture; import android.media.MediaPlayer2Proto; import android.media.MediaPlayer2Proto.PlayerMessage; import android.media.MediaPlayer2Proto.Value; import android.media.SubtitleController.Anchor; import android.media.SubtitleTrack.RenderingWidget; import android.net.Uri; Loading @@ -49,6 +52,7 @@ import android.view.Surface; import android.view.SurfaceHolder; import android.widget.VideoView; import com.android.framework.protobuf.InvalidProtocolBufferException; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; Loading @@ -72,6 +76,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; Loading Loading @@ -555,28 +560,30 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } /** * Invoke a generic method on the native player using opaque * parcels for the request and reply. Both payloads' format is a * Invoke a generic method on the native player using opaque protocol * buffer message for the request and reply. Both payloads' format is a * convention between the java caller and the native player. * Must be called after setDataSource or setPlaylist to make sure a native player * exists. On failure, a RuntimeException is thrown. * * @param request Parcel with the data for the extension. The * @param request PlayerMessage for the extension. The * caller must use {@link #newRequest()} to get one. * * @param reply Output parcel with the data returned by the * @return PlayerMessage with the data returned by the * native player. * {@hide} */ @Override public void invoke(Parcel request, Parcel reply) { int retcode = native_invoke(request, reply); reply.setDataPosition(0); if (retcode != 0) { throw new RuntimeException("failure code: " + retcode); private PlayerMessage invoke(PlayerMessage msg) { byte[] ret = _invoke(msg.toByteArray()); if (ret == null) { return null; } try { return PlayerMessage.parseFrom(ret); } catch (InvalidProtocolBufferException e) { return null; } } private native byte[] _invoke(byte[] request); @Override public void notifyWhenCommandLabelReached(Object label) { addTask(new Task(CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED, false) { Loading Loading @@ -683,16 +690,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { final String msg = "Scaling mode " + mode + " is not supported"; throw new IllegalArgumentException(msg); } Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(INVOKE_ID_SET_VIDEO_SCALE_MODE); request.writeInt(mode); invoke(request, reply); } finally { request.recycle(); reply.recycle(); } PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder() .setInt32Value(INVOKE_ID_SET_VIDEO_SCALE_MODE)) .addValues(Value.newBuilder().setInt32Value(mode)) .build(); invoke(request); } }); } Loading Loading @@ -1798,14 +1801,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private native void _setAuxEffectSendLevel(float level); /* * @param request Parcel destinated to the media player. * @param reply[out] Parcel that will contain the reply. * @return The status code. */ private native final int native_invoke(Parcel request, Parcel reply); /* * @param update_only If true fetch only the set of metadata that have * changed since the last invocation of getMetadata. Loading Loading @@ -1886,18 +1881,18 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { final int mTrackType; final MediaFormat mFormat; TrackInfoImpl(Parcel in) { mTrackType = in.readInt(); // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat TrackInfoImpl(Iterator<Value> in) { mTrackType = in.next().getInt32Value(); // TODO: build the full MediaFormat; currently we are using createSubtitleFormat // even for audio/video tracks, meaning we only set the mime and language. String mime = in.readString(); String language = in.readString(); String mime = in.next().getStringValue(); String language = in.next().getStringValue(); mFormat = MediaFormat.createSubtitleFormat(mime, language); if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) { mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.next().getInt32Value()); mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.next().getInt32Value()); mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.next().getInt32Value()); } } Loading Loading @@ -1952,23 +1947,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { out.append("}"); return out.toString(); } /** * Used to read a TrackInfoImpl from a Parcel. */ /* package private */ static final Parcelable.Creator<TrackInfoImpl> CREATOR = new Parcelable.Creator<TrackInfoImpl>() { @Override public TrackInfoImpl createFromParcel(Parcel in) { return new TrackInfoImpl(in); } @Override public TrackInfoImpl[] newArray(int size) { return new TrackInfoImpl[size]; } }; }; // We would like domain specific classes with more informative names than the `first` and `second` Loading Loading @@ -2010,17 +1988,23 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } private TrackInfoImpl[] getInbandTrackInfoImpl() throws IllegalStateException { Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(INVOKE_ID_GET_TRACK_INFO); invoke(request, reply); TrackInfoImpl trackInfo[] = reply.createTypedArray(TrackInfoImpl.CREATOR); return trackInfo; } finally { request.recycle(); reply.recycle(); PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_TRACK_INFO)) .build(); PlayerMessage response = invoke(request); if (response == null) { return null; } Iterator<Value> in = response.getValuesList().iterator(); int size = in.next().getInt32Value(); if (size == 0) { return null; } TrackInfoImpl trackInfo[] = new TrackInfoImpl[size]; for (int i = 0; i < size; ++i) { trackInfo[i] = new TrackInfoImpl(in); } return trackInfo; } /* Loading Loading @@ -2481,13 +2465,15 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(INVOKE_ID_GET_SELECTED_TRACK); request.writeInt(trackType); invoke(request, reply); int inbandTrackIndex = reply.readInt(); PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder().setInt32Value(INVOKE_ID_GET_SELECTED_TRACK)) .addValues(Value.newBuilder().setInt32Value(trackType)) .build(); PlayerMessage response = invoke(request); if (response == null) { return -1; } int inbandTrackIndex = response.getValues(0).getInt32Value(); synchronized (mIndexTrackPairs) { for (int i = 0; i < mIndexTrackPairs.size(); i++) { Pair<Integer, SubtitleTrack> p = mIndexTrackPairs.get(i); Loading @@ -2497,10 +2483,6 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } } return -1; } finally { request.recycle(); reply.recycle(); } } /** Loading Loading @@ -2617,16 +2599,12 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { private void selectOrDeselectInbandTrack(int index, boolean select) throws IllegalStateException { Parcel request = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { request.writeInt(select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK); request.writeInt(index); invoke(request, reply); } finally { request.recycle(); reply.recycle(); } PlayerMessage request = PlayerMessage.newBuilder() .addValues(Value.newBuilder().setInt32Value( select? INVOKE_ID_SELECT_TRACK: INVOKE_ID_DESELECT_TRACK)) .addValues(Value.newBuilder().setInt32Value(index)) .build(); invoke(request); } // Have to declare protected for finalize() since it is protected Loading Loading @@ -2935,20 +2913,7 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { case MEDIA_INFO: { synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { cb.first.execute(() -> cb.second.onInfo( mMediaPlayer, dsd, what, extra)); } } switch (msg.arg1) { case MEDIA_INFO_DATA_SOURCE_START: if (isCurrentSrcId) { prepareNextDataSource(); } break; case MEDIA_INFO_VIDEO_TRACK_LAGGING: Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")"); break; Loading Loading @@ -2980,6 +2945,20 @@ public final class MediaPlayer2Impl extends MediaPlayer2 { } break; } synchronized (mEventCbLock) { for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) { cb.first.execute(() -> cb.second.onInfo( mMediaPlayer, dsd, what, extra)); } } if (msg.arg1 == MEDIA_INFO_DATA_SOURCE_START) { if (isCurrentSrcId) { prepareNextDataSource(); } } // No real default action so far. return; } Loading
media/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -133,8 +133,10 @@ cc_library_shared { "libmediaextractor", "libmediametrics", "libmediaplayer2", "libmediaplayer2-protos", "libmediautils", "libnetd_client", "libprotobuf-cpp-lite", "libstagefright_esds", "libstagefright_foundation", "libstagefright_httplive", Loading
media/jni/android_media_MediaPlayer2.cpp +36 −15 Original line number Diff line number Diff line Loading @@ -56,6 +56,10 @@ #include "android_util_Binder.h" #include <binder/Parcel.h> #include "mediaplayer2.pb.h" using android::media::MediaPlayer2Proto::PlayerMessage; // Modular DRM begin #define FIND_CLASS(var, className) \ var = env->FindClass(className); \ Loading Loading @@ -196,6 +200,11 @@ void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2, if (obj && obj->dataSize() > 0) { jobject jParcel = createJavaParcelObject(env); if (jParcel != NULL) { // TODO: replace the following Parcel usages with proto. // 1. MEDIA_DRM_INFO : DrmInfo // 2. MEDIA_TIMED_TEXT : TimedText // 2. MEDIA_SUBTITLE_DATA : SubtitleData // 4. MEDIA_META_DATA : TimedMetaData Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, Loading Loading @@ -911,6 +920,9 @@ android_media_MediaPlayer2_setParameter(JNIEnv *env, jobject thiz, jint key, job return false; } // TODO: parcelForJavaObject() shouldn't be used since it's dependent on // framework's Parcel implementation. This setParameter() is used // only with AudioAttribute. Can this be used as jobject with JAudioTrack? Parcel *request = parcelForJavaObject(env, java_request); status_t err = mp->setParameter(key, *request); if (err == OK) { Loading Loading @@ -978,26 +990,35 @@ android_media_MediaPlayer2_setVolume(JNIEnv *env, jobject thiz, jfloat leftVolum process_media_player_call( env, thiz, mp->setVolume((float) leftVolume, (float) rightVolume), NULL, NULL ); } // Sends the request and reply parcels to the media player via the // binder interface. static jint android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jobject java_request, jobject java_reply) { static jbyteArray android_media_MediaPlayer2_invoke(JNIEnv *env, jobject thiz, jbyteArray requestData) { sp<MediaPlayer2> media_player = getMediaPlayer(env, thiz); if (media_player == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); return UNKNOWN_ERROR; return NULL; } Parcel *request = parcelForJavaObject(env, java_request); Parcel *reply = parcelForJavaObject(env, java_reply); // Get the byte[] pointer and data length. jbyte* pData = env->GetByteArrayElements(requestData, NULL); jsize pDataLen = env->GetArrayLength(requestData); // Deserialize from the byte stream. PlayerMessage request; PlayerMessage response; request.ParseFromArray(pData, pDataLen); media_player->invoke(request, &response); int size = response.ByteSize(); jbyte* temp = new jbyte[size]; response.SerializeToArray(temp, size); request->setDataPosition(0); // return the response as a byte array. jbyteArray out = env->NewByteArray(size); env->SetByteArrayRegion(out, 0, size, temp); delete[] temp; // Don't use process_media_player_call which use the async loop to // report errors, instead returns the status. return (jint) media_player->invoke(*request, reply); return out; } // Sends the new filter to the client. Loading Loading @@ -1512,7 +1533,7 @@ static const JNINativeMethod gMethods[] = { {"setLooping", "(Z)V", (void *)android_media_MediaPlayer2_setLooping}, {"isLooping", "()Z", (void *)android_media_MediaPlayer2_isLooping}, {"_setVolume", "(FF)V", (void *)android_media_MediaPlayer2_setVolume}, {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer2_invoke}, {"_invoke", "([B)[B", (void *)android_media_MediaPlayer2_invoke}, {"native_setMetadataFilter", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer2_setMetadataFilter}, {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer2_getMetadata}, {"native_init", "()V", (void *)android_media_MediaPlayer2_native_init}, Loading