Switch the way we configure for MediaPlayer retransmission.

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
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index e905903..ed98dce 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -22,6 +22,10 @@
 #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 @@
     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 354f91d..74a265e 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -29,6 +29,10 @@
 #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 @@
     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 e6a0cc5..7cc1693 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -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 @@
             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 @@
             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 @@
     int                         mVideoHeight;
     int                         mAudioSessionId;
     float                       mSendLevel;
+    struct sockaddr_in          mRetransmitEndpoint;
+    bool                        mRetransmitEndpointValid;
 };
 
 }; // namespace android
diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp
index 6407074..6328115 100644
--- a/media/libaah_rtp/aah_tx_player.cpp
+++ b/media/libaah_rtp/aah_tx_player.cpp
@@ -149,14 +149,7 @@
         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::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 @@
     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 b45a661..6843f9b 100644
--- a/media/libaah_rtp/aah_tx_player.h
+++ b/media/libaah_rtp/aah_tx_player.h
@@ -63,16 +63,8 @@
                                     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;
 
diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp
index cbe5514..1dcb6e9 100644
--- a/media/libaah_rtp/aah_tx_sender.cpp
+++ b/media/libaah_rtp/aah_tx_sender.cpp
@@ -243,7 +243,7 @@
     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 @@
         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 9c1e6b7..36a9efe 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -15,6 +15,7 @@
 ** limitations under the License.
 */
 
+#include <arpa/inet.h>
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -55,6 +56,7 @@
     SET_VIDEO_SURFACETEXTURE,
     SET_PARAMETER,
     GET_PARAMETER,
+    SET_RETRANSMIT_ENDPOINT,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -291,6 +293,25 @@
         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 @@
             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 c2e1ddf..111962c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -63,6 +63,7 @@
     mAudioSessionId = AudioSystem::newAudioSessionId();
     AudioSystem::acquireAudioSessionId(mAudioSessionId);
     mSendLevel = 0;
+    mRetransmitEndpointValid = false;
 }
 
 MediaPlayer::~MediaPlayer()
@@ -95,6 +96,7 @@
     mCurrentPosition = -1;
     mSeekPosition = -1;
     mVideoWidth = mVideoHeight = 0;
+    mRetransmitEndpointValid = false;
 }
 
 status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
@@ -146,7 +148,8 @@
         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 @@
     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 @@
     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 @@
     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 @@
     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);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5b1d6c7..3b05085 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -492,6 +492,7 @@
     mStatus = NO_INIT;
     mAudioSessionId = audioSessionId;
     mUID = uid;
+    mRetransmitEndpointValid = false;
 
 #if CALLBACK_ANTAGONIZER
     LOGD("create Antagonizer");
@@ -602,10 +603,6 @@
         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 @@
         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 @@
         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 @@
         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 @@
 
     // 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(
         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 @@
     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::reset()
 {
     LOGV("[%d] reset", mConnId);
+    mRetransmitEndpointValid = false;
     sp<MediaPlayerBase> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->reset();
@@ -1100,6 +1144,36 @@
     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)
 {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 04d9e28..25ed054 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -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 @@
         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 @@
                     uid_t                       mUID;
                     sp<ANativeWindow>           mConnectedWindow;
                     sp<IBinder>                 mConnectedWindowBinder;
+                    struct sockaddr_in          mRetransmitEndpoint;
+                    bool                        mRetransmitEndpointValid;
 
         // Metadata filters.
         media::Metadata::Filter mMetadataAllow;  // protected by mLock