/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "LibAAH_RTP" #include <utils/Log.h> #include <arpa/inet.h> #include <string.h> #include <media/stagefright/foundation/ADebug.h> #include "aah_tx_packet.h" namespace android { const int TRTPPacket::kRTPHeaderLen; const uint32_t TRTPPacket::kTRTPEpochMask; TRTPPacket::~TRTPPacket() { delete mPacket; } /*** TRTP packet properties ***/ void TRTPPacket::setSeqNumber(uint16_t val) { mSeqNumber = val; if (mIsPacked) { const int kTRTPSeqNumberOffset = 2; uint16_t* buf = reinterpret_cast<uint16_t*>( mPacket + kTRTPSeqNumberOffset); *buf = htons(mSeqNumber); } } uint16_t TRTPPacket::getSeqNumber() const { return mSeqNumber; } void TRTPPacket::setPTS(int64_t val) { CHECK(!mIsPacked); mPTS = val; mPTSValid = true; } int64_t TRTPPacket::getPTS() const { return mPTS; } void TRTPPacket::setEpoch(uint32_t val) { mEpoch = val; if (mIsPacked) { const int kTRTPEpochOffset = 8; uint32_t* buf = reinterpret_cast<uint32_t*>( mPacket + kTRTPEpochOffset); uint32_t val = ntohl(*buf); val &= ~(kTRTPEpochMask << kTRTPEpochShift); val |= (mEpoch & kTRTPEpochMask) << kTRTPEpochShift; *buf = htonl(val); } } void TRTPPacket::setProgramID(uint16_t val) { CHECK(!mIsPacked); mProgramID = val; } void TRTPPacket::setSubstreamID(uint16_t val) { CHECK(!mIsPacked); mSubstreamID = val; } void TRTPPacket::setClockTransform(const LinearTransform& trans) { CHECK(!mIsPacked); mClockTranform = trans; mClockTranformValid = true; } uint8_t* TRTPPacket::getPacket() const { CHECK(mIsPacked); return mPacket; } int TRTPPacket::getPacketLen() const { CHECK(mIsPacked); return mPacketLen; } void TRTPPacket::setExpireTime(nsecs_t val) { CHECK(!mIsPacked); mExpireTime = val; } nsecs_t TRTPPacket::getExpireTime() const { return mExpireTime; } /*** TRTP audio packet properties ***/ void TRTPAudioPacket::setCodecType(TRTPAudioCodecType val) { CHECK(!mIsPacked); mCodecType = val; } void TRTPAudioPacket::setRandomAccessPoint(bool val) { CHECK(!mIsPacked); mRandomAccessPoint = val; } void TRTPAudioPacket::setDropable(bool val) { CHECK(!mIsPacked); mDropable = val; } void TRTPAudioPacket::setDiscontinuity(bool val) { CHECK(!mIsPacked); mDiscontinuity = val; } void TRTPAudioPacket::setEndOfStream(bool val) { CHECK(!mIsPacked); mEndOfStream = val; } void TRTPAudioPacket::setVolume(uint8_t val) { CHECK(!mIsPacked); mVolume = val; } 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) { CHECK(!mIsPacked); mCommandID = val; } /*** TRTP packet serializers ***/ void TRTPPacket::writeU8(uint8_t*& buf, uint8_t val) { *buf = val; buf++; } void TRTPPacket::writeU16(uint8_t*& buf, uint16_t val) { *reinterpret_cast<uint16_t*>(buf) = htons(val); buf += 2; } void TRTPPacket::writeU32(uint8_t*& buf, uint32_t val) { *reinterpret_cast<uint32_t*>(buf) = htonl(val); buf += 4; } void TRTPPacket::writeU64(uint8_t*& buf, uint64_t val) { buf[0] = static_cast<uint8_t>(val >> 56); buf[1] = static_cast<uint8_t>(val >> 48); buf[2] = static_cast<uint8_t>(val >> 40); buf[3] = static_cast<uint8_t>(val >> 32); buf[4] = static_cast<uint8_t>(val >> 24); buf[5] = static_cast<uint8_t>(val >> 16); buf[6] = static_cast<uint8_t>(val >> 8); buf[7] = static_cast<uint8_t>(val); buf += 8; } void TRTPPacket::writeTRTPHeader(uint8_t*& buf, bool isFirstFragment, int totalPacketLen) { // RTP header writeU8(buf, ((mVersion & 0x03) << 6) | (static_cast<int>(mPadding) << 5) | (static_cast<int>(mExtension) << 4) | (mCsrcCount & 0x0F)); writeU8(buf, (static_cast<int>(isFirstFragment) << 7) | (mPayloadType & 0x7F)); writeU16(buf, mSeqNumber); if (isFirstFragment && mPTSValid) { writeU32(buf, mPTS & 0xFFFFFFFF); } else { writeU32(buf, 0); } writeU32(buf, ((mEpoch & kTRTPEpochMask) << kTRTPEpochShift) | ((mProgramID & 0x1F) << 5) | (mSubstreamID & 0x1F)); // TRTP header writeU8(buf, mTRTPVersion); writeU8(buf, ((mTRTPHeaderType & 0x0F) << 4) | (mClockTranformValid ? 0x02 : 0x00) | (mPTSValid ? 0x01 : 0x00)); writeU32(buf, totalPacketLen - kRTPHeaderLen); if (mPTSValid) { writeU32(buf, mPTS >> 32); } if (mClockTranformValid) { writeU64(buf, mClockTranform.a_zero); writeU32(buf, mClockTranform.a_to_b_numer); writeU32(buf, mClockTranform.a_to_b_denom); writeU64(buf, mClockTranform.b_zero); } } bool TRTPAudioPacket::pack() { if (mIsPacked) { return false; } int packetLen = kRTPHeaderLen + mAuxDataLen + mAccessUnitLen + TRTPHeaderLen(); // TODO : support multiple fragments const int kMaxUDPPayloadLen = 65507; if (packetLen > kMaxUDPPayloadLen) { return false; } mPacket = new uint8_t[packetLen]; if (!mPacket) { return false; } 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, flags); writeU8(cur, mVolume); if (hasAux) { writeU32(cur, mAuxDataLen); memcpy(cur, mAuxData, mAuxDataLen); cur += mAuxDataLen; } memcpy(cur, mAccessUnitData, mAccessUnitLen); mIsPacked = true; return true; } int TRTPPacket::TRTPHeaderLen() const { // 6 bytes for version, payload type, flags and length. An additional 4 if // there are upper timestamp bits present and another 24 if there is a clock // transformation present. return 6 + (mClockTranformValid ? 24 : 0) + (mPTSValid ? 4 : 0); } int TRTPAudioPacket::TRTPHeaderLen() const { // TRTPPacket::TRTPHeaderLen() for the base TRTPHeader. 3 bytes for audio's // codec type, flags and volume field. Another 5 bytes if the codec type is // PCM and we are sending sample rate/channel count. as well as however long // the aux data (if present) is. int pcmParamLength; switch(mCodecType) { case kCodecPCMBigEndian: case kCodecPCMLittleEndian: pcmParamLength = 5; break; default: pcmParamLength = 0; break; } int auxDataLenField = (NULL != mAuxData) ? sizeof(uint32_t) : 0; return TRTPPacket::TRTPHeaderLen() + 3 + auxDataLenField + pcmParamLength; } bool TRTPControlPacket::pack() { if (mIsPacked) { return false; } // command packets contain a 2-byte command ID int packetLen = kRTPHeaderLen + TRTPHeaderLen() + 2; mPacket = new uint8_t[packetLen]; if (!mPacket) { return false; } mPacketLen = packetLen; uint8_t* cur = mPacket; writeTRTPHeader(cur, true, packetLen); writeU16(cur, mCommandID); mIsPacked = true; return true; } } // namespace android