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;