/*
* 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