diff options
-rw-r--r-- | media/libaah_rtp/aah_rx_player.h | 11 | ||||
-rw-r--r-- | media/libaah_rtp/aah_rx_player_substream.cpp | 348 | ||||
-rw-r--r-- | media/libaah_rtp/aah_tx_packet.cpp | 33 | ||||
-rw-r--r-- | media/libaah_rtp/aah_tx_packet.h | 15 | ||||
-rw-r--r-- | media/libaah_rtp/aah_tx_player.cpp | 91 | ||||
-rw-r--r-- | media/libaah_rtp/aah_tx_player.h | 5 |
6 files changed, 399 insertions, 104 deletions
diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h index 28665ff..53361b4 100644 --- a/media/libaah_rtp/aah_rx_player.h +++ b/media/libaah_rtp/aah_rx_player.h @@ -198,14 +198,15 @@ class AAH_RXPlayer : public MediaPlayerInterface { 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); @@ -216,12 +217,16 @@ class AAH_RXPlayer : public MediaPlayerInterface { 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_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp index 698b3f9..3e3a95c 100644 --- a/media/libaah_rtp/aah_rx_player_substream.cpp +++ b/media/libaah_rtp/aah_rx_player_substream.cpp @@ -27,6 +27,9 @@ #include <media/stagefright/Utils.h> #include "aah_rx_player.h" +#include "aah_tx_packet.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) namespace android { @@ -38,6 +41,7 @@ AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) { substream_details_known_ = false; buffer_in_progress_ = NULL; status_ = OK; + codec_mime_type_ = ""; decoder_ = new AAH_DecoderPump(omx); if (decoder_ == NULL) { @@ -52,6 +56,9 @@ AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) { cleanupBufferInProgress(); } +AAH_RXPlayer::Substream::~Substream() { + shutdown(); +} void AAH_RXPlayer::Substream::shutdown() { substream_meta_ = NULL; @@ -69,6 +76,9 @@ void AAH_RXPlayer::Substream::cleanupBufferInProgress() { 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() { @@ -168,11 +178,7 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, } // 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) { LOGV("TRTP length (%u) is too short to be valid. Must be at least %u" " bytes.", trtp_len, min_length); @@ -183,12 +189,9 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, 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 @@ -245,9 +248,37 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, return; } + // Check for the presence of codec aux data. if (flags & 0x10) { - LOGV("Dropping TRTP Audio Payload with aux codec data present (only" - " handle MP3 right now, and it has no aux data)"); + min_length += 4; + trtp_header_len += 4; + + if (trtp_len < min_length) { + LOGV("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) { + LOGV("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) { + LOGV("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 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, // 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_) { LOGV("Dropping TRTP Audio Payload with 0 Access Unit length"); return; @@ -263,9 +296,10 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, 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) { LOGV("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; } @@ -289,16 +323,32 @@ void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, // 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 +368,18 @@ void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf, 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 +402,6 @@ void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf, } 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,10 +411,91 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() { goto bailout; } + // Make sure our metadata used to initialize the decoder has been properly + // set up. + if (!setupSubstreamMeta()) + goto bailout; + + // If our decoder has not be set up, do so now. + res = decoder_->init(substream_meta_); + if (OK != res) { + LOGE("Failed to init decoder (res = %d)", res); + cleanupDecoder(); + substream_meta_ = NULL; + goto bailout; + } + + // Queue the payload for decode. + res = decoder_->queueForDecode(buffer_in_progress_); + + if (res != OK) { + LOGD("Failed to queue payload for decode, resetting decoder pump!" + " (res = %d)", res); + status_ = res; + cleanupDecoder(); + cleanupBufferInProgress(); + } + + // NULL out buffer_in_progress before calling the cleanup helper. + // + // MediaBuffers use something of a hybrid ref-counting pattern which prevent + // the AAH_DecoderPump's input queue from adding their own reference to the + // MediaBuffer. MediaBuffers start life with a reference count of 0, as + // well as an observer which starts as NULL. Before being given an + // observer, the ref count cannot be allowed to become non-zero as it will + // cause calls to release() to assert. Basically, before a MediaBuffer has + // an observer, they behave like non-ref counted obects where release() + // serves the roll of delete. After a MediaBuffer has an observer, they + // become more like ref counted objects where add ref and release can be + // used, and when the ref count hits zero, the MediaBuffer is handed off to + // the observer. + // + // Given all of this, when we give the buffer to the decoder pump to wait in + // the to-be-processed queue, the decoder cannot add a ref to the buffer as + // it would in a traditional ref counting system. Instead it needs to + // "steal" the non-existent ref. In the case of queue failure, we need to + // make certain to release this non-existent reference so that the buffer is + // cleaned up during the cleanupBufferInProgress helper. In the case of a + // successful queue operation, we need to make certain that the + // cleanupBufferInProgress helper does not release the buffer since it needs + // to remain alive in the queue. We acomplish this by NULLing out the + // buffer pointer before calling the cleanup helper. + buffer_in_progress_ = NULL; + +bailout: + 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: + LOGV("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) { LOGV("MP3 payload too short to contain header, dropping payload."); - goto bailout; + return false; } // Extract the channel count and the sample rate from the MP3 header. The @@ -369,7 +508,7 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() { NULL, NULL)) { LOGV("Failed to parse MP3 header in payload, droping payload."); - goto bailout; + return false; } @@ -381,8 +520,8 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() { substream_meta_ = new MetaData(); if (substream_meta_ == NULL) { - LOGE("Failed to allocate MetaData structure for substream"); - goto bailout; + LOGE("Failed to allocate MetaData structure for MP3 substream"); + return false; } substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); @@ -396,7 +535,7 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() { if ((prev_channel_count != channel_count) || (prev_sample_rate != sample_rate)) { - LOGW("Format change detected, forcing decoder reset."); + LOGW("MP3 format change detected, forcing decoder reset."); cleanupDecoder(); substream_meta_->setInt32(kKeyChannelCount, channel_count); @@ -404,56 +543,87 @@ void AAH_RXPlayer::Substream::processCompletedBuffer() { } } - // If our decoder has not be set up, do so now. - res = decoder_->init(substream_meta_); - if (OK != res) { - LOGE("Failed to init decoder (res = %d)", res); + 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) { + LOGE("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; + + substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate); + substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count); + + // 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. + } + + LOGW("AAC format change detected, forcing decoder reset."); cleanupDecoder(); substream_meta_ = NULL; - goto bailout; } - // Queue the payload for decode. - res = decoder_->queueForDecode(buffer_in_progress_); + CHECK(substream_meta_ == NULL); - if (res != OK) { - LOGD("Failed to queue payload for decode, resetting decoder pump!" - " (res = %d)", res); - status_ = res; - cleanupDecoder(); - cleanupBufferInProgress(); + substream_meta_ = new MetaData(); + if (substream_meta_ == NULL) { + LOGE("Failed to allocate MetaData structure for AAC substream"); + return false; } - // NULL out buffer_in_progress before calling the cleanup helper. - // - // MediaBuffers use something of a hybrid ref-counting pattern which prevent - // the AAH_DecoderPump's input queue from adding their own reference to the - // MediaBuffer. MediaBuffers start life with a reference count of 0, as - // well as an observer which starts as NULL. Before being given an - // observer, the ref count cannot be allowed to become non-zero as it will - // cause calls to release() to assert. Basically, before a MediaBuffer has - // an observer, they behave like non-ref counted obects where release() - // serves the roll of delete. After a MediaBuffer has an observer, they - // become more like ref counted objects where add ref and release can be - // used, and when the ref count hits zero, the MediaBuffer is handed off to - // the observer. - // - // Given all of this, when we give the buffer to the decoder pump to wait in - // the to-be-processed queue, the decoder cannot add a ref to the buffer as - // it would in a traditional ref counting system. Instead it needs to - // "steal" the non-existent ref. In the case of queue failure, we need to - // make certain to release this non-existent reference so that the buffer is - // cleaned up during the cleanupBufferInProgress helper. In the case of a - // successful queue operation, we need to make certain that the - // cleanupBufferInProgress helper does not release the buffer since it needs - // to remain alive in the queue. We acomplish this by NULLing out the - // buffer pointer before calling the cleanup helper. - buffer_in_progress_ = NULL; + substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC); + substream_meta_->setInt32 (kKeySampleRate, sample_rate); + substream_meta_->setInt32 (kKeyChannelCount, channel_cnt); -bailout: - cleanupBufferInProgress(); -} + 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,27 +641,35 @@ bool AAH_RXPlayer::Substream::isAboutToUnderflow() { 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_)) { - LOGV("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_) { + LOGV("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; + } - if (codec_type != 0x03) { - LOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported codec" - " type (%u)", ssrc_, codec_type); - return false; + return true; } - if (!substream_details_known_) { - substream_type_ = substream_type; - codec_type_ = codec_type; - substream_details_known_ = true; + switch (codec_type) { + // MP3 and AAC are all we support right now. + case TRTPAudioPacket::kCodecMPEG1Audio: + case TRTPAudioPacket::kCodecAACAudio: + break; + + default: + LOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported" + " codec type (%u)", ssrc_, codec_type); + return false; } + 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 f3e15e2..c7ad3e0 100644 --- a/media/libaah_rtp/aah_tx_packet.cpp +++ b/media/libaah_rtp/aah_tx_packet.cpp @@ -142,12 +142,18 @@ void TRTPAudioPacket::setVolume(uint8_t val) { 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 @@ bool TRTPAudioPacket::pack() { } int packetLen = kRTPHeaderLen + + mAuxDataLen + mAccessUnitLen + TRTPHeaderLen(); @@ -249,16 +256,24 @@ bool TRTPAudioPacket::pack() { 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 @@ int TRTPAudioPacket::TRTPHeaderLen() const { } - // 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 c5f6285..62436a0 100644 --- a/media/libaah_rtp/aah_tx_packet.h +++ b/media/libaah_rtp/aah_tx_packet.h @@ -126,13 +126,17 @@ class TRTPAudioPacket : public TRTPPacket { , 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); @@ -141,7 +145,8 @@ class TRTPAudioPacket : public TRTPPacket { 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(); @@ -155,8 +160,10 @@ class TRTPAudioPacket : public TRTPPacket { bool mDiscontinuity; bool mEndOfStream; uint8_t mVolume; - void* mAccessUnitData; - int mAccessUnitLen; + const void* mAccessUnitData; + size_t mAccessUnitLen; + const void* mAuxData; + size_t mAuxDataLen; }; class TRTPControlPacket : public TRTPPacket { diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp index 7b1d658..6407074 100644 --- a/media/libaah_rtp/aah_tx_player.cpp +++ b/media/libaah_rtp/aah_tx_player.cpp @@ -28,6 +28,7 @@ #include <media/stagefright/FileSource.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> #include <media/stagefright/MetaData.h> #include <utils/Timers.h> @@ -98,6 +99,8 @@ AAH_TXPlayer::AAH_TXPlayer() mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio); mPumpAudioEventPending = false; + mAudioCodecData = NULL; + reset(); } @@ -398,7 +401,76 @@ void AAH_TXPlayer::onPrepareAsyncEvent() { } } - 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)) { + LOGE("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)) { + LOGE("Failed to find sample rate for AAC substream."); + abortPrepare(BAD_VALUE); + return; + } + + if (!mAudioFormat->findInt32(kKeyChannelCount, &channel_count)) { + LOGE("Failed to find channel count for AAC substream."); + abortPrepare(BAD_VALUE); + return; + } + + if (!mAudioFormat->findData(kKeyESDS, &type, &esds_data, &esds_len)) { + LOGE("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) { + LOGE("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 { + LOGE("Unsupported MIME type \"%s\" in audio substream", mime_type); + abortPrepare(BAD_VALUE); + return; + } status_t err = mAudioSource->start(); if (err != OK) { @@ -666,6 +738,11 @@ void AAH_TXPlayer::reset_l() { mAudioSource->stop(); } mAudioSource.clear(); + mAudioCodec = TRTPAudioPacket::kCodecInvalid; + mAudioFormat = NULL; + delete[] mAudioCodecData; + mAudioCodecData = NULL; + mAudioCodecDataSize = 0; mFlags = 0; mExtractorFlags = 0; @@ -1078,14 +1155,24 @@ void AAH_TXPlayer::onPumpAudio() { 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 6bae5f0..b45a661 100644 --- a/media/libaah_rtp/aah_tx_player.h +++ b/media/libaah_rtp/aah_tx_player.h @@ -153,6 +153,11 @@ class AAH_TXPlayer : public MediaPlayerHWInterface { sp<NuCachedSource2> mCachedSource; sp<MediaSource> mAudioSource; + TRTPAudioPacket::TRTPAudioCodecType mAudioCodec; + sp<MetaData> mAudioFormat; + uint8_t* mAudioCodecData; + size_t mAudioCodecDataSize; + int64_t mDurationUs; int64_t mBitrate; |