diff --git a/api/current.txt b/api/current.txt index b8487a98cddb4..c718afd64264e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -10668,7 +10668,7 @@ package android.media { method public void setAuxEffectSendLevel(float); method public void setDataSource(android.content.Context, android.net.Uri) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException; method public void setDataSource(android.content.Context, android.net.Uri, java.util.Map) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException; - method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; + method public void setDataSource(java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.SecurityException; method public void setDataSource(java.io.FileDescriptor) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void setDataSource(java.io.FileDescriptor, long, long) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException; method public void setDisplay(android.view.SurfaceHolder); diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp index aa3bc03bae4dd..b13236a3569cf 100644 --- a/cmds/stagefright/stream.cpp +++ b/cmds/stagefright/stream.cpp @@ -357,9 +357,9 @@ int main(int argc, char **argv) { } sp player = - service->create(getpid(), client, source, 0); + service->create(getpid(), client, 0); - if (player != NULL) { + if (player != NULL && player->setDataSource(source) == NO_ERROR) { player->setVideoSurface(surface); player->start(); diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h index d552b2e23c5b0..0e2cdf79ad198 100644 --- a/include/media/IMediaPlayer.h +++ b/include/media/IMediaPlayer.h @@ -20,11 +20,13 @@ #include #include #include +#include namespace android { class Parcel; class Surface; +class IStreamSource; class ISurfaceTexture; class IMediaPlayer: public IInterface @@ -34,6 +36,10 @@ public: virtual void disconnect() = 0; + virtual status_t setDataSource(const char *url, + const KeyedVector* headers) = 0; + virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0; + virtual status_t setDataSource(const sp& source) = 0; virtual status_t setVideoSurface(const sp& surface) = 0; virtual status_t setVideoSurfaceTexture( const sp& surfaceTexture) = 0; diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h index 795678881a012..93bbe13ea4c10 100644 --- a/include/media/IMediaPlayerService.h +++ b/include/media/IMediaPlayerService.h @@ -39,17 +39,9 @@ class IMediaPlayerService: public IInterface public: DECLARE_META_INTERFACE(MediaPlayerService); - virtual sp createMediaRecorder(pid_t pid) = 0; + 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, const KeyedVector *headers = NULL, - int audioSessionId = 0) = 0; - virtual sp create(pid_t pid, const sp& client, - int fd, int64_t offset, int64_t length, int audioSessionId) = 0; - - virtual sp create( - pid_t pid, const sp &client, - const sp &source, int audioSessionId) = 0; + virtual sp create(pid_t pid, const sp& client, int audioSessionId = 0) = 0; virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0; virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0; diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h index 1a676716afdd6..e98d55cee5024 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -168,6 +169,7 @@ public: const KeyedVector *headers); status_t setDataSource(int fd, int64_t offset, int64_t length); + status_t setDataSource(const sp &source); status_t setVideoSurface(const sp& surface); status_t setVideoSurfaceTexture( const sp& surfaceTexture); @@ -206,7 +208,7 @@ private: status_t seekTo_l(int msec); status_t prepareAsync_l(); status_t getDuration_l(int *msec); - status_t setDataSource(const sp& player); + status_t attachNewPlayer(const sp& player); void disconnectNativeWindow(); status_t reset_l(); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 1ee9a1fcc52b6..e25f654f812f8 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -459,6 +459,9 @@ import java.lang.ref.WeakReference; * android.R.styleable#AndroidManifestUsesPermission <uses-permission>} * element. * + *

This class requires the {@link android.Manifest.permission#INTERNET} permission + * when used with network-based content. + * * *

Callbacks

*

Applications may want to register for informational and error @@ -828,6 +831,7 @@ public class MediaPlayer fd.close(); } } + Log.d(TAG, "Couldn't open file on client side, trying server side"); setDataSource(uri.toString(), headers); return; @@ -839,7 +843,8 @@ public class MediaPlayer * @param path the path of the file, or the http/rtsp URL of the stream you want to play * @throws IllegalStateException if it is called in an invalid state */ - public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException; + public native void setDataSource(String path) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; /** * Sets the data source (file-path or http/rtsp URL) to use. @@ -850,7 +855,7 @@ public class MediaPlayer * @hide pending API council */ public void setDataSource(String path, Map headers) - throws IOException, IllegalArgumentException, IllegalStateException + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { String[] keys = null; String[] values = null; @@ -871,7 +876,7 @@ public class MediaPlayer private native void _setDataSource( String path, String[] keys, String[] values) - throws IOException, IllegalArgumentException, IllegalStateException; + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException; /** * Sets the data source (FileDescriptor) to use. It is the caller's responsibility diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 354f2c94933ab..5dfbe01396a11 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -155,6 +155,8 @@ static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStat } else { // Throw exception! if ( opStatus == (status_t) INVALID_OPERATION ) { jniThrowException(env, "java/lang/IllegalStateException", NULL); + } else if ( opStatus == (status_t) PERMISSION_DENIED ) { + jniThrowException(env, "java/lang/SecurityException", NULL); } else if ( opStatus != (status_t) OK ) { if (strlen(message) > 230) { // if the message is too long, don't bother displaying the status code diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 52885d2e57b2d..bd89ad824e99a 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -21,14 +21,20 @@ #include #include +#include + #include #include #include +#include namespace android { enum { DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, + SET_DATA_SOURCE_URL, + SET_DATA_SOURCE_FD, + SET_DATA_SOURCE_STREAM, SET_VIDEO_SURFACE, PREPARE_ASYNC, START, @@ -68,6 +74,43 @@ public: remote()->transact(DISCONNECT, data, &reply); } + status_t setDataSource(const char* url, + const KeyedVector* headers) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeCString(url); + if (headers == NULL) { + data.writeInt32(0); + } else { + // serialize the headers + data.writeInt32(headers->size()); + for (size_t i = 0; i < headers->size(); ++i) { + data.writeString8(headers->keyAt(i)); + data.writeString8(headers->valueAt(i)); + } + } + remote()->transact(SET_DATA_SOURCE_URL, data, &reply); + return reply.readInt32(); + } + + status_t setDataSource(int fd, int64_t offset, int64_t length) { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeFileDescriptor(fd); + data.writeInt64(offset); + data.writeInt64(length); + remote()->transact(SET_DATA_SOURCE_FD, data, &reply); + return reply.readInt32(); + } + + status_t setDataSource(const sp &source) { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeStrongBinder(source->asBinder()); + return reply.readInt32(); + } + // pass the buffered Surface to the media player service status_t setVideoSurface(const sp& surface) { @@ -273,6 +316,34 @@ status_t BnMediaPlayer::onTransact( disconnect(); return NO_ERROR; } break; + case SET_DATA_SOURCE_URL: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + const char* url = data.readCString(); + KeyedVector headers; + int32_t numHeaders = data.readInt32(); + for (int i = 0; i < numHeaders; ++i) { + String8 key = data.readString8(); + String8 value = data.readString8(); + headers.add(key, value); + } + reply->writeInt32(setDataSource(url, numHeaders > 0 ? &headers : NULL)); + return NO_ERROR; + } break; + case SET_DATA_SOURCE_FD: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + int fd = data.readFileDescriptor(); + int64_t offset = data.readInt64(); + int64_t length = data.readInt64(); + reply->writeInt32(setDataSource(fd, offset, length)); + return NO_ERROR; + } + case SET_DATA_SOURCE_STREAM: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + sp source = + interface_cast(data.readStrongBinder()); + reply->writeInt32(setDataSource(source)); + return NO_ERROR; + } case SET_VIDEO_SURFACE: { CHECK_INTERFACE(IMediaPlayer, data, reply); sp surface = Surface::readFromParcel(data); diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index 17a0362862e05..8e4dd04f811ac 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -30,9 +30,7 @@ namespace android { enum { - CREATE_URL = IBinder::FIRST_CALL_TRANSACTION, - CREATE_FD, - CREATE_STREAM, + CREATE = IBinder::FIRST_CALL_TRANSACTION, DECODE_URL, DECODE_FD, CREATE_MEDIA_RECORDER, @@ -60,28 +58,14 @@ public: } virtual sp create( - pid_t pid, const sp& client, - const char* url, const KeyedVector *headers, int audioSessionId) { + pid_t pid, const sp& client, int audioSessionId) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); data.writeInt32(pid); data.writeStrongBinder(client->asBinder()); - data.writeCString(url); - - if (headers == NULL) { - data.writeInt32(0); - } else { - // serialize the headers - data.writeInt32(headers->size()); - for (size_t i = 0; i < headers->size(); ++i) { - data.writeString8(headers->keyAt(i)); - data.writeString8(headers->valueAt(i)); - } - } data.writeInt32(audioSessionId); - remote()->transact(CREATE_URL, data, &reply); - + remote()->transact(CREATE, data, &reply); return interface_cast(reply.readStrongBinder()); } @@ -94,38 +78,6 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual sp create(pid_t pid, const sp& client, int fd, - int64_t offset, int64_t length, int audioSessionId) - { - Parcel data, reply; - data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - data.writeInt32(pid); - data.writeStrongBinder(client->asBinder()); - data.writeFileDescriptor(fd); - data.writeInt64(offset); - data.writeInt64(length); - data.writeInt32(audioSessionId); - - remote()->transact(CREATE_FD, data, &reply); - - return interface_cast(reply.readStrongBinder());; - } - - virtual sp create( - pid_t pid, const sp &client, - const sp &source, int audioSessionId) { - Parcel data, reply; - data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); - data.writeInt32(static_cast(pid)); - data.writeStrongBinder(client->asBinder()); - data.writeStrongBinder(source->asBinder()); - data.writeInt32(static_cast(audioSessionId)); - - remote()->transact(CREATE_STREAM, data, &reply); - - return interface_cast(reply.readStrongBinder());; - } - virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) { Parcel data, reply; @@ -181,62 +133,16 @@ status_t BnMediaPlayerService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { - case CREATE_URL: { + case CREATE: { CHECK_INTERFACE(IMediaPlayerService, data, reply); pid_t pid = data.readInt32(); sp client = interface_cast(data.readStrongBinder()); - const char* url = data.readCString(); - - KeyedVector headers; - int32_t numHeaders = data.readInt32(); - for (int i = 0; i < numHeaders; ++i) { - String8 key = data.readString8(); - String8 value = data.readString8(); - headers.add(key, value); - } int audioSessionId = data.readInt32(); - - sp player = create( - pid, client, url, numHeaders > 0 ? &headers : NULL, audioSessionId); - + sp player = create(pid, client, audioSessionId); reply->writeStrongBinder(player->asBinder()); return NO_ERROR; } break; - case CREATE_FD: { - CHECK_INTERFACE(IMediaPlayerService, data, reply); - pid_t pid = data.readInt32(); - sp client = interface_cast(data.readStrongBinder()); - int fd = dup(data.readFileDescriptor()); - int64_t offset = data.readInt64(); - int64_t length = data.readInt64(); - int audioSessionId = data.readInt32(); - - sp player = create(pid, client, fd, offset, length, audioSessionId); - reply->writeStrongBinder(player->asBinder()); - return NO_ERROR; - } break; - case CREATE_STREAM: - { - CHECK_INTERFACE(IMediaPlayerService, data, reply); - - pid_t pid = static_cast(data.readInt32()); - - sp client = - interface_cast(data.readStrongBinder()); - - sp source = - interface_cast(data.readStrongBinder()); - - int audioSessionId = static_cast(data.readInt32()); - - sp player = - create(pid, client, source, audioSessionId); - - reply->writeStrongBinder(player->asBinder()); - return OK; - break; - } case DECODE_URL: { CHECK_INTERFACE(IMediaPlayerService, data, reply); const char* url = data.readCString(); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 67a66a289f1cf..0fc6a8a85138a 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -108,7 +108,7 @@ status_t MediaPlayer::setListener(const sp& listener) } -status_t MediaPlayer::setDataSource(const sp& player) +status_t MediaPlayer::attachNewPlayer(const sp& player) { status_t err = UNKNOWN_ERROR; sp p; @@ -117,7 +117,7 @@ status_t MediaPlayer::setDataSource(const sp& player) if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) || (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) { - LOGE("setDataSource called in state %d", mCurrentState); + LOGE("attachNewPlayer called in state %d", mCurrentState); return INVALID_OPERATION; } @@ -147,9 +147,11 @@ status_t MediaPlayer::setDataSource( if (url != NULL) { const sp& service(getMediaPlayerService()); if (service != 0) { - sp player( - service->create(getpid(), this, url, headers, mAudioSessionId)); - err = setDataSource(player); + sp player(service->create(getpid(), this, mAudioSessionId)); + err = attachNewPlayer(player); + if (err == NO_ERROR) { + err = mPlayer->setDataSource(url, headers); + } } } return err; @@ -161,8 +163,26 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) status_t err = UNKNOWN_ERROR; const sp& service(getMediaPlayerService()); if (service != 0) { - sp player(service->create(getpid(), this, fd, offset, length, mAudioSessionId)); - err = setDataSource(player); + sp player(service->create(getpid(), this, mAudioSessionId)); + err = attachNewPlayer(player); + if (err == NO_ERROR) { + err = mPlayer->setDataSource(fd, offset, length); + } + } + return err; +} + +status_t MediaPlayer::setDataSource(const sp &source) +{ + LOGV("setDataSource"); + status_t err = UNKNOWN_ERROR; + const sp& service(getMediaPlayerService()); + if (service != 0) { + sp player(service->create(getpid(), this, mAudioSessionId)); + err = attachNewPlayer(player); + if (err == NO_ERROR) { + err = mPlayer->setDataSource(source); + } } return err; } diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 2051b3ba49feb..0386d4b659877 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -176,6 +176,16 @@ bool findMetadata(const Metadata::Filter& filter, const int32_t val) namespace android { +static bool checkPermission(const char* permissionString) { +#ifndef HAVE_ANDROID_OS + return true; +#endif + if (getpid() == IPCThreadState::self()->getCallingPid()) return true; + bool ok = checkCallingPermission(String16(permissionString)); + if (!ok) LOGE("Request requires %s", permissionString); + return ok; +} + // TODO: Temp hack until we can register players typedef struct { const char *extension; @@ -245,31 +255,8 @@ sp MediaPlayerService::createMetadataRetriever(pid_t pi return retriever; } -sp MediaPlayerService::create( - pid_t pid, const sp& client, const char* url, - const KeyedVector *headers, int audioSessionId) -{ - int32_t connId = android_atomic_inc(&mNextConnId); - - sp c = new Client( - this, pid, connId, client, audioSessionId, - IPCThreadState::self()->getCallingUid()); - - LOGV("Create new client(%d) from pid %d, uid %d, url=%s, connId=%d, audioSessionId=%d", - connId, pid, IPCThreadState::self()->getCallingUid(), url, connId, audioSessionId); - if (NO_ERROR != c->setDataSource(url, headers)) - { - c.clear(); - return c; - } - wp w = c; - Mutex::Autolock lock(mLock); - mClients.add(w); - return c; -} - sp MediaPlayerService::create(pid_t pid, const sp& client, - int fd, int64_t offset, int64_t length, int audioSessionId) + int audioSessionId) { int32_t connId = android_atomic_inc(&mNextConnId); @@ -277,40 +264,14 @@ sp MediaPlayerService::create(pid_t pid, const spgetCallingUid()); - LOGV("Create new client(%d) from pid %d, uid %d, fd=%d, offset=%lld, " - "length=%lld, audioSessionId=%d", connId, pid, - IPCThreadState::self()->getCallingUid(), fd, offset, length, audioSessionId); - if (NO_ERROR != c->setDataSource(fd, offset, length)) { - c.clear(); - } else { - wp w = c; + LOGV("Create new client(%d) from pid %d, uid %d, ", connId, pid, + IPCThreadState::self()->getCallingUid()); + + wp w = c; + { Mutex::Autolock lock(mLock); mClients.add(w); } - ::close(fd); - return c; -} - -sp MediaPlayerService::create( - pid_t pid, const sp &client, - const sp &source, int audioSessionId) { - int32_t connId = android_atomic_inc(&mNextConnId); - - sp c = new Client( - this, pid, connId, client, audioSessionId, - IPCThreadState::self()->getCallingUid()); - - LOGV("Create new client(%d) from pid %d, audioSessionId=%d", - connId, pid, audioSessionId); - - if (OK != c->setDataSource(source)) { - c.clear(); - } else { - wp w = c; - Mutex::Autolock lock(mLock); - mClients.add(w); - } - return c; } @@ -701,6 +662,14 @@ status_t MediaPlayerService::Client::setDataSource( if (url == NULL) return UNKNOWN_ERROR; + if ((strncmp(url, "http://", 7) == 0) || + (strncmp(url, "https://", 8) == 0) || + (strncmp(url, "rtsp://", 7) == 0)) { + if (!checkPermission("android.permission.INTERNET")) { + return PERMISSION_DENIED; + } + } + if (strncmp(url, "content://", 10) == 0) { // get a filedescriptor for the content Uri and // pass it to the setDataSource(fd) method @@ -781,6 +750,7 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64 // now set data source mStatus = p->setDataSource(fd, offset, length); if (mStatus == NO_ERROR) mPlayer = p; + return mStatus; } diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index e32b92a659ca4..53e625a438555 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -188,16 +188,7 @@ public: void removeMediaRecorderClient(wp client); virtual sp createMetadataRetriever(pid_t pid); - // House keeping for media player clients - virtual sp create( - pid_t pid, const sp& client, const char* url, - const KeyedVector *headers, int audioSessionId); - - virtual sp create(pid_t pid, const sp& client, int fd, int64_t offset, int64_t length, int audioSessionId); - - virtual sp create( - pid_t pid, const sp &client, - const sp &source, int audioSessionId); + virtual sp create(pid_t pid, const sp& client, int audioSessionId); virtual sp decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); virtual sp decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat); @@ -284,13 +275,13 @@ private: sp createPlayer(player_type playerType); - status_t setDataSource( + virtual status_t setDataSource( const char *url, const KeyedVector *headers); - status_t setDataSource(int fd, int64_t offset, int64_t length); + virtual status_t setDataSource(int fd, int64_t offset, int64_t length); - status_t setDataSource(const sp &source); + virtual status_t setDataSource(const sp &source); static void notify(void* cookie, int msg, int ext1, int ext2, const Parcel *obj);