OSDN Git Service

Switch the way we configure for MediaPlayer retransmission.
authorJohn Grossman <johngro@google.com>
Wed, 22 Feb 2012 23:38:35 +0000 (15:38 -0800)
committerJohn Grossman <johngro@google.com>
Thu, 23 Feb 2012 20:02:04 +0000 (12:02 -0800)
Move in the direction of a more publishable API for configuring a
media player for retransmission.  It used to be that we used a custom
invoke and a modified URL (prefixed with aahTX://).  There are many
issues with this technique and it was never meant to stand the test of
time.

This CL gets rid of all that.  A new (but currently hidden) method was
introduced to the java level MediaPlayer API, called
setRetransmitTarget(InetSocketAddress), which allows an app writer to
set the retransmit target.  For now, this method needs to be called
before a call to setDataSource (which is pretty unusual for the
MediaPlayer API) because this mid level code uses this as a cue to
instantiate an aahTX player instead of relying on the data source to
select a player.  When retranmit functionality becomes part of the
existing android player implemenation, this
set-retrans-before-set-data-source behavior can go away, along with
the aahTX player itself.

Change-Id: I6ab07d89b2eeb0650e634b8c3b7a0b36aba4e7dd

include/media/IMediaPlayer.h
include/media/MediaPlayerInterface.h
include/media/mediaplayer.h
media/libaah_rtp/aah_tx_player.cpp
media/libaah_rtp/aah_tx_player.h
media/libaah_rtp/aah_tx_sender.cpp
media/libmedia/IMediaPlayer.cpp
media/libmedia/mediaplayer.cpp
media/libmediaplayerservice/MediaPlayerService.cpp
media/libmediaplayerservice/MediaPlayerService.h

index e905903..ed98dce 100644 (file)
 #include <binder/Parcel.h>
 #include <utils/KeyedVector.h>
 
+// 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;
@@ -58,6 +62,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.
index 354f91d..74a265e 100644 (file)
 #include <media/AudioSystem.h>
 #include <media/Metadata.h>
 
+// 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;
@@ -139,6 +143,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.
     //
index e6a0cc5..7cc1693 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef ANDROID_MEDIAPLAYER_H
 #define ANDROID_MEDIAPLAYER_H
 
+#include <arpa/inet.h>
+
 #include <binder/IMemory.h>
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
@@ -201,6 +203,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();
@@ -209,6 +212,7 @@ private:
             status_t        getDuration_l(int *msec);
             status_t        attachNewPlayer(const sp<IMediaPlayer>& player);
             status_t        reset_l();
+            status_t        doSetRetransmitEndpoint(const sp<IMediaPlayer>& player);
 
     sp<IMediaPlayer>            mPlayer;
     thread_id_t                 mLockThreadId;
@@ -231,6 +235,8 @@ private:
     int                         mVideoHeight;
     int                         mAudioSessionId;
     float                       mSendLevel;
+    struct sockaddr_in          mRetransmitEndpoint;
+    bool                        mRetransmitEndpointValid;
 };
 
 }; // namespace android
index 6407074..6328115 100644 (file)
@@ -149,14 +149,7 @@ status_t AAH_TXPlayer::setDataSource_l(
         const KeyedVector<String8, String8> *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<uint16_t>(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<struct in_addr*>(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(int 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);
 }
index b45a661..6843f9b 100644 (file)
@@ -63,16 +63,8 @@ class AAH_TXPlayer : public MediaPlayerHWInterface {
                                     Parcel* records);
     virtual status_t    setVolume(float leftVolume, float rightVolume);
     virtual status_t    setAudioStreamType(int 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;
 
index cbe5514..1dcb6e9 100644 (file)
@@ -243,7 +243,7 @@ void AAH_TXSender::doSendPacket_l(const sp<TRTPPacket>& 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(),
@@ -411,7 +411,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);
 
index 9c1e6b7..36a9efe 100644 (file)
@@ -15,6 +15,7 @@
 ** limitations under the License.
 */
 
+#include <arpa/inet.h>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -55,6 +56,7 @@ enum {
     SET_VIDEO_SURFACETEXTURE,
     SET_PARAMETER,
     GET_PARAMETER,
+    SET_RETRANSMIT_ENDPOINT,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -291,6 +293,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");
@@ -459,6 +480,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);
     }
index c2e1ddf..111962c 100644 (file)
@@ -63,6 +63,7 @@ MediaPlayer::MediaPlayer()
     mAudioSessionId = AudioSystem::newAudioSessionId();
     AudioSystem::acquireAudioSessionId(mAudioSessionId);
     mSendLevel = 0;
+    mRetransmitEndpointValid = false;
 }
 
 MediaPlayer::~MediaPlayer()
@@ -95,6 +96,7 @@ void MediaPlayer::clear_l()
     mCurrentPosition = -1;
     mSeekPosition = -1;
     mVideoWidth = mVideoHeight = 0;
+    mRetransmitEndpointValid = false;
 }
 
 status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
@@ -146,7 +148,8 @@ status_t MediaPlayer::setDataSource(
         const sp<IMediaPlayerService>& service(getMediaPlayerService());
         if (service != 0) {
             sp<IMediaPlayer> 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);
@@ -162,7 +165,8 @@ status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length)
     const sp<IMediaPlayerService>& service(getMediaPlayerService());
     if (service != 0) {
         sp<IMediaPlayer> 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);
@@ -177,7 +181,8 @@ status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
     const sp<IMediaPlayerService>& service(getMediaPlayerService());
     if (service != 0) {
         sp<IMediaPlayer> 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);
@@ -471,6 +476,18 @@ status_t MediaPlayer::reset_l()
     return NO_ERROR;
 }
 
+status_t MediaPlayer::doSetRetransmitEndpoint(const sp<IMediaPlayer>& player) {
+    Mutex::Autolock _l(mLock);
+
+    if (player == NULL)
+        return UNKNOWN_ERROR;
+
+    if (mRetransmitEndpointValid)
+        return player->setRetransmitEndpoint(&mRetransmitEndpoint);
+
+    return OK;
+}
+
 status_t MediaPlayer::reset()
 {
     LOGV("reset");
@@ -599,6 +616,36 @@ status_t MediaPlayer::getParameter(int key, Parcel *reply)
     return INVALID_OPERATION;
 }
 
+status_t MediaPlayer::setRetransmitEndpoint(const char* addrString,
+                                            uint16_t port) {
+    LOGV("MediaPlayer::setRetransmitEndpoint(%s:%hu)",
+            addrString ? addrString : "(null)", port);
+
+    Mutex::Autolock _l(mLock);
+    if ((mPlayer == NULL) && (mCurrentState == MEDIA_PLAYER_IDLE)) {
+        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;
+    }
+
+    LOGV("setRetransmitEndpoint: after idle");
+    return INVALID_OPERATION;
+}
+
 void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
 {
     LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
index 5b1d6c7..3b05085 100644 (file)
@@ -492,6 +492,7 @@ MediaPlayerService::Client::Client(
     mStatus = NO_INIT;
     mAudioSessionId = audioSessionId;
     mUID = uid;
+    mRetransmitEndpointValid = false;
 
 #if CALLBACK_ANTAGONIZER
     LOGD("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) {
@@ -716,7 +713,12 @@ status_t MediaPlayerService::Client::setDataSource(
         close(fd);
         return mStatus;
     } else {
-        player_type playerType = getPlayerType(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.
+        player_type playerType = mRetransmitEndpointValid
+                               ? AAH_TX_PLAYER
+                               : getPlayerType(url);
         LOGV("player type = %d", playerType);
 
         // create the right type of player
@@ -732,6 +734,15 @@ status_t MediaPlayerService::Client::setDataSource(
         LOGV(" setDataSource");
         mStatus = p->setDataSource(url, headers);
         if (mStatus == NO_ERROR) {
+            // Set the re-transmission endpoint if one was chosen.
+            if (mRetransmitEndpointValid) {
+                mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+                if (mStatus != NO_ERROR) {
+                    LOGE("setRetransmitEndpoint error: %d", mStatus);
+                    return mStatus;
+                }
+            }
+
             mPlayer = p;
         } else {
             LOGE("  error: %d", mStatus);
@@ -766,7 +777,12 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
         LOGV("calculated length = %lld", length);
     }
 
-    player_type playerType = getPlayerType(fd, offset, 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 = mRetransmitEndpointValid
+                           ? AAH_TX_PLAYER
+                           : getPlayerType(fd, offset, length);
     LOGV("player type = %d", playerType);
 
     // create the right type of player
@@ -780,7 +796,18 @@ 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;
+    if (mStatus == NO_ERROR) {
+        // Set the re-transmission endpoint if one was chosen.
+        if (mRetransmitEndpointValid) {
+            mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+            if (mStatus != NO_ERROR) {
+                LOGE("setRetransmitEndpoint error: %d", mStatus);
+                return mStatus;
+            }
+        }
+
+        mPlayer = p;
+    }
 
     return mStatus;
 }
@@ -788,7 +815,14 @@ status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64
 status_t MediaPlayerService::Client::setDataSource(
         const sp<IStreamSource> &source) {
     // create the right type of player
-    sp<MediaPlayerBase> 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 = mRetransmitEndpointValid
+                           ? AAH_TX_PLAYER
+                           : NU_PLAYER;
+    LOGV("player type = %d", playerType);
+    sp<MediaPlayerBase> p = createPlayer(playerType);
 
     if (p == NULL) {
         return NO_INIT;
@@ -803,6 +837,15 @@ status_t MediaPlayerService::Client::setDataSource(
     mStatus = p->setDataSource(source);
 
     if (mStatus == OK) {
+        // Set the re-transmission endpoint if one was chosen.
+        if (mRetransmitEndpointValid) {
+            mStatus = p->setRetransmitEndpoint(&mRetransmitEndpoint);
+            if (mStatus != NO_ERROR) {
+                LOGE("setRetransmitEndpoint error: %d", mStatus);
+                return mStatus;
+            }
+        }
+
         mPlayer = p;
     }
 
@@ -1026,6 +1069,7 @@ status_t MediaPlayerService::Client::seekTo(int msec)
 status_t MediaPlayerService::Client::reset()
 {
     LOGV("[%d] reset", mConnId);
+    mRetransmitEndpointValid = false;
     sp<MediaPlayerBase> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->reset();
@@ -1100,6 +1144,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);
+        LOGV("[%d] setRetransmitEndpoint(%u.%u.%u.%u:%hu)", mConnId,
+                (a >> 24), (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a & 0xFF), p);
+    } else {
+        LOGV("[%d] setRetransmitEndpoint = <none>", mConnId);
+    }
+
+    sp<MediaPlayerBase> 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)
 {
index 04d9e28..25ed054 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef ANDROID_MEDIAPLAYERSERVICE_H
 #define ANDROID_MEDIAPLAYERSERVICE_H
 
+#include <arpa/inet.h>
+
 #include <utils/Log.h>
 #include <utils/threads.h>
 #include <utils/List.h>
@@ -271,6 +273,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<MediaPlayerBase>     createPlayer(player_type playerType);
 
@@ -333,6 +336,8 @@ private:
                     uid_t                       mUID;
                     sp<ANativeWindow>           mConnectedWindow;
                     sp<IBinder>                 mConnectedWindowBinder;
+                    struct sockaddr_in          mRetransmitEndpoint;
+                    bool                        mRetransmitEndpointValid;
 
         // Metadata filters.
         media::Metadata::Filter mMetadataAllow;  // protected by mLock