diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h index 64258864756d6..39d58ab586a59 100644 --- a/include/media/IMediaPlayer.h +++ b/include/media/IMediaPlayer.h @@ -23,6 +23,10 @@ #include #include +// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is +// global, and not in android:: +struct sockaddr_in; + namespace android { class Parcel; @@ -59,6 +63,7 @@ public: virtual status_t attachAuxEffect(int effectId) = 0; virtual status_t setParameter(int key, const Parcel& request) = 0; virtual status_t getParameter(int key, Parcel* reply) = 0; + virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) = 0; // Invoke a generic method on the player by using opaque parcels // for the request and reply. diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index 23a3e4905a637..f7491d82a98b1 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -29,6 +29,10 @@ #include #include +// Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is +// global, and not in android:: +struct sockaddr_in; + namespace android { class Parcel; @@ -141,6 +145,14 @@ public: virtual status_t setParameter(int key, const Parcel &request) = 0; virtual status_t getParameter(int key, Parcel *reply) = 0; + // Right now, only the AAX TX player supports this functionality. For now, + // provide a default implementation which indicates a lack of support for + // this functionality to make life easier for all of the other media player + // maintainers out there. + virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) { + return INVALID_OPERATION; + } + // Invoke a generic method on the player by using opaque parcels // for the request and reply. // diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h index d0b87c8e68881..9cd5f9fc7d32d 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -17,6 +17,8 @@ #ifndef ANDROID_MEDIAPLAYER_H #define ANDROID_MEDIAPLAYER_H +#include + #include #include #include @@ -204,6 +206,7 @@ public: status_t attachAuxEffect(int effectId); status_t setParameter(int key, const Parcel& request); status_t getParameter(int key, Parcel* reply); + status_t setRetransmitEndpoint(const char* addrString, uint16_t port); private: void clear_l(); @@ -212,6 +215,7 @@ private: status_t getDuration_l(int *msec); status_t attachNewPlayer(const sp& player); status_t reset_l(); + status_t doSetRetransmitEndpoint(const sp& player); sp mPlayer; thread_id_t mLockThreadId; @@ -234,6 +238,8 @@ private: int mVideoHeight; int mAudioSessionId; float mSendLevel; + struct sockaddr_in mRetransmitEndpoint; + bool mRetransmitEndpointValid; }; }; // namespace android diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 4c70e9de1fb88..e663e91660262 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -35,6 +35,7 @@ import android.media.AudioManager; import java.io.FileDescriptor; import java.io.IOException; +import java.net.InetSocketAddress; import java.util.Map; import java.util.Set; import java.lang.ref.WeakReference; @@ -1486,6 +1487,52 @@ public class MediaPlayer */ public native static int native_pullBatteryData(Parcel reply); + /** + * Sets the target UDP re-transmit endpoint for the low level player. + * Generally, the address portion of the endpoint is an IP multicast + * address, although a unicast address would be equally valid. When a valid + * retransmit endpoint has been set, the media player will not decode and + * render the media presentation locally. Instead, the player will attempt + * to re-multiplex its media data using the Android@Home RTP profile and + * re-transmit to the target endpoint. Receiver devices (which may be + * either the same as the transmitting device or different devices) may + * instantiate, prepare, and start a receiver player using a setDataSource + * URL of the form... + * + * aahRX://<multicastIP>:<port> + * + * to receive, decode and render the re-transmitted content. + * + * setRetransmitEndpoint may only be called before setDataSource has been + * called; while the player is in the Idle state. + * + * @param endpoint the address and UDP port of the re-transmission target or + * null if no re-transmission is to be performed. + * @throws IllegalStateException if it is called in an invalid state + * @throws IllegalArgumentException if the retransmit endpoint is supplied, + * but invalid. + * + * {@hide} pending API council + */ + public void setRetransmitEndpoint(InetSocketAddress endpoint) + throws IllegalStateException, IllegalArgumentException + { + String addrString = null; + int port = 0; + + if (null != endpoint) { + addrString = endpoint.getAddress().getHostAddress(); + port = endpoint.getPort(); + } + + int ret = native_setRetransmitEndpoint(addrString, port); + if (ret != 0) { + throw new IllegalArgumentException("Illegal re-transmit endpoint; native ret " + ret); + } + } + + private native final int native_setRetransmitEndpoint(String addrString, int port); + @Override protected void finalize() { native_finalize(); } diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index f3a56686d6674..6ec5d2073236b 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -722,6 +722,45 @@ android_media_MediaPlayer_pullBatteryData(JNIEnv *env, jobject thiz, jobject jav return service->pullBatteryData(reply); } +static jint +android_media_MediaPlayer_setRetransmitEndpoint(JNIEnv *env, jobject thiz, + jstring addrString, jint port) { + sp mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return INVALID_OPERATION; + } + + const char *cAddrString = NULL; + + if (NULL != addrString) { + cAddrString = env->GetStringUTFChars(addrString, NULL); + if (cAddrString == NULL) { // Out of memory + return NO_MEMORY; + } + } + ALOGV("setRetransmitEndpoint: %s:%d", + cAddrString ? cAddrString : "(null)", port); + + status_t ret; + if (cAddrString && (port > 0xFFFF)) { + ret = BAD_VALUE; + } else { + ret = mp->setRetransmitEndpoint(cAddrString, + static_cast(port)); + } + + if (NULL != addrString) { + env->ReleaseStringUTFChars(addrString, cAddrString); + } + + if (ret == INVALID_OPERATION ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + } + + return ret; +} + static jboolean android_media_MediaPlayer_setParameter(JNIEnv *env, jobject thiz, jint key, jobject java_request) { @@ -799,6 +838,7 @@ static JNINativeMethod gMethods[] = { {"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData}, {"setParameter", "(ILandroid/os/Parcel;)Z", (void *)android_media_MediaPlayer_setParameter}, {"getParameter", "(ILandroid/os/Parcel;)V", (void *)android_media_MediaPlayer_getParameter}, + {"native_setRetransmitEndpoint", "(Ljava/lang/String;I)I", (void *)android_media_MediaPlayer_setRetransmitEndpoint}, }; static const char* const kClassPathName = "android/media/MediaPlayer"; diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp index 90f78945bde64..974805b306d75 100644 --- a/media/libaah_rtp/aah_tx_player.cpp +++ b/media/libaah_rtp/aah_tx_player.cpp @@ -149,14 +149,7 @@ status_t AAH_TXPlayer::setDataSource_l( const KeyedVector *headers) { reset_l(); - // the URL must consist of "aahTX://" followed by the real URL of - // the data source - const char *kAAHPrefix = "aahTX://"; - if (strncasecmp(url, kAAHPrefix, strlen(kAAHPrefix))) { - return INVALID_OPERATION; - } - - mUri.setTo(url + strlen(kAAHPrefix)); + mUri.setTo(url); if (headers) { mUriHeaders = *headers; @@ -794,67 +787,7 @@ status_t AAH_TXPlayer::getParameter(int key, Parcel *reply) { } status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) { - if (!reply) { - return BAD_VALUE; - } - - int32_t methodID; - status_t err = request.readInt32(&methodID); - if (err != android::OK) { - return err; - } - - switch (methodID) { - case kInvokeSetAAHDstIPPort: - case kInvokeSetAAHConfigBlob: { - if (mEndpointValid) { - return INVALID_OPERATION; - } - - String8 addr; - uint16_t port; - - if (methodID == kInvokeSetAAHDstIPPort) { - addr = String8(request.readString16()); - - int32_t port32; - err = request.readInt32(&port32); - if (err != android::OK) { - return err; - } - port = static_cast(port32); - } else { - String8 blob(request.readString16()); - - char addr_buf[101]; - if (sscanf(blob.string(), "V1:%100s %" SCNu16, - addr_buf, &port) != 2) { - return BAD_VALUE; - } - if (addr.setTo(addr_buf) != OK) { - return NO_MEMORY; - } - } - - struct hostent* ent = gethostbyname(addr.string()); - if (ent == NULL) { - return ERROR_UNKNOWN_HOST; - } - if (!(ent->h_addrtype == AF_INET && ent->h_length == 4)) { - return BAD_VALUE; - } - - Mutex::Autolock lock(mEndpointLock); - mEndpoint = AAH_TXSender::Endpoint( - reinterpret_cast(ent->h_addr)->s_addr, - port); - mEndpointValid = true; - return OK; - }; - - default: - return INVALID_OPERATION; - } + return INVALID_OPERATION; } status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids, @@ -889,6 +822,24 @@ status_t AAH_TXPlayer::setAudioStreamType(audio_stream_type_t streamType) { return OK; } +status_t AAH_TXPlayer::setRetransmitEndpoint( + const struct sockaddr_in* endpoint) { + Mutex::Autolock lock(mLock); + + if (NULL == endpoint) + return BAD_VALUE; + + // Once the endpoint has been registered, it may not be changed. + if (mEndpointRegistered) + return INVALID_OPERATION; + + mEndpoint.addr = endpoint->sin_addr.s_addr; + mEndpoint.port = endpoint->sin_port; + mEndpointValid = true; + + return OK; +} + void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) { sendEvent(msg, ext1, ext2); } diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h index 094c6f2b14fe0..2e4b1f7ec5042 100644 --- a/media/libaah_rtp/aah_tx_player.h +++ b/media/libaah_rtp/aah_tx_player.h @@ -63,16 +63,8 @@ class AAH_TXPlayer : public MediaPlayerHWInterface { Parcel* records); virtual status_t setVolume(float leftVolume, float rightVolume); virtual status_t setAudioStreamType(audio_stream_type_t streamType); - - // invoke method IDs - enum { - // set the IP address and port of the A@H receiver - kInvokeSetAAHDstIPPort = 1, - - // set the destination IP address and port (and perhaps any additional - // parameters added in the future) packaged in one string - kInvokeSetAAHConfigBlob, - }; + virtual status_t setRetransmitEndpoint( + const struct sockaddr_in* endpoint); static const int64_t kAAHRetryKeepAroundTimeNs; diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp index 499068c17d6bd..08e32d26b00ae 100644 --- a/media/libaah_rtp/aah_tx_sender.cpp +++ b/media/libaah_rtp/aah_tx_sender.cpp @@ -243,7 +243,7 @@ void AAH_TXSender::doSendPacket_l(const sp& packet, memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = endpoint.addr; - addr.sin_port = htons(endpoint.port); + addr.sin_port = endpoint.port; ssize_t result = sendto(mSocket, packet->getPacket(), @@ -412,7 +412,7 @@ void AAH_TXSender::RetryReceiver::handleRetryRequest() { return; } - Endpoint endpoint(request.endpointIP, ntohs(request.endpointPort)); + Endpoint endpoint(request.endpointIP, request.endpointPort); Mutex::Autolock lock(mSender->mEndpointLock); diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 86d65db5ddc10..c47fa41e346b4 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -15,6 +15,7 @@ ** limitations under the License. */ +#include #include #include @@ -53,6 +54,7 @@ enum { SET_VIDEO_SURFACETEXTURE, SET_PARAMETER, GET_PARAMETER, + SET_RETRANSMIT_ENDPOINT, }; class BpMediaPlayer: public BpInterface @@ -289,6 +291,25 @@ public: return remote()->transact(GET_PARAMETER, data, reply); } + status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint) { + Parcel data, reply; + status_t err; + + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + if (NULL != endpoint) { + data.writeInt32(sizeof(*endpoint)); + data.write(endpoint, sizeof(*endpoint)); + } else { + data.writeInt32(0); + } + + err = remote()->transact(SET_RETRANSMIT_ENDPOINT, data, &reply); + if (OK != err) { + return err; + } + + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); @@ -457,6 +478,20 @@ status_t BnMediaPlayer::onTransact( CHECK_INTERFACE(IMediaPlayer, data, reply); return getParameter(data.readInt32(), reply); } break; + case SET_RETRANSMIT_ENDPOINT: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + + struct sockaddr_in endpoint; + int amt = data.readInt32(); + if (amt == sizeof(endpoint)) { + data.read(&endpoint, sizeof(struct sockaddr_in)); + reply->writeInt32(setRetransmitEndpoint(&endpoint)); + } else { + reply->writeInt32(setRetransmitEndpoint(NULL)); + } + + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 9d459071f3f90..4ff1862e8d9c5 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -61,6 +61,7 @@ MediaPlayer::MediaPlayer() mAudioSessionId = AudioSystem::newAudioSessionId(); AudioSystem::acquireAudioSessionId(mAudioSessionId); mSendLevel = 0; + mRetransmitEndpointValid = false; } MediaPlayer::~MediaPlayer() @@ -93,6 +94,7 @@ void MediaPlayer::clear_l() mCurrentPosition = -1; mSeekPosition = -1; mVideoWidth = mVideoHeight = 0; + mRetransmitEndpointValid = false; } status_t MediaPlayer::setListener(const sp& listener) @@ -144,7 +146,8 @@ status_t MediaPlayer::setDataSource( const sp& service(getMediaPlayerService()); if (service != 0) { sp player(service->create(getpid(), this, mAudioSessionId)); - if (NO_ERROR != player->setDataSource(url, headers)) { + if ((NO_ERROR != doSetRetransmitEndpoint(player)) || + (NO_ERROR != player->setDataSource(url, headers))) { player.clear(); } err = attachNewPlayer(player); @@ -160,7 +163,8 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) const sp& service(getMediaPlayerService()); if (service != 0) { sp player(service->create(getpid(), this, mAudioSessionId)); - if (NO_ERROR != player->setDataSource(fd, offset, length)) { + if ((NO_ERROR != doSetRetransmitEndpoint(player)) || + (NO_ERROR != player->setDataSource(fd, offset, length))) { player.clear(); } err = attachNewPlayer(player); @@ -175,7 +179,8 @@ status_t MediaPlayer::setDataSource(const sp &source) const sp& service(getMediaPlayerService()); if (service != 0) { sp player(service->create(getpid(), this, mAudioSessionId)); - if (NO_ERROR != player->setDataSource(source)) { + if ((NO_ERROR != doSetRetransmitEndpoint(player)) || + (NO_ERROR != player->setDataSource(source))) { player.clear(); } err = attachNewPlayer(player); @@ -469,6 +474,20 @@ status_t MediaPlayer::reset_l() return NO_ERROR; } +status_t MediaPlayer::doSetRetransmitEndpoint(const sp& player) { + Mutex::Autolock _l(mLock); + + if (player == NULL) { + return UNKNOWN_ERROR; + } + + if (mRetransmitEndpointValid) { + return player->setRetransmitEndpoint(&mRetransmitEndpoint); + } + + return OK; +} + status_t MediaPlayer::reset() { ALOGV("reset"); @@ -597,6 +616,34 @@ status_t MediaPlayer::getParameter(int key, Parcel *reply) return INVALID_OPERATION; } +status_t MediaPlayer::setRetransmitEndpoint(const char* addrString, + uint16_t port) { + ALOGV("MediaPlayer::setRetransmitEndpoint(%s:%hu)", + addrString ? addrString : "(null)", port); + + Mutex::Autolock _l(mLock); + if ((mPlayer != NULL) || (mCurrentState != MEDIA_PLAYER_IDLE)) + return INVALID_OPERATION; + + if (NULL == addrString) { + mRetransmitEndpointValid = false; + return OK; + } + + struct in_addr saddr; + if(!inet_aton(addrString, &saddr)) { + return BAD_VALUE; + } + + memset(&mRetransmitEndpoint, 0, sizeof(&mRetransmitEndpoint)); + mRetransmitEndpoint.sin_family = AF_INET; + mRetransmitEndpoint.sin_addr = saddr; + mRetransmitEndpoint.sin_port = htons(port); + mRetransmitEndpointValid = true; + + return OK; +} + void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj) { ALOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 764eddc840a82..1e2abf026126f 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -492,6 +492,7 @@ MediaPlayerService::Client::Client( mStatus = NO_INIT; mAudioSessionId = audioSessionId; mUID = uid; + mRetransmitEndpointValid = false; #if CALLBACK_ANTAGONIZER ALOGD("create Antagonizer"); @@ -602,10 +603,6 @@ player_type getPlayerType(const char* url) return AAH_RX_PLAYER; } - if (!strncasecmp("aahTX://", url, 8)) { - return AAH_TX_PLAYER; - } - // use MidiFile for MIDI extensions int lenURL = strlen(url); for (int i = 0; i < NELEM(FILE_EXTS); ++i) { @@ -621,6 +618,44 @@ player_type getPlayerType(const char* url) return getDefaultPlayerType(); } +player_type MediaPlayerService::Client::getPlayerType(int fd, + int64_t offset, + int64_t length) +{ + // Until re-transmit functionality is added to the existing core android + // players, we use the special AAH TX player whenever we were configured + // for retransmission. + if (mRetransmitEndpointValid) { + return AAH_TX_PLAYER; + } + + return android::getPlayerType(fd, offset, length); +} + +player_type MediaPlayerService::Client::getPlayerType(const char* url) +{ + // Until re-transmit functionality is added to the existing core android + // players, we use the special AAH TX player whenever we were configured + // for retransmission. + if (mRetransmitEndpointValid) { + return AAH_TX_PLAYER; + } + + return android::getPlayerType(url); +} + +player_type MediaPlayerService::Client::getPlayerType( + const sp &source) { + // Until re-transmit functionality is added to the existing core android + // players, we use the special AAH TX player whenever we were configured + // for retransmission. + if (mRetransmitEndpointValid) { + return AAH_TX_PLAYER; + } + + return NU_PLAYER; +} + static sp createPlayer(player_type playerType, void* cookie, notify_callback_f notifyFunc) { @@ -686,6 +721,49 @@ sp MediaPlayerService::Client::createPlayer(player_type playerT return p; } +sp MediaPlayerService::Client::setDataSource_pre( + player_type playerType) +{ + ALOGV("player type = %d", playerType); + + // create the right type of player + sp p = createPlayer(playerType); + if (p == NULL) { + return p; + } + + if (!p->hardwareOutput()) { + mAudioOutput = new AudioOutput(mAudioSessionId); + static_cast(p.get())->setAudioSink(mAudioOutput); + } + + return p; +} + +void MediaPlayerService::Client::setDataSource_post( + const sp& p, + status_t status) +{ + ALOGV(" setDataSource"); + mStatus = status; + if (mStatus != OK) { + ALOGE(" error: %d", mStatus); + return; + } + + // Set the re-transmission endpoint if one was chosen. + if (mRetransmitEndpointValid) { + mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint); + if (mStatus != NO_ERROR) { + ALOGE("setRetransmitEndpoint error: %d", mStatus); + } + } + + if (mStatus == OK) { + mPlayer = p; + } +} + status_t MediaPlayerService::Client::setDataSource( const char *url, const KeyedVector *headers) { @@ -717,25 +795,12 @@ status_t MediaPlayerService::Client::setDataSource( return mStatus; } else { player_type playerType = getPlayerType(url); - ALOGV("player type = %d", playerType); - - // create the right type of player - sp p = createPlayer(playerType); - if (p == NULL) return NO_INIT; - - if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(mAudioSessionId); - static_cast(p.get())->setAudioSink(mAudioOutput); + sp p = setDataSource_pre(playerType); + if (p == NULL) { + return NO_INIT; } - // now set data source - ALOGV(" setDataSource"); - mStatus = p->setDataSource(url, headers); - if (mStatus == NO_ERROR) { - mPlayer = p; - } else { - ALOGE(" error: %d", mStatus); - } + setDataSource_post(p, p->setDataSource(url, headers)); return mStatus; } } @@ -766,46 +831,34 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64 ALOGV("calculated length = %lld", length); } + // Until re-transmit functionality is added to the existing core android + // players, we use the special AAH TX player whenever we were configured for + // retransmission. player_type playerType = getPlayerType(fd, offset, length); - ALOGV("player type = %d", playerType); - - // create the right type of player - sp p = createPlayer(playerType); - if (p == NULL) return NO_INIT; - - if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(mAudioSessionId); - static_cast(p.get())->setAudioSink(mAudioOutput); + sp p = setDataSource_pre(playerType); + if (p == NULL) { + return NO_INIT; } // now set data source - mStatus = p->setDataSource(fd, offset, length); - if (mStatus == NO_ERROR) mPlayer = p; - + setDataSource_post(p, p->setDataSource(fd, offset, length)); return mStatus; } status_t MediaPlayerService::Client::setDataSource( const sp &source) { // create the right type of player - sp p = createPlayer(NU_PLAYER); - + // Until re-transmit functionality is added to the existing core android + // players, we use the special AAH TX player whenever we were configured for + // retransmission. + player_type playerType = getPlayerType(source); + sp p = setDataSource_pre(playerType); if (p == NULL) { return NO_INIT; } - if (!p->hardwareOutput()) { - mAudioOutput = new AudioOutput(mAudioSessionId); - static_cast(p.get())->setAudioSink(mAudioOutput); - } - // now set data source - mStatus = p->setDataSource(source); - - if (mStatus == OK) { - mPlayer = p; - } - + setDataSource_post(p, p->setDataSource(source)); return mStatus; } @@ -1026,6 +1079,7 @@ status_t MediaPlayerService::Client::seekTo(int msec) status_t MediaPlayerService::Client::reset() { ALOGV("[%d] reset", mConnId); + mRetransmitEndpointValid = false; sp p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; return p->reset(); @@ -1100,6 +1154,36 @@ status_t MediaPlayerService::Client::getParameter(int key, Parcel *reply) { return p->getParameter(key, reply); } +status_t MediaPlayerService::Client::setRetransmitEndpoint( + const struct sockaddr_in* endpoint) { + + if (NULL != endpoint) { + uint32_t a = ntohl(endpoint->sin_addr.s_addr); + uint16_t p = ntohs(endpoint->sin_port); + ALOGV("[%d] setRetransmitEndpoint(%u.%u.%u.%u:%hu)", mConnId, + (a >> 24), (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a & 0xFF), p); + } else { + ALOGV("[%d] setRetransmitEndpoint = ", mConnId); + } + + sp p = getPlayer(); + + // Right now, the only valid time to set a retransmit endpoint is before + // player selection has been made (since the presence or absence of a + // retransmit endpoint is going to determine which player is selected during + // setDataSource). + if (p != 0) return INVALID_OPERATION; + + if (NULL != endpoint) { + mRetransmitEndpoint = *endpoint; + mRetransmitEndpointValid = true; + } else { + mRetransmitEndpointValid = false; + } + + return NO_ERROR; +} + void MediaPlayerService::Client::notify( void* cookie, int msg, int ext1, int ext2, const Parcel *obj) { diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 52af64de80350..53847eda2a080 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -18,6 +18,8 @@ #ifndef ANDROID_MEDIAPLAYERSERVICE_H #define ANDROID_MEDIAPLAYERSERVICE_H +#include + #include #include #include @@ -276,6 +278,7 @@ private: virtual status_t attachAuxEffect(int effectId); virtual status_t setParameter(int key, const Parcel &request); virtual status_t getParameter(int key, Parcel *reply); + virtual status_t setRetransmitEndpoint(const struct sockaddr_in* endpoint); sp createPlayer(player_type playerType); @@ -287,6 +290,14 @@ private: virtual status_t setDataSource(const sp &source); + sp setDataSource_pre(player_type playerType); + void setDataSource_post(const sp& p, + status_t status); + + player_type getPlayerType(int fd, int64_t offset, int64_t length); + player_type getPlayerType(const char* url); + player_type getPlayerType(const sp &source); + static void notify(void* cookie, int msg, int ext1, int ext2, const Parcel *obj); @@ -338,6 +349,8 @@ private: uid_t mUID; sp mConnectedWindow; sp mConnectedWindowBinder; + struct sockaddr_in mRetransmitEndpoint; + bool mRetransmitEndpointValid; // Metadata filters. media::Metadata::Filter mMetadataAllow; // protected by mLock