Jason Simmons e066b8fce4 Ensure that the TRTP retry buffer has contiguous sequence numbers
Previously, sequence numbers for audio packets were assigned by the
TX player before packets were queued to the sender.  This caused a
race between assignment of sequence numbers on audio packets and
sequence numbers on heartbeat packets.  A heartbeat could get queued
and added to the retry buffer before an audio packet with an earlier
sequence number got queued.

This CL centralizes packet sequence number assignment and insertion
into the retry buffer inside AAH_TXSender::doSendPacket_l.  It also
makes explicit what operations can be done on a TRTPPacket before
and after packing.

Change-Id: I6d02eae81061983e4def4f1b3dd7c1625467b151
2011-10-28 10:14:50 -04:00

332 lines
8.0 KiB
C++

/*
* 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/MediaDebug.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(void* data, int len) {
CHECK(!mIsPacked);
mAccessUnitData = data;
mAccessUnitLen = 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 +
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;
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, mVolume);
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;
}
// TODO : properly compute aux data length. Currently, nothing
// uses aux data, so its length is always 0.
int auxDataLength = 0;
return TRTPPacket::TRTPHeaderLen() +
3 +
auxDataLength +
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