Merge "Remove hacks that worked around issues in OMX components several releases back."
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 6425886..39d58ab 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -23,6 +23,10 @@
 #include <utils/KeyedVector.h>
 #include <system/audio.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;
@@ -59,6 +63,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 23a3e49..f7491d8 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;
@@ -141,6 +145,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 d0b87c8..9cd5f9f 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>
@@ -204,6 +206,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();
@@ -212,6 +215,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;
@@ -234,6 +238,8 @@
     int                         mVideoHeight;
     int                         mAudioSessionId;
     float                       mSendLevel;
+    struct sockaddr_in          mRetransmitEndpoint;
+    bool                        mRetransmitEndpointValid;
 };
 
 }; // namespace android
diff --git a/media/libaah_rtp/aah_decoder_pump.cpp b/media/libaah_rtp/aah_decoder_pump.cpp
index 72fe43b..28b8c7b 100644
--- a/media/libaah_rtp/aah_decoder_pump.cpp
+++ b/media/libaah_rtp/aah_decoder_pump.cpp
@@ -159,8 +159,8 @@
 
                 res = renderer_->queueTimedBuffer(pcm_payload, ts);
                 if (res != OK) {
-                    ALOGE("Failed to queue %d byte audio track buffer with media"
-                          " PTS %lld. (res = %d)", decoded_amt, ts, res);
+                    ALOGE("Failed to queue %d byte audio track buffer with"
+                          " media PTS %lld. (res = %d)", decoded_amt, ts, res);
                 } else {
                     last_queued_pts_valid_ = true;
                     last_queued_pts_ = ts;
@@ -291,8 +291,8 @@
     // thread_status_.
     thread_status_ = decoder_->start(format_.get());
     if (OK != thread_status_) {
-        ALOGE("AAH_DecoderPump's work thread failed to start decoder (res = %d)",
-                thread_status_);
+        ALOGE("AAH_DecoderPump's work thread failed to start decoder"
+              " (res = %d)", thread_status_);
         return NULL;
     }
 
diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h
index 7a1b6e3..ba5617e 100644
--- a/media/libaah_rtp/aah_rx_player.h
+++ b/media/libaah_rtp/aah_rx_player.h
@@ -217,14 +217,15 @@
         status_t getStatus() const { return status_; }
 
       protected:
-        virtual ~Substream() {
-            shutdown();
-        }
+        virtual ~Substream();
 
       private:
         void                cleanupDecoder();
         bool                shouldAbort(const char* log_tag);
         void                processCompletedBuffer();
+        bool                setupSubstreamMeta();
+        bool                setupMP3SubstreamMeta();
+        bool                setupAACSubstreamMeta();
         bool                setupSubstreamType(uint8_t substream_type,
                                                uint8_t codec_type);
 
@@ -235,12 +236,16 @@
         bool                substream_details_known_;
         uint8_t             substream_type_;
         uint8_t             codec_type_;
+        const char*         codec_mime_type_;
         sp<MetaData>        substream_meta_;
 
         MediaBuffer*        buffer_in_progress_;
         uint32_t            expected_buffer_size_;
         uint32_t            buffer_filled_;
 
+        Vector<uint8_t>     aux_data_in_progress_;
+        uint32_t            aux_data_expected_size_;
+
         sp<AAH_DecoderPump> decoder_;
 
         static int64_t      kAboutToUnderflowThreshold;
diff --git a/media/libaah_rtp/aah_rx_player_core.cpp b/media/libaah_rtp/aah_rx_player_core.cpp
index d2b3386..d6b31fd 100644
--- a/media/libaah_rtp/aah_rx_player_core.cpp
+++ b/media/libaah_rtp/aah_rx_player_core.cpp
@@ -431,8 +431,8 @@
         // Looks like a NAK packet; make sure its long enough.
 
         if (amt < static_cast<ssize_t>(sizeof(RetransRequest))) {
-            ALOGV("Dropping packet, too short to contain NAK payload (%u bytes)",
-                  static_cast<uint32_t>(amt));
+            ALOGV("Dropping packet, too short to contain NAK payload"
+                  " (%u bytes)", static_cast<uint32_t>(amt));
             goto drop_packet;
         }
 
@@ -441,7 +441,8 @@
         gap.start_seq_ = ntohs(rtr->start_seq_);
         gap.end_seq_   = ntohs(rtr->end_seq_);
 
-        ALOGV("Process NAK for gap at [%hu, %hu]", gap.start_seq_, gap.end_seq_);
+        ALOGV("Process NAK for gap at [%hu, %hu]",
+                gap.start_seq_, gap.end_seq_);
         ring_buffer_.processNAK(&gap);
 
         return true;
@@ -770,7 +771,8 @@
             ALOGE("Error when sending retransmit request (%d)", errno);
         } else {
             ALOGV("%s request for range [%hu, %hu] sent",
-                  (kGS_FastStartGap == gap_status) ? "Fast Start" : "Retransmit",
+                  (kGS_FastStartGap == gap_status) ? "Fast Start"
+                                                   : "Retransmit",
                   gap.start_seq_, gap.end_seq_);
         }
 
diff --git a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
index 0d8b31f..779405e 100644
--- a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
+++ b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
@@ -116,8 +116,8 @@
 
     // Check for overflow first.
     if ((!(norm_seq & 0x8000)) && (norm_seq >= (capacity_ - 1))) {
-        ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu], seq = %hu",
-              capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq);
+        ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu],"
+              " seq = %hu", capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq);
         PacketBuffer::destroy(buf);
         return false;
     }
diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp
index 1e4c784..18b0e2b 100644
--- a/media/libaah_rtp/aah_rx_player_substream.cpp
+++ b/media/libaah_rtp/aah_rx_player_substream.cpp
@@ -27,6 +27,11 @@
 #include <media/stagefright/Utils.h>
 
 #include "aah_rx_player.h"
+#include "aah_tx_packet.h"
+
+inline uint32_t min(uint32_t a, uint32_t b) {
+    return (a < b ? a : b);
+}
 
 namespace android {
 
@@ -38,6 +43,7 @@
     substream_details_known_ = false;
     buffer_in_progress_ = NULL;
     status_ = OK;
+    codec_mime_type_ = "";
 
     decoder_ = new AAH_DecoderPump(omx);
     if (decoder_ == NULL) {
@@ -52,6 +58,9 @@
     cleanupBufferInProgress();
 }
 
+AAH_RXPlayer::Substream::~Substream() {
+    shutdown();
+}
 
 void AAH_RXPlayer::Substream::shutdown() {
     substream_meta_ = NULL;
@@ -69,6 +78,9 @@
     expected_buffer_size_ = 0;
     buffer_filled_ = 0;
     waiting_for_rap_ = true;
+
+    aux_data_in_progress_.clear();
+    aux_data_expected_size_ = 0;
 }
 
 void AAH_RXPlayer::Substream::cleanupDecoder() {
@@ -129,16 +141,16 @@
     // one that does not conflict with any previously received substream type.
     uint8_t header_type = (buf[1] >> 4) & 0xF;
     switch (header_type) {
-        case 0x01:
+        case TRTPPacket::kHeaderTypeAudio:
             // Audio, yay!  Just break.  We understand audio payloads.
             break;
-        case 0x02:
+        case TRTPPacket::kHeaderTypeVideo:
             ALOGV("RXed packet with unhandled TRTP header type (Video).");
             return;
-        case 0x03:
+        case TRTPPacket::kHeaderTypeSubpicture:
             ALOGV("RXed packet with unhandled TRTP header type (Subpicture).");
             return;
-        case 0x04:
+        case TRTPPacket::kHeaderTypeControl:
             ALOGV("RXed packet with unhandled TRTP header type (Control).");
             return;
         default:
@@ -148,15 +160,15 @@
     }
 
     if (substream_details_known_ && (header_type != substream_type_)) {
-        ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does not"
-              " match previously received header type (%u)",
+        ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does"
+              " not match previously received header type (%u)",
               ssrc_, header_type, substream_type_);
         return;
     }
 
     // Check the flags to see if there is another 32 bits of timestamp present.
     uint32_t trtp_header_len = 6;
-    bool ts_valid = buf[1] & 0x1;
+    bool ts_valid = buf[1] & TRTPPacket::kFlag_TSValid;
     if (ts_valid) {
         min_length += 4;
         trtp_header_len += 4;
@@ -168,11 +180,7 @@
     }
 
     // Extract the TRTP length field and sanity check it.
-    uint32_t trtp_len;
-    trtp_len = (static_cast<uint32_t>(buf[2]) << 24) |
-        (static_cast<uint32_t>(buf[3]) << 16) |
-        (static_cast<uint32_t>(buf[4]) <<  8) |
-        static_cast<uint32_t>(buf[5]);
+    uint32_t trtp_len = U32_AT(buf + 2);
     if (trtp_len < min_length) {
         ALOGV("TRTP length (%u) is too short to be valid.  Must be at least %u"
               " bytes.", trtp_len, min_length);
@@ -183,17 +191,14 @@
     int64_t ts = 0;
     uint32_t parse_offset = 6;
     if (ts_valid) {
-        ts = (static_cast<int64_t>(buf[parse_offset    ]) << 56) |
-            (static_cast<int64_t>(buf[parse_offset + 1]) << 48) |
-            (static_cast<int64_t>(buf[parse_offset + 2]) << 40) |
-            (static_cast<int64_t>(buf[parse_offset + 3]) << 32);
-        ts |= ts_lower;
+        uint32_t ts_upper = U32_AT(buf + parse_offset);
         parse_offset += 4;
+        ts = (static_cast<int64_t>(ts_upper) << 32) | ts_lower;
     }
 
     // Check the flags to see if there is another 24 bytes of timestamp
     // transformation present.
-    if (buf[1] & 0x2) {
+    if (buf[1] & TRTPPacket::kFlag_TSTransformPresent) {
         min_length += 24;
         parse_offset += 24;
         trtp_header_len += 24;
@@ -219,8 +224,8 @@
 
     if (amt < min_length) {
         ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
-              " entire TRTP header.  TRTP does not currently support fragmenting"
-              " TRTP headers across RTP payloads", amt);
+              " entire TRTP header.  TRTP does not currently support"
+              " fragmenting TRTP headers across RTP payloads", amt);
         return;
     }
 
@@ -238,16 +243,42 @@
         decoder_->setRenderVolume(volume);
     }
 
-    // TODO : move all of the constant flag and offset definitions for TRTP up
-    // into some sort of common header file.
-    if (waiting_for_rap_ && !(flags & 0x08)) {
+    if (waiting_for_rap_ && !(flags & TRTPAudioPacket::kFlag_RandomAccessPoint)) {
         ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP.");
         return;
     }
 
-    if (flags & 0x10) {
-        ALOGV("Dropping TRTP Audio Payload with aux codec data present (only"
-              " handle MP3 right now, and it has no aux data)");
+    // Check for the presence of codec aux data.
+    if (flags & TRTPAudioPacket::kFlag_AuxLengthPresent) {
+        min_length += 4;
+        trtp_header_len += 4;
+
+        if (trtp_len < min_length) {
+            ALOGV("TRTP length (%u) is too short to be a valid audio payload.  "
+                  "Must be at least %u bytes.", trtp_len, min_length);
+            return;
+        }
+
+        if (amt < min_length) {
+            ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
+                  " entire TRTP header.  TRTP does not currently support"
+                  " fragmenting TRTP headers across RTP payloads", amt);
+            return;
+        }
+
+        aux_data_expected_size_ = U32_AT(buf + parse_offset);
+        aux_data_in_progress_.clear();
+        if (aux_data_in_progress_.capacity() < aux_data_expected_size_) {
+            aux_data_in_progress_.setCapacity(aux_data_expected_size_);
+        }
+    } else {
+        aux_data_expected_size_ = 0;
+    }
+
+    if ((aux_data_expected_size_ + trtp_header_len) > trtp_len) {
+        ALOGV("Expected codec aux data length (%u) and TRTP header overhead"
+              " (%u) too large for total TRTP payload length (%u).",
+             aux_data_expected_size_, trtp_header_len, trtp_len);
         return;
     }
 
@@ -255,7 +286,9 @@
     // the buffer in progress and pack as much payload as we can into it.  If
     // the payload is finished once we are done, go ahead and send the payload
     // to the decoder.
-    expected_buffer_size_ = trtp_len - trtp_header_len;
+    expected_buffer_size_ = trtp_len
+                          - trtp_header_len
+                          - aux_data_expected_size_;
     if (!expected_buffer_size_) {
         ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
         return;
@@ -263,9 +296,10 @@
 
     CHECK(amt >= trtp_header_len);
     uint32_t todo = amt - trtp_header_len;
-    if (expected_buffer_size_ < todo) {
+    if ((expected_buffer_size_ + aux_data_expected_size_) < todo) {
         ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
-              " dropping payload.", todo, expected_buffer_size_);
+              " dropping payload.", todo,
+              expected_buffer_size_ + aux_data_expected_size_);
         return;
     }
 
@@ -287,18 +321,32 @@
         return;
     }
 
-    // TODO : set this based on the codec type indicated in the TRTP stream.
-    // Right now, we only support MP3, so the choice is obvious.
-    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+    meta->setCString(kKeyMIMEType, codec_mime_type_);
     if (ts_valid) {
         meta->setInt64(kKeyTime, ts);
     }
 
-    if (amt > 0) {
+    // Skip over the header we have already extracted.
+    amt -= trtp_header_len;
+    buf += trtp_header_len;
+
+    // Extract as much of the expected aux data as we can.
+    todo = min(aux_data_expected_size_, amt);
+    if (todo) {
+        aux_data_in_progress_.appendArray(buf, todo);
+        buf += todo;
+        amt -= todo;
+    }
+
+    // Extract as much of the expected payload as we can.
+    todo = min(expected_buffer_size_, amt);
+    if (todo > 0) {
         uint8_t* tgt =
             reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
-        memcpy(tgt + buffer_filled_, buf + trtp_header_len, todo);
-        buffer_filled_ += amt;
+        memcpy(tgt, buf, todo);
+        buffer_filled_ = amt;
+        buf += todo;
+        amt -= todo;
     }
 
     if (buffer_filled_ >= expected_buffer_size_) {
@@ -318,6 +366,18 @@
         return;
     }
 
+    CHECK(aux_data_in_progress_.size() <= aux_data_expected_size_);
+    uint32_t aux_left = aux_data_expected_size_ - aux_data_in_progress_.size();
+    if (aux_left) {
+        uint32_t todo = min(aux_left, amt);
+        aux_data_in_progress_.appendArray(buf, todo);
+        amt -= todo;
+        buf += todo;
+
+        if (!amt)
+            return;
+    }
+
     CHECK(buffer_filled_ < expected_buffer_size_);
     uint32_t buffer_left = expected_buffer_size_ - buffer_filled_;
     if (amt > buffer_left) {
@@ -340,10 +400,6 @@
 }
 
 void AAH_RXPlayer::Substream::processCompletedBuffer() {
-    const uint8_t* buffer_data = NULL;
-    int sample_rate;
-    int channel_count;
-    size_t frame_size;
     status_t res;
 
     CHECK(NULL != buffer_in_progress_);
@@ -353,56 +409,10 @@
         goto bailout;
     }
 
-    buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
-    if (buffer_in_progress_->size() < 4) {
-        ALOGV("MP3 payload too short to contain header, dropping payload.");
+    // Make sure our metadata used to initialize the decoder has been properly
+    // set up.
+    if (!setupSubstreamMeta())
         goto bailout;
-    }
-
-    // Extract the channel count and the sample rate from the MP3 header.  The
-    // stagefright MP3 requires that these be delivered before decoing can
-    // begin.
-    if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
-                               &frame_size,
-                               &sample_rate,
-                               &channel_count,
-                               NULL,
-                               NULL)) {
-        ALOGV("Failed to parse MP3 header in payload, droping payload.");
-        goto bailout;
-    }
-
-
-    // Make sure that our substream metadata is set up properly.  If there has
-    // been a format change, be sure to reset the underlying decoder.  In
-    // stagefright, it seems like the only way to do this is to destroy and
-    // recreate the decoder.
-    if (substream_meta_ == NULL) {
-        substream_meta_ = new MetaData();
-
-        if (substream_meta_ == NULL) {
-            ALOGE("Failed to allocate MetaData structure for substream");
-            goto bailout;
-        }
-
-        substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
-        substream_meta_->setInt32  (kKeyChannelCount, channel_count);
-        substream_meta_->setInt32  (kKeySampleRate,   sample_rate);
-    } else {
-        int32_t prev_sample_rate;
-        int32_t prev_channel_count;
-        substream_meta_->findInt32(kKeySampleRate,   &prev_sample_rate);
-        substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
-
-        if ((prev_channel_count != channel_count) ||
-            (prev_sample_rate   != sample_rate)) {
-            ALOGW("Format change detected, forcing decoder reset.");
-            cleanupDecoder();
-
-            substream_meta_->setInt32(kKeyChannelCount, channel_count);
-            substream_meta_->setInt32(kKeySampleRate,   sample_rate);
-        }
-    }
 
     // If our decoder has not be set up, do so now.
     res = decoder_->init(substream_meta_);
@@ -418,7 +428,7 @@
 
     if (res != OK) {
         ALOGD("Failed to queue payload for decode, resetting decoder pump!"
-              " (res = %d)", res);
+             " (res = %d)", res);
         status_ = res;
         cleanupDecoder();
         cleanupBufferInProgress();
@@ -454,6 +464,167 @@
     cleanupBufferInProgress();
 }
 
+bool AAH_RXPlayer::Substream::setupSubstreamMeta() {
+    switch (codec_type_) {
+        case TRTPAudioPacket::kCodecMPEG1Audio:
+            codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_MPEG;
+            return setupMP3SubstreamMeta();
+
+        case TRTPAudioPacket::kCodecAACAudio:
+            codec_mime_type_ = MEDIA_MIMETYPE_AUDIO_AAC;
+            return setupAACSubstreamMeta();
+
+        default:
+            ALOGV("Failed to setup substream metadata for unsupported codec"
+                  " type (%u)", codec_type_);
+            break;
+    }
+
+    return false;
+}
+
+bool AAH_RXPlayer::Substream::setupMP3SubstreamMeta() {
+    const uint8_t* buffer_data = NULL;
+    int sample_rate;
+    int channel_count;
+    size_t frame_size;
+    status_t res;
+
+    buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
+    if (buffer_in_progress_->size() < 4) {
+        ALOGV("MP3 payload too short to contain header, dropping payload.");
+        return false;
+    }
+
+    // Extract the channel count and the sample rate from the MP3 header.  The
+    // stagefright MP3 requires that these be delivered before decoing can
+    // begin.
+    if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
+                               &frame_size,
+                               &sample_rate,
+                               &channel_count,
+                               NULL,
+                               NULL)) {
+        ALOGV("Failed to parse MP3 header in payload, droping payload.");
+        return false;
+    }
+
+
+    // Make sure that our substream metadata is set up properly.  If there has
+    // been a format change, be sure to reset the underlying decoder.  In
+    // stagefright, it seems like the only way to do this is to destroy and
+    // recreate the decoder.
+    if (substream_meta_ == NULL) {
+        substream_meta_ = new MetaData();
+
+        if (substream_meta_ == NULL) {
+            ALOGE("Failed to allocate MetaData structure for MP3 substream");
+            return false;
+        }
+
+        substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+        substream_meta_->setInt32  (kKeyChannelCount, channel_count);
+        substream_meta_->setInt32  (kKeySampleRate,   sample_rate);
+    } else {
+        int32_t prev_sample_rate;
+        int32_t prev_channel_count;
+        substream_meta_->findInt32(kKeySampleRate,   &prev_sample_rate);
+        substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
+
+        if ((prev_channel_count != channel_count) ||
+            (prev_sample_rate   != sample_rate)) {
+            ALOGW("MP3 format change detected, forcing decoder reset.");
+            cleanupDecoder();
+
+            substream_meta_->setInt32(kKeyChannelCount, channel_count);
+            substream_meta_->setInt32(kKeySampleRate,   sample_rate);
+        }
+    }
+
+    return true;
+}
+
+bool AAH_RXPlayer::Substream::setupAACSubstreamMeta() {
+    int32_t sample_rate, channel_cnt;
+    static const size_t overhead = sizeof(sample_rate)
+                                 + sizeof(channel_cnt);
+
+    if (aux_data_in_progress_.size() < overhead) {
+        ALOGE("Not enough aux data (%u) to initialize AAC substream decoder",
+                aux_data_in_progress_.size());
+        return false;
+    }
+
+    const uint8_t* aux_data = aux_data_in_progress_.array();
+    size_t aux_data_size = aux_data_in_progress_.size();
+    sample_rate = U32_AT(aux_data);
+    channel_cnt = U32_AT(aux_data + sizeof(sample_rate));
+
+    const uint8_t* esds_data = NULL;
+    size_t esds_data_size = 0;
+    if (aux_data_size > overhead) {
+        esds_data = aux_data + overhead;
+        esds_data_size = aux_data_size - overhead;
+    }
+
+    // Do we already have metadata?  If so, has it changed at all?  If not, then
+    // there should be nothing else to do.  Otherwise, release our old stream
+    // metadata and make new metadata.
+    if (substream_meta_ != NULL) {
+        uint32_t type;
+        const void* data;
+        size_t size;
+        int32_t prev_sample_rate;
+        int32_t prev_channel_count;
+        bool res;
+
+        res = substream_meta_->findInt32(kKeySampleRate,   &prev_sample_rate);
+        CHECK(res);
+        res = substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
+        CHECK(res);
+
+        // If nothing has changed about the codec aux data (esds, sample rate,
+        // channel count), then we can just do nothing and get out.  Otherwise,
+        // we will need to reset the decoder and make a new metadata object to
+        // deal with the format change.
+        bool hasData = (esds_data != NULL);
+        bool hadData = substream_meta_->findData(kKeyESDS, &type, &data, &size);
+        bool esds_change = (hadData != hasData);
+
+        if (!esds_change && hasData)
+            esds_change = ((size != esds_data_size) ||
+                           memcmp(data, esds_data, size));
+
+        if (!esds_change &&
+            (prev_sample_rate   == sample_rate) &&
+            (prev_channel_count == channel_cnt)) {
+            return true;  // no change, just get out.
+        }
+
+        ALOGW("AAC format change detected, forcing decoder reset.");
+        cleanupDecoder();
+        substream_meta_ = NULL;
+    }
+
+    CHECK(substream_meta_ == NULL);
+
+    substream_meta_ = new MetaData();
+    if (substream_meta_ == NULL) {
+        ALOGE("Failed to allocate MetaData structure for AAC substream");
+        return false;
+    }
+
+    substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+    substream_meta_->setInt32  (kKeySampleRate,   sample_rate);
+    substream_meta_->setInt32  (kKeyChannelCount, channel_cnt);
+
+    if (esds_data) {
+        substream_meta_->setData(kKeyESDS, kTypeESDS,
+                                 esds_data, esds_data_size);
+    }
+
+    return true;
+}
 
 void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
     if (decoder_ != NULL) {
@@ -471,26 +642,34 @@
 
 bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
                                                  uint8_t codec_type) {
-    // Sanity check the codec type.  Right now we only support MP3.  Also check
-    // for conflicts with previously delivered codec types.
-    if (substream_details_known_ && (codec_type != codec_type_)) {
-        ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does not"
-              " match previously received codec type (%u)",
-              ssrc_, codec_type, codec_type_);
-        return false;
+    // Sanity check the codec type.  Right now we only support MP3 and AAC.
+    // Also check for conflicts with previously delivered codec types.
+    if (substream_details_known_) {
+        if (codec_type != codec_type_) {
+            ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does"
+                  " not match previously received codec type (%u)",
+                 ssrc_, codec_type, codec_type_);
+            return false;
+        }
+
+        return true;
     }
 
-    if (codec_type != 0x03) {
-        ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported codec"
-              " type (%u)", ssrc_, codec_type);
-        return false;
+    switch (codec_type) {
+        // MP3 and AAC are all we support right now.
+        case TRTPAudioPacket::kCodecMPEG1Audio:
+        case TRTPAudioPacket::kCodecAACAudio:
+            break;
+
+        default:
+            ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported"
+                  " codec type (%u)", ssrc_, codec_type);
+            return false;
     }
 
-    if (!substream_details_known_) {
-        substream_type_ = substream_type;
-        codec_type_ = codec_type;
-        substream_details_known_ = true;
-    }
+    substream_type_ = substream_type;
+    codec_type_ = codec_type;
+    substream_details_known_ = true;
 
     return true;
 }
diff --git a/media/libaah_rtp/aah_tx_packet.cpp b/media/libaah_rtp/aah_tx_packet.cpp
index 3f6e0e9..4cd6e47 100644
--- a/media/libaah_rtp/aah_tx_packet.cpp
+++ b/media/libaah_rtp/aah_tx_packet.cpp
@@ -142,12 +142,18 @@
     mVolume = val;
 }
 
-void TRTPAudioPacket::setAccessUnitData(void* data, int len) {
+void TRTPAudioPacket::setAccessUnitData(const void* data, size_t len) {
     CHECK(!mIsPacked);
     mAccessUnitData = data;
     mAccessUnitLen = len;
 }
 
+void TRTPAudioPacket::setAuxData(const void* data, size_t len) {
+    CHECK(!mIsPacked);
+    mAuxData = data;
+    mAuxDataLen = len;
+}
+
 /*** TRTP control packet properties ***/
 
 void TRTPControlPacket::setCommandID(TRTPCommandID val) {
@@ -232,6 +238,7 @@
     }
 
     int packetLen = kRTPHeaderLen +
+                    mAuxDataLen +
                     mAccessUnitLen +
                     TRTPHeaderLen();
 
@@ -249,16 +256,24 @@
     mPacketLen = packetLen;
 
     uint8_t* cur = mPacket;
+    bool hasAux = mAuxData && mAuxDataLen;
+    uint8_t flags = (static_cast<int>(hasAux) << 4) |
+                    (static_cast<int>(mRandomAccessPoint) << 3) |
+                    (static_cast<int>(mDropable) << 2) |
+                    (static_cast<int>(mDiscontinuity) << 1) |
+                    (static_cast<int>(mEndOfStream));
 
     writeTRTPHeader(cur, true, packetLen);
     writeU8(cur, mCodecType);
-    writeU8(cur,
-            (static_cast<int>(mRandomAccessPoint) << 3) |
-            (static_cast<int>(mDropable) << 2) |
-            (static_cast<int>(mDiscontinuity) << 1) |
-            (static_cast<int>(mEndOfStream)));
+    writeU8(cur, flags);
     writeU8(cur, mVolume);
 
+    if (hasAux) {
+        writeU32(cur, mAuxDataLen);
+        memcpy(cur, mAuxData, mAuxDataLen);
+        cur += mAuxDataLen;
+    }
+
     memcpy(cur, mAccessUnitData, mAccessUnitLen);
 
     mIsPacked = true;
@@ -293,12 +308,10 @@
     }
 
 
-    // TODO : properly compute aux data length.  Currently, nothing
-    // uses aux data, so its length is always 0.
-    int auxDataLength = 0;
+    int auxDataLenField = (NULL != mAuxData) ? sizeof(uint32_t) : 0;
     return TRTPPacket::TRTPHeaderLen() +
            3 +
-           auxDataLength +
+           auxDataLenField +
            pcmParamLength;
 }
 
diff --git a/media/libaah_rtp/aah_tx_packet.h b/media/libaah_rtp/aah_tx_packet.h
index 833803e..7f78ea0 100644
--- a/media/libaah_rtp/aah_tx_packet.h
+++ b/media/libaah_rtp/aah_tx_packet.h
@@ -25,7 +25,7 @@
 namespace android {
 
 class TRTPPacket : public RefBase {
-  protected:
+  public:
     enum TRTPHeaderType {
         kHeaderTypeAudio = 1,
         kHeaderTypeVideo = 2,
@@ -33,6 +33,12 @@
         kHeaderTypeControl = 4,
     };
 
+    enum TRTPPayloadFlags {
+        kFlag_TSTransformPresent = 0x02,
+        kFlag_TSValid = 0x01,
+    };
+
+  protected:
     TRTPPacket(TRTPHeaderType headerType)
         : mIsPacked(false)
         , mVersion(2)
@@ -121,6 +127,14 @@
 
 class TRTPAudioPacket : public TRTPPacket {
   public:
+    enum AudioPayloadFlags {
+        kFlag_AuxLengthPresent = 0x10,
+        kFlag_RandomAccessPoint = 0x08,
+        kFlag_Dropable = 0x04,
+        kFlag_Discontinuity = 0x02,
+        kFlag_EndOfStream = 0x01,
+    };
+
     TRTPAudioPacket()
         : TRTPPacket(kHeaderTypeAudio)
         , mCodecType(kCodecInvalid)
@@ -129,13 +143,17 @@
         , mDiscontinuity(false)
         , mEndOfStream(false)
         , mVolume(0)
-        , mAccessUnitData(NULL) { }
+        , mAccessUnitData(NULL)
+        , mAccessUnitLen(0)
+        , mAuxData(NULL)
+        , mAuxDataLen(0) { }
 
     enum TRTPAudioCodecType {
         kCodecInvalid = 0,
         kCodecPCMBigEndian = 1,
         kCodecPCMLittleEndian = 2,
         kCodecMPEG1Audio = 3,
+        kCodecAACAudio = 4,
     };
 
     void setCodecType(TRTPAudioCodecType val);
@@ -144,7 +162,8 @@
     void setDiscontinuity(bool val);
     void setEndOfStream(bool val);
     void setVolume(uint8_t val);
-    void setAccessUnitData(void* data, int len);
+    void setAccessUnitData(const void* data, size_t len);
+    void setAuxData(const void* data, size_t len);
 
     virtual bool pack();
 
@@ -158,8 +177,11 @@
     bool mDiscontinuity;
     bool mEndOfStream;
     uint8_t mVolume;
-    void* mAccessUnitData;
-    int mAccessUnitLen;
+
+    const void* mAccessUnitData;
+    size_t mAccessUnitLen;
+    const void* mAuxData;
+    size_t mAuxDataLen;
 
     DISALLOW_EVIL_CONSTRUCTORS(TRTPAudioPacket);
 };
diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp
index a79a989..974805b 100644
--- a/media/libaah_rtp/aah_tx_player.cpp
+++ b/media/libaah_rtp/aah_tx_player.cpp
@@ -28,6 +28,7 @@
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <utils/Timers.h>
 
@@ -98,6 +99,8 @@
     mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio);
     mPumpAudioEventPending = false;
 
+    mAudioCodecData = NULL;
+
     reset_l();
 }
 
@@ -146,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;
@@ -398,7 +394,76 @@
         }
     }
 
-    mAudioSource->getFormat()->findInt64(kKeyDuration, &mDurationUs);
+    mAudioFormat = mAudioSource->getFormat();
+    if (!mAudioFormat->findInt64(kKeyDuration, &mDurationUs))
+        mDurationUs = 1;
+
+    const char* mime_type = NULL;
+    if (!mAudioFormat->findCString(kKeyMIMEType, &mime_type)) {
+        ALOGE("Failed to find audio substream MIME type during prepare.");
+        abortPrepare(BAD_VALUE);
+        return;
+    }
+
+    if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_MPEG)) {
+        mAudioCodec = TRTPAudioPacket::kCodecMPEG1Audio;
+    } else
+    if (!strcmp(mime_type, MEDIA_MIMETYPE_AUDIO_AAC)) {
+        mAudioCodec = TRTPAudioPacket::kCodecAACAudio;
+
+        uint32_t type;
+        int32_t  sample_rate;
+        int32_t  channel_count;
+        const void* esds_data;
+        size_t esds_len;
+
+        if (!mAudioFormat->findInt32(kKeySampleRate, &sample_rate)) {
+            ALOGE("Failed to find sample rate for AAC substream.");
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        if (!mAudioFormat->findInt32(kKeyChannelCount, &channel_count)) {
+            ALOGE("Failed to find channel count for AAC substream.");
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        if (!mAudioFormat->findData(kKeyESDS, &type, &esds_data, &esds_len)) {
+            ALOGE("Failed to find codec init data for AAC substream.");
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        CHECK(NULL == mAudioCodecData);
+        mAudioCodecDataSize = esds_len
+                            + sizeof(sample_rate)
+                            + sizeof(channel_count);
+        mAudioCodecData = new uint8_t[mAudioCodecDataSize];
+        if (NULL == mAudioCodecData) {
+            ALOGE("Failed to allocate %u bytes for AAC substream codec aux"
+                  " data.", mAudioCodecDataSize);
+            mAudioCodecDataSize = 0;
+            abortPrepare(BAD_VALUE);
+            return;
+        }
+
+        uint8_t* tmp = mAudioCodecData;
+        tmp[0] = static_cast<uint8_t>((sample_rate   >> 24) & 0xFF);
+        tmp[1] = static_cast<uint8_t>((sample_rate   >> 16) & 0xFF);
+        tmp[2] = static_cast<uint8_t>((sample_rate   >>  8) & 0xFF);
+        tmp[3] = static_cast<uint8_t>((sample_rate        ) & 0xFF);
+        tmp[4] = static_cast<uint8_t>((channel_count >> 24) & 0xFF);
+        tmp[5] = static_cast<uint8_t>((channel_count >> 16) & 0xFF);
+        tmp[6] = static_cast<uint8_t>((channel_count >>  8) & 0xFF);
+        tmp[7] = static_cast<uint8_t>((channel_count      ) & 0xFF);
+
+        memcpy(tmp + 8, esds_data, esds_len);
+    } else {
+        ALOGE("Unsupported MIME type \"%s\" in audio substream", mime_type);
+        abortPrepare(BAD_VALUE);
+        return;
+    }
 
     status_t err = mAudioSource->start();
     if (err != OK) {
@@ -666,6 +731,11 @@
         mAudioSource->stop();
     }
     mAudioSource.clear();
+    mAudioCodec = TRTPAudioPacket::kCodecInvalid;
+    mAudioFormat = NULL;
+    delete[] mAudioCodecData;
+    mAudioCodecData = NULL;
+    mAudioCodecDataSize = 0;
 
     mFlags = 0;
     mExtractorFlags = 0;
@@ -717,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,
@@ -812,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);
 }
@@ -1078,14 +1106,24 @@
         packet->setPTS(mediaTimeUs);
         packet->setSubstreamID(1);
 
-        packet->setCodecType(TRTPAudioPacket::kCodecMPEG1Audio);
+        packet->setCodecType(mAudioCodec);
         packet->setVolume(mTRTPVolume);
         // TODO : introduce a throttle for this so we can control the
         // frequency with which transforms get sent.
         packet->setClockTransform(mCurrentClockTransform);
         packet->setAccessUnitData(data, mediaBuffer->range_length());
+
+        // TODO : while its pretty much universally true that audio ES payloads
+        // are all RAPs across all codecs, it might be a good idea to throttle
+        // the frequency with which we send codec out of band data to the RXers.
+        // If/when we do, we need to flag only those payloads which have
+        // required out of band data attached to them as RAPs.
         packet->setRandomAccessPoint(true);
 
+        if (mAudioCodecData && mAudioCodecDataSize) {
+            packet->setAuxData(mAudioCodecData, mAudioCodecDataSize);
+        }
+
         queuePacketToSender_l(packet);
         mediaBuffer->release();
 
diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h
index 64cf5dc..2e4b1f7 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(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;
 
@@ -153,6 +145,11 @@
     sp<NuCachedSource2> mCachedSource;
 
     sp<MediaSource> mAudioSource;
+    TRTPAudioPacket::TRTPAudioCodecType mAudioCodec;
+    sp<MetaData> mAudioFormat;
+    uint8_t* mAudioCodecData;
+    size_t mAudioCodecDataSize;
+
     int64_t mDurationUs;
     int64_t mBitrate;
 
diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp
index d991ea7..08e32d2 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(),
@@ -283,7 +283,8 @@
     // remove the state for any endpoints that are no longer in use
     for (size_t i = 0; i < endpointsToRemove.size(); i++) {
         Endpoint& e = endpointsToRemove.editItemAt(i);
-        ALOGD("*** %s removing endpoint addr=%08x", __PRETTY_FUNCTION__, e.addr);
+        ALOGD("*** %s removing endpoint addr=%08x",
+                __PRETTY_FUNCTION__, e.addr);
         size_t index = mEndpointMap.indexOfKey(e);
         delete mEndpointMap.valueAt(index);
         mEndpointMap.removeItemsAt(index);
@@ -411,7 +412,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 86d65db..c47fa41 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>
 
@@ -53,6 +54,7 @@
     SET_VIDEO_SURFACETEXTURE,
     SET_PARAMETER,
     GET_PARAMETER,
+    SET_RETRANSMIT_ENDPOINT,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -289,6 +291,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");
@@ -457,6 +478,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 9d45907..4ff1862 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -61,6 +61,7 @@
     mAudioSessionId = AudioSystem::newAudioSessionId();
     AudioSystem::acquireAudioSessionId(mAudioSessionId);
     mSendLevel = 0;
+    mRetransmitEndpointValid = false;
 }
 
 MediaPlayer::~MediaPlayer()
@@ -93,6 +94,7 @@
     mCurrentPosition = -1;
     mSeekPosition = -1;
     mVideoWidth = mVideoHeight = 0;
+    mRetransmitEndpointValid = false;
 }
 
 status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener)
@@ -144,7 +146,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);
@@ -160,7 +163,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);
@@ -175,7 +179,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);
@@ -469,6 +474,20 @@
     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()
 {
     ALOGV("reset");
@@ -597,6 +616,34 @@
     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 764eddc..1e2abf0 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
     ALOGD("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) {
@@ -621,6 +618,44 @@
     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<IStreamSource> &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<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
         notify_callback_f notifyFunc)
 {
@@ -686,6 +721,49 @@
     return p;
 }
 
+sp<MediaPlayerBase> MediaPlayerService::Client::setDataSource_pre(
+        player_type playerType)
+{
+    ALOGV("player type = %d", playerType);
+
+    // create the right type of player
+    sp<MediaPlayerBase> p = createPlayer(playerType);
+    if (p == NULL) {
+        return p;
+    }
+
+    if (!p->hardwareOutput()) {
+        mAudioOutput = new AudioOutput(mAudioSessionId);
+        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
+    }
+
+    return p;
+}
+
+void MediaPlayerService::Client::setDataSource_post(
+        const sp<MediaPlayerBase>& 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<String8, String8> *headers)
 {
@@ -717,25 +795,12 @@
         return mStatus;
     } else {
         player_type playerType = getPlayerType(url);
-        ALOGV("player type = %d", playerType);
-
-        // create the right type of player
-        sp<MediaPlayerBase> p = createPlayer(playerType);
-        if (p == NULL) return NO_INIT;
-
-        if (!p->hardwareOutput()) {
-            mAudioOutput = new AudioOutput(mAudioSessionId);
-            static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
+        sp<MediaPlayerBase> 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 @@
         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<MediaPlayerBase> p = createPlayer(playerType);
-    if (p == NULL) return NO_INIT;
-
-    if (!p->hardwareOutput()) {
-        mAudioOutput = new AudioOutput(mAudioSessionId);
-        static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
+    sp<MediaPlayerBase> 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<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 = getPlayerType(source);
+    sp<MediaPlayerBase> p = setDataSource_pre(playerType);
     if (p == NULL) {
         return NO_INIT;
     }
 
-    if (!p->hardwareOutput()) {
-        mAudioOutput = new AudioOutput(mAudioSessionId);
-        static_cast<MediaPlayerInterface*>(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::reset()
 {
     ALOGV("[%d] reset", mConnId);
+    mRetransmitEndpointValid = false;
     sp<MediaPlayerBase> p = getPlayer();
     if (p == 0) return UNKNOWN_ERROR;
     return p->reset();
@@ -1100,6 +1154,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);
+        ALOGV("[%d] setRetransmitEndpoint(%u.%u.%u.%u:%hu)", mConnId,
+                (a >> 24), (a >> 16) & 0xFF, (a >> 8) & 0xFF, (a & 0xFF), p);
+    } else {
+        ALOGV("[%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 52af64d..53847ed 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>
@@ -276,6 +278,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);
 
@@ -287,6 +290,14 @@
 
         virtual status_t        setDataSource(const sp<IStreamSource> &source);
 
+        sp<MediaPlayerBase>     setDataSource_pre(player_type playerType);
+        void                    setDataSource_post(const sp<MediaPlayerBase>& 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<IStreamSource> &source);
+
         static  void            notify(void* cookie, int msg,
                                        int ext1, int ext2, const Parcel *obj);
 
@@ -338,6 +349,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
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 34a2796..509193c 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -79,7 +79,7 @@
 endif
 
 ifeq ($(VOTT), v7)
-LOCAL_CFLAGS += -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM
+LOCAL_CFLAGS += -DARMV5E -DARMV7Neon -DARM_INASM -DARMV5_INASM -DARMV6_INASM
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV5E
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
 endif
diff --git a/media/libstagefright/codecs/aacenc/basic_op/basic_op.h b/media/libstagefright/codecs/aacenc/basic_op/basic_op.h
index e878bba..5cd7e5f 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/basic_op.h
+++ b/media/libstagefright/codecs/aacenc/basic_op/basic_op.h
@@ -227,13 +227,7 @@
 #if ARMV4_INASM
 __inline Word32 ASM_L_shr(Word32 L_var1, Word16 var2)
 {
-	Word32 result;
-	asm (
-		"MOV %[result], %[L_var1], ASR %[var2] \n"
-		:[result]"=r"(result)
-		:[L_var1]"r"(L_var1), [var2]"r"(var2)
-		);
-	return result;
+	return L_var1 >> var2;
 }
 
 __inline Word32 ASM_L_shl(Word32 L_var1, Word16 var2)
@@ -264,6 +258,18 @@
 
 __inline Word32 ASM_shl(Word32 L_var1, Word16 var2)
 {
+#if ARMV6_SAT
+	Word32 result;
+	asm (
+		"CMP	%[var2], #16\n"
+		"MOVLT  %[result], %[L_var1], ASL %[var2]\n"
+		"MOVGE  %[result], %[L_var1], ASL #16\n"
+		"SSAT   %[result], #16, %[result]\n"
+		:[result]"=r"(result)
+		:[L_var1]"r"(L_var1), [var2]"r"(var2)
+		);
+	return result;
+#else
 	Word32 result;
 	Word32 tmp;
 	asm (
@@ -277,6 +283,7 @@
 		:[L_var1]"r"(L_var1), [var2]"r"(var2), [mask]"r"(0x7fff)
 		);
 	return result;
+#endif
 }
 #endif
 
@@ -288,7 +295,15 @@
 #if (SATRUATE_IS_INLINE)
 __inline Word16 saturate(Word32 L_var1)
 {
-#if ARMV5TE_SAT
+#if ARMV6_SAT
+    Word16 result;
+	asm (
+		"SSAT %[result], #16, %[L_var1]"
+		: [result]"=r"(result)
+		: [L_var1]"r"(L_var1)
+		);
+	return result;
+#elif ARMV5TE_SAT
 	Word16 result;
 	Word32 tmp;
 	asm volatile (
@@ -445,8 +460,7 @@
 	Word32 result;
 	asm (
 		"SMULBB %[result], %[var1], %[var2] \n"
-		"QADD %[result], %[result], %[result] \n"
-		"QSUB %[result], %[L_var3], %[result]\n"
+		"QDSUB %[result], %[L_var3], %[result]\n"
 		:[result]"=&r"(result)
 		:[L_var3]"r"(L_var3), [var1]"r"(var1), [var2]"r"(var2)
 		);
@@ -671,7 +685,16 @@
 #if (MULT_IS_INLINE)
 __inline Word16 mult (Word16 var1, Word16 var2)
 {
-#if ARMV5TE_MULT
+#if ARMV5TE_MULT && ARMV6_SAT
+	Word32 result;
+	asm (
+		"SMULBB %[result], %[var1], %[var2] \n"
+		"SSAT   %[result], #16, %[result], ASR #15 \n"
+		:[result]"=r"(result)
+		:[var1]"r"(var1), [var2]"r"(var2)
+		);
+	return result;
+#elif ARMV5TE_MULT
 	Word32 result, tmp;
 	asm (
 		"SMULBB %[tmp], %[var1], %[var2] \n"
@@ -990,8 +1013,7 @@
 	Word32 result;
 	asm (
 		"SMULBB %[result], %[var1], %[var2]\n"
-		"QADD	%[result], %[result], %[result]\n"
-		"QADD   %[result], %[result], %[L_var3]\n"
+		"QDADD  %[result], %[L_var3], %[result]\n"
 		:[result]"=&r"(result)
 		: [L_var3]"r"(L_var3), [var1]"r"(var1), [var2]"r"(var2)
 		);
diff --git a/media/libstagefright/codecs/aacenc/basic_op/typedefs.h b/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
index 8ef43e2..6059237 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
+++ b/media/libstagefright/codecs/aacenc/basic_op/typedefs.h
@@ -128,6 +128,13 @@
     #define ARMV5TE_NORM_L        1
 	#define ARMV5TE_L_MPY_LS	  1
 #endif
+#if ARMV6_INASM
+    #undef  ARMV5TE_ADD
+    #define ARMV5TE_ADD           0
+    #undef  ARMV5TE_SUB
+    #define ARMV5TE_SUB           0
+    #define ARMV6_SAT             1
+#endif
 
 //basic operation functions optimization flags
 #define SATRUATE_IS_INLINE              1   //define saturate as inline function
diff --git a/media/libstagefright/codecs/aacenc/src/bitbuffer.c b/media/libstagefright/codecs/aacenc/src/bitbuffer.c
index a706893..0ce93d3 100644
--- a/media/libstagefright/codecs/aacenc/src/bitbuffer.c
+++ b/media/libstagefright/codecs/aacenc/src/bitbuffer.c
@@ -152,6 +152,7 @@
 
   wBitPos = hBitBuf->wBitPos;
   wBitPos += noBitsToWrite;
+  writeValue &= ~(0xffffffff << noBitsToWrite); // Mask out everything except the lowest noBitsToWrite bits
   writeValue <<= 32 - wBitPos;
   writeValue |= hBitBuf->cache;