diff --git a/api/current.xml b/api/current.xml index a3a8c61e27467..cd9cf5dcb609a 100644 --- a/api/current.xml +++ b/api/current.xml @@ -73258,6 +73258,21 @@ visibility="public" > + + + + + + + + // for status_t #include #include #include @@ -36,7 +37,6 @@ public: virtual sp createMediaRecorder(pid_t pid) = 0; virtual sp createMetadataRetriever(pid_t pid) = 0; - virtual sp create(pid_t pid, const sp& client, const char* url) = 0; virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length) = 0; virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0; diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index 7bf555a43320c..21600b2de9aae 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -27,12 +27,15 @@ namespace android { +class Parcel; + enum player_type { PV_PLAYER = 1, SONIVOX_PLAYER = 2, VORBIS_PLAYER = 3 }; + #define DEFAULT_AUDIOSINK_BUFFERCOUNT 4 #define DEFAULT_AUDIOSINK_BUFFERSIZE 1200 #define DEFAULT_AUDIOSINK_SAMPLERATE 44100 @@ -45,7 +48,6 @@ typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2); class MediaPlayerBase : public RefBase { public: - // AudioSink: abstraction layer for audio output class AudioSink : public RefBase { public: @@ -88,7 +90,14 @@ public: virtual player_type playerType() = 0; virtual void setNotifyCallback(void* cookie, notify_callback_f notifyFunc) { mCookie = cookie; mNotify = notifyFunc; } - + // Invoke a generic method on the player by using opaque parcels + // for the request and reply. + // @param request Parcel that is positioned at the start of the + // data sent by the java layer. + // @param[out] reply Parcel to hold the reply data. Cannot be null. + // @return OK if the invocation was made successfully. A player + // not supporting the direct API should return INVALID_OPERATION. + virtual status_t invoke(const Parcel& request, Parcel *reply) = 0; protected: virtual void sendEvent(int msg, int ext1=0, int ext2=0) { if (mNotify) mNotify(mCookie, msg, ext1, ext2); } diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h index 8122df60eb5dd..eb4595ba156aa 100644 --- a/include/media/PVPlayer.h +++ b/include/media/PVPlayer.h @@ -52,6 +52,7 @@ public: virtual status_t reset(); virtual status_t setLooping(int loop); virtual player_type playerType() { return PV_PLAYER; } + virtual status_t invoke(const Parcel& request, Parcel *reply); // make available to PlayerDriver void sendEvent(int msg, int ext1=0, int ext2=0) { MediaPlayerBase::sendEvent(msg, ext1, ext2); } diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h index ffb325dc18e71..dd8ea19a13b47 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -151,7 +151,7 @@ public: void notify(int msg, int ext1, int ext2); static sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); static sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); - + status_t invoke(const Parcel& request, Parcel *reply); private: void clear_l(); status_t seekTo_l(int msec); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 3b46d690c40be..298cce9aa8e5e 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -23,6 +23,7 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.util.Log; @@ -435,6 +436,10 @@ public class MediaPlayer } private final static String TAG = "MediaPlayer"; + // Name of the remote interface for the media player. Must be kept + // in sync with the 2nd parameter of the IMPLEMENT_META_INTERFACE + // macro invocation in IMediaPlayer.cpp + private final static String IMEDIA_PLAYER = "android.media.IMediaPlayer"; private int mNativeContext; // accessed by native methods private int mListenerContext; // accessed by native methods @@ -474,6 +479,43 @@ public class MediaPlayer */ private native void _setVideoSurface(); + /** + * Create a request parcel which can be routed to the native media + * player using {@link #invoke(Parcel, Parcel)}. The Parcel + * returned has the proper InterfaceToken set. The caller should + * not overwrite that token, i.e it can only append data to the + * Parcel. + * + * @return A parcel suitable to hold a request for the native + * player. + */ + public Parcel newRequest() { + Parcel parcel = Parcel.obtain(); + parcel.writeInterfaceToken(IMEDIA_PLAYER); + return parcel; + } + + /** + * 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. + * + * @param request Parcel with the data for the extension. The + * caller must use {@link #newRequest()} to get one. + * + * @param[out] reply Parcel with the data returned by the + * native player. + * + * @return The status code see utils/Errors.h + */ + public int invoke(Parcel request, Parcel reply) { + int retcode = native_invoke(request, reply); + reply.setDataPosition(0); + return retcode; + } + /** * Sets the SurfaceHolder to use for displaying the video portion of the media. * This call is optional. Not calling it when playing back a video will @@ -915,8 +957,18 @@ public class MediaPlayer */ public native Bitmap getFrameAt(int msec) throws IllegalStateException; + /** + * @param request Parcel destinated to the media player. The + * Interface token must be set to the IMediaPlayer + * one to be routed correctly through the system. + * @param reply Parcel that will contain the reply. + * @return The status code. + */ + private native final int native_invoke(Parcel request, Parcel reply); + private native final void native_setup(Object mediaplayer_this); private native final void native_finalize(); + @Override protected void finalize() { native_finalize(); } diff --git a/media/jni/Android.mk b/media/jni/Android.mk index 9552aa6d0dd9c..f19649bd56607 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -27,6 +27,7 @@ LOCAL_STATIC_LIBRARIES := LOCAL_C_INCLUDES += \ external/tremor/Tremor \ + frameworks/base/core/jni \ $(PV_INCLUDES) \ $(JNI_H_INCLUDE) \ $(call include-path-for, corecg graphics) diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 6317fe21b702a..2c08c16f98138 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -20,6 +20,7 @@ #include "utils/Log.h" #include +#include #include #include #include @@ -30,6 +31,8 @@ #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include "utils/Errors.h" // for status_t +#include "android_util_Binder.h" +#include // ---------------------------------------------------------------------------- @@ -442,6 +445,28 @@ android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) return NULL; } + +// Sends the request and reply parcels to the media player via the +// binder interface. +static jint +android_media_MediaPlayer_invoke(JNIEnv *env, jobject thiz, + jobject java_request, jobject java_reply) +{ + sp media_player = getMediaPlayer(env, thiz); + if (media_player == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + } + + + Parcel *request = parcelForJavaObject(env, java_request); + Parcel *reply = parcelForJavaObject(env, java_reply); + + const status_t status = media_player->invoke(*request, reply); + // Don't use process_media_player_call which use the async loop to + // report errors, instead returns the status. + return status; +} + static void android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { @@ -503,6 +528,7 @@ static JNINativeMethod gMethods[] = { {"isLooping", "()Z", (void *)android_media_MediaPlayer_isLooping}, {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, + {"native_invoke", "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke}, {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, }; diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index fa2d81dfcba39..3f278f401b507 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -39,7 +39,8 @@ enum { RESET, SET_AUDIO_STREAM_TYPE, SET_LOOPING, - SET_VOLUME + SET_VOLUME, + INVOKE, }; class BpMediaPlayer: public BpInterface @@ -170,6 +171,13 @@ public: remote()->transact(SET_VOLUME, data, &reply); return reply.readInt32(); } + + status_t invoke(const Parcel& request, Parcel *reply) + { // Avoid doing any extra copy. The interface descriptor should + // have been set by MediaPlayer.java. + status_t retcode = remote()->transact(INVOKE, request, reply); + return retcode; + } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); @@ -260,6 +268,11 @@ status_t BnMediaPlayer::onTransact( reply->writeInt32(setVolume(data.readFloat(), data.readFloat())); return NO_ERROR; } break; + case INVOKE: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + invoke(data, reply); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 33b3e22e2b057..0f64259012f0b 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -20,6 +20,7 @@ #include #include +#include // for status_t #include #include diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 220c998c5bfff..4683166d6b392 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -196,6 +196,20 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) return err; } +status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply) +{ + Mutex::Autolock _l(mLock); + if ((mPlayer != NULL) && ( mCurrentState & MEDIA_PLAYER_INITIALIZED )) + { + LOGV("invoke %d", request.dataSize()); + return mPlayer->invoke(request, reply); + } + LOGE("invoke failed: wrong state %X", mCurrentState); + return INVALID_OPERATION; +} + + + status_t MediaPlayer::setVideoSurface(const sp& surface) { LOGV("setVideoSurface"); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index a17e6512fad33..e39495bf2b933 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -34,6 +34,9 @@ #include #include #include +#include // for status_t +#include +#include #include #include @@ -61,7 +64,6 @@ pid_t gettid() { return syscall(__NR_gettid);} #undef __KERNEL__ #endif - namespace android { // TODO: Temp hack until we can register players @@ -671,6 +673,14 @@ status_t MediaPlayerService::Client::setVideoSurface(const sp& surface return p->setVideoSurface(surface); } +status_t MediaPlayerService::Client::invoke(const Parcel& request, + Parcel *reply) +{ + sp p = getPlayer(); + if (p == NULL) return UNKNOWN_ERROR; + return p->invoke(request, reply); +} + status_t MediaPlayerService::Client::prepareAsync() { LOGV("[%d] prepareAsync", mConnId); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 5a296bf323bb2..12f22317569b1 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -187,6 +187,7 @@ private: virtual status_t setAudioStreamType(int type); virtual status_t setLooping(int loop); virtual status_t setVolume(float leftVolume, float rightVolume); + virtual status_t invoke(const Parcel& request, Parcel *reply); sp createPlayer(player_type playerType); status_t setDataSource(const char *url); @@ -238,4 +239,3 @@ private: }; // namespace android #endif // ANDROID_MEDIAPLAYERSERVICE_H - diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h index 302f1cf2f8e46..83d97fee6dfa9 100644 --- a/media/libmediaplayerservice/MidiFile.h +++ b/media/libmediaplayerservice/MidiFile.h @@ -46,6 +46,7 @@ public: virtual status_t reset(); virtual status_t setLooping(int loop); virtual player_type playerType() { return SONIVOX_PLAYER; } + virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;} private: status_t createOutputTrack(); @@ -74,4 +75,3 @@ private: }; // namespace android #endif // ANDROID_MIDIFILE_H - diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h index c30dc1b72dd25..40246543d4ce0 100644 --- a/media/libmediaplayerservice/VorbisPlayer.h +++ b/media/libmediaplayerservice/VorbisPlayer.h @@ -53,6 +53,7 @@ public: virtual status_t reset(); virtual status_t setLooping(int loop); virtual player_type playerType() { return VORBIS_PLAYER; } + virtual status_t invoke(const Parcel& request, Parcel *reply) {return INVALID_OPERATION;} private: status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length); @@ -88,4 +89,3 @@ private: }; // namespace android #endif // ANDROID_VORBISPLAYER_H -