C++程序  |  345行  |  8.42 KB

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