Direct api to the native media player.
MediaPlayer.java has 3 new methods: * newRequest creates a Parcel that can be used to send data to the native player using invoke. * invoke issues synchronous calls to the native player using opaque parcels for the request and reply. IMediaPlayer.h has 1 new abstract method: * invoke The Midi and Vorbis players have a stub for these. So far only PV makes use of that new feature. To avoid any copy overhead, the JNI interface uses Parcel as a java object (no serialization/copy happens at the JNI layer). The remote interface token is inserted when the Parcel is constructed in java. That way the parcel is already routable when it reaches IMediaPlayer.cpp (proxy). No extra copy is needed there.
This commit is contained in:
@@ -73258,6 +73258,21 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="invoke"
|
||||
return="int"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="request" type="android.os.Parcel">
|
||||
</parameter>
|
||||
<parameter name="reply" type="android.os.Parcel">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="isLooping"
|
||||
return="boolean"
|
||||
abstract="false"
|
||||
@@ -73280,6 +73295,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="newRequest"
|
||||
return="android.os.Parcel"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="pause"
|
||||
return="void"
|
||||
abstract="false"
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
class Parcel;
|
||||
class ISurface;
|
||||
|
||||
class IMediaPlayer: public IInterface
|
||||
@@ -45,6 +46,14 @@ public:
|
||||
virtual status_t setAudioStreamType(int type) = 0;
|
||||
virtual status_t setLooping(int loop) = 0;
|
||||
virtual status_t setVolume(float leftVolume, float rightVolume) = 0;
|
||||
|
||||
// Invoke a generic method on the player by using opaque parcels
|
||||
// for the request and reply.
|
||||
// @param request Parcel that must start with the media player
|
||||
// interface token.
|
||||
// @param[out] reply Parcel to hold the reply data. Cannot be null.
|
||||
// @return OK if the invocation was made. PERMISSION_DENIED otherwise.
|
||||
virtual status_t invoke(const Parcel& request, Parcel *reply) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -61,4 +70,3 @@ public:
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_IMEDIAPLAYER_H
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef ANDROID_IMEDIAPLAYERSERVICE_H
|
||||
#define ANDROID_IMEDIAPLAYERSERVICE_H
|
||||
|
||||
#include <utils/Errors.h> // for status_t
|
||||
#include <utils/RefBase.h>
|
||||
#include <binder/IInterface.h>
|
||||
#include <binder/Parcel.h>
|
||||
@@ -36,7 +37,6 @@ public:
|
||||
|
||||
virtual sp<IMediaRecorder> createMediaRecorder(pid_t pid) = 0;
|
||||
virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
|
||||
|
||||
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
|
||||
virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
|
||||
virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
|
||||
|
||||
@@ -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); }
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
@@ -151,7 +151,7 @@ public:
|
||||
void notify(int msg, int ext1, int ext2);
|
||||
static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
|
||||
static sp<IMemory> 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);
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "utils/Log.h"
|
||||
|
||||
#include <media/mediaplayer.h>
|
||||
#include <media/MediaPlayerInterface.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
@@ -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 <binder/Parcel.h>
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -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<MediaPlayer> 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},
|
||||
};
|
||||
|
||||
@@ -39,7 +39,8 @@ enum {
|
||||
RESET,
|
||||
SET_AUDIO_STREAM_TYPE,
|
||||
SET_LOOPING,
|
||||
SET_VOLUME
|
||||
SET_VOLUME,
|
||||
INVOKE,
|
||||
};
|
||||
|
||||
class BpMediaPlayer: public BpInterface<IMediaPlayer>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <binder/Parcel.h>
|
||||
|
||||
#include <binder/IMemory.h>
|
||||
#include <utils/Errors.h> // for status_t
|
||||
#include <media/IMediaPlayerService.h>
|
||||
#include <media/IMediaRecorder.h>
|
||||
|
||||
|
||||
@@ -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>& surface)
|
||||
{
|
||||
LOGV("setVideoSurface");
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/MemoryHeapBase.h>
|
||||
#include <binder/MemoryBase.h>
|
||||
#include <utils/Errors.h> // for status_t
|
||||
#include <utils/String8.h>
|
||||
#include <utils/Vector.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include <media/MediaPlayerInterface.h>
|
||||
@@ -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<ISurface>& surface
|
||||
return p->setVideoSurface(surface);
|
||||
}
|
||||
|
||||
status_t MediaPlayerService::Client::invoke(const Parcel& request,
|
||||
Parcel *reply)
|
||||
{
|
||||
sp<MediaPlayerBase> p = getPlayer();
|
||||
if (p == NULL) return UNKNOWN_ERROR;
|
||||
return p->invoke(request, reply);
|
||||
}
|
||||
|
||||
status_t MediaPlayerService::Client::prepareAsync()
|
||||
{
|
||||
LOGV("[%d] prepareAsync", mConnId);
|
||||
|
||||
@@ -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<MediaPlayerBase> createPlayer(player_type playerType);
|
||||
status_t setDataSource(const char *url);
|
||||
@@ -238,4 +239,3 @@ private:
|
||||
}; // namespace android
|
||||
|
||||
#endif // ANDROID_MEDIAPLAYERSERVICE_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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user