You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1005 lines
25 KiB
1005 lines
25 KiB
/*
|
|
* Copyright 2012, 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_NDEBUG 0
|
|
#define LOG_TAG "RTPSink"
|
|
#include <utils/Log.h>
|
|
|
|
#include "include/RTPSink.h"
|
|
#include "include/TunnelRenderer.h"
|
|
#include "include/ANetworkSession.h"
|
|
|
|
#include <media/stagefright/foundation/AMessage.h>
|
|
#include <media/stagefright/foundation/ABuffer.h>
|
|
#include <media/stagefright/foundation/ADebug.h>
|
|
#include <media/stagefright/foundation/AMessage.h>
|
|
#include <media/stagefright/foundation/hexdump.h>
|
|
#include <media/stagefright/MediaErrors.h>
|
|
#include <media/stagefright/Utils.h>
|
|
#include <utils/CallStack.h>
|
|
#include <inttypes.h>
|
|
|
|
#define RTP_DEBUG 0
|
|
|
|
namespace android {
|
|
|
|
static uint16_t U16_AT_EXT(const uint8_t *ptr) {
|
|
return ptr[0]<<8 | ptr[1];
|
|
}
|
|
|
|
static uint32_t U32_AT_EXT(const uint8_t *ptr) {
|
|
return ptr[0]<<24 | ptr[1]<<16 | ptr[2]<<8 | ptr[3];
|
|
}
|
|
|
|
static uint64_t U64_AT_EXT(const uint8_t *ptr) {
|
|
return (uint64_t)U32_AT_EXT(ptr)<<32 | U32_AT_EXT(ptr+4);
|
|
}
|
|
|
|
struct RTPSink::Source : public RefBase {
|
|
Source(uint16_t seq, const sp<ABuffer> &buffer,
|
|
const sp<AMessage> queueBufferMsg,RTPSink* owner);
|
|
|
|
bool updateSeq(uint16_t seq, const sp<ABuffer> &buffer);
|
|
|
|
void addReportBlock(uint32_t ssrc, const sp<ABuffer> &buf);
|
|
|
|
protected:
|
|
virtual ~Source();
|
|
|
|
private:
|
|
static const uint32_t kMinSequential = 2;
|
|
static const uint32_t kMaxDropout = 30000;//3000;
|
|
static const uint32_t kMaxMisorder = 100;
|
|
static const uint32_t kRTPSeqMod = 1u << 16;
|
|
|
|
sp<AMessage> mQueueBufferMsg;
|
|
|
|
uint16_t mMaxSeq;
|
|
uint32_t mCycles;
|
|
uint32_t mBaseSeq;
|
|
uint32_t mBadSeq;
|
|
uint32_t mProbation;
|
|
uint32_t mReceived;
|
|
uint32_t mExpectedPrior;
|
|
uint32_t mReceivedPrior;
|
|
|
|
RTPSink* owner;
|
|
void initSeq(uint16_t seq);
|
|
void queuePacket(const sp<ABuffer> &buffer);
|
|
|
|
DISALLOW_EVIL_CONSTRUCTORS(Source);
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
RTPSink::Source::Source(
|
|
uint16_t seq, const sp<ABuffer> &buffer,
|
|
const sp<AMessage> queueBufferMsg,RTPSink* mRTPSink)
|
|
: mQueueBufferMsg(queueBufferMsg),
|
|
mProbation(kMinSequential) {
|
|
initSeq(seq);
|
|
mMaxSeq = seq - 1;
|
|
owner = mRTPSink;
|
|
buffer->setInt32Data(mCycles | seq);
|
|
queuePacket(buffer);
|
|
}
|
|
|
|
RTPSink::Source::~Source() {
|
|
}
|
|
|
|
void RTPSink::Source::initSeq(uint16_t seq) {
|
|
mMaxSeq = seq;
|
|
mCycles = 0;
|
|
mBaseSeq = seq;
|
|
mBadSeq = kRTPSeqMod + 1;
|
|
mReceived = 0;
|
|
mExpectedPrior = 0;
|
|
mReceivedPrior = 0;
|
|
}
|
|
|
|
bool RTPSink::Source::updateSeq(uint16_t seq, const sp<ABuffer> &buffer) {
|
|
uint16_t udelta = seq - mMaxSeq;
|
|
|
|
if (mProbation) {
|
|
// Startup phase
|
|
|
|
if (seq == mMaxSeq + 1) {
|
|
buffer->setInt32Data(mCycles | seq);
|
|
queuePacket(buffer);
|
|
|
|
--mProbation;
|
|
mMaxSeq = seq;
|
|
if (mProbation == 0) {
|
|
initSeq(seq);
|
|
++mReceived;
|
|
|
|
return true;
|
|
}
|
|
} else {
|
|
// Packet out of sequence, restart startup phase
|
|
|
|
mProbation = kMinSequential - 1;
|
|
mMaxSeq = seq;
|
|
|
|
#if 0
|
|
mPackets.clear();
|
|
mTotalBytesQueued = 0;
|
|
ALOGI("XXX cleared packets");
|
|
#endif
|
|
|
|
buffer->setInt32Data(mCycles | seq);
|
|
queuePacket(buffer);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (udelta < kMaxDropout) {
|
|
// In order, with permissible gap.
|
|
|
|
if (seq < mMaxSeq) {
|
|
// Sequence number wrapped - count another 64K cycle
|
|
mCycles += kRTPSeqMod;
|
|
}
|
|
|
|
mMaxSeq = seq;
|
|
} else if (udelta <= kRTPSeqMod - kMaxMisorder) {
|
|
// The sequence number made a very large jump
|
|
|
|
if (seq == mBadSeq) {
|
|
// Two sequential packets -- assume that the other side
|
|
// restarted without telling us so just re-sync
|
|
// (i.e. pretend this was the first packet)
|
|
ALOGD("resync RTP seq %d %d %d", seq, mMaxSeq, udelta);
|
|
initSeq(seq);
|
|
++mReceived;
|
|
buffer->setInt32Data(mCycles | seq);
|
|
sp<AMessage> msg = mQueueBufferMsg->dup();
|
|
msg->setBuffer("buffer", buffer);
|
|
msg->setInt32("resync_rtpseq", 1);
|
|
msg->post();
|
|
return true;
|
|
} else {
|
|
mBadSeq = (seq + 1) & (kRTPSeqMod - 1);
|
|
|
|
return false;
|
|
}
|
|
} else {
|
|
// Duplicate or reordered packet.
|
|
}
|
|
|
|
++mReceived;
|
|
|
|
buffer->setInt32Data(mCycles | seq);
|
|
queuePacket(buffer);
|
|
|
|
return true;
|
|
}
|
|
|
|
void RTPSink::Source::queuePacket(const sp<ABuffer> &buffer) {
|
|
ALOGV("RTPSink::Source::queuePacket");
|
|
#if 0
|
|
int64_t cur_time = systemTime(SYSTEM_TIME_MONOTONIC) / 1000;
|
|
|
|
|
|
if((data_length + buffer->size()> 29 * 188 * 10 && data_length + buffer->size() < 30 * 188 * 10))
|
|
{
|
|
sp<ABuffer> buf = new ABuffer(30 * 188 * 10);
|
|
memcpy(mBuffer+ data_length,buffer->data(),buffer->size());
|
|
data_length+=buffer->size();
|
|
|
|
|
|
memcpy(buf->data(),mBuffer,data_length);
|
|
buf->setRange( 0,data_length);
|
|
buffer->clear();
|
|
|
|
|
|
sp<AMessage> msg = mQueueBufferMsg->dup();
|
|
msg->setBuffer("buffer", buf);
|
|
msg->post();
|
|
data_length = 0;
|
|
}
|
|
else if(data_length + buffer->size() > 30 * 188 * 10)
|
|
{
|
|
sp<ABuffer> buf = new ABuffer(30 * 188 * 10);
|
|
memcpy(mBuffer+ data_length,buffer->data(),buffer->size());
|
|
buf->setRange( 0,data_length);
|
|
sp<AMessage> msg = mQueueBufferMsg->dup();
|
|
msg->setBuffer("buffer", buf);
|
|
msg->post();
|
|
|
|
memcpy(mBuffer,buffer->data(),buffer->size());
|
|
data_length = buffer->size();
|
|
buffer->clear();
|
|
|
|
|
|
}
|
|
else if(cur_time -mPrev_packet_time > 5000ll)
|
|
{
|
|
sp<ABuffer> buf = new ABuffer(30 * 188 * 10);
|
|
memcpy(mBuffer+ data_length,buffer->data(),buffer->size());
|
|
data_length+=buffer->size();
|
|
|
|
|
|
memcpy(buf->data(),mBuffer,data_length);
|
|
buf->setRange( 0,data_length);
|
|
buffer->clear();
|
|
|
|
|
|
sp<AMessage> msg = mQueueBufferMsg->dup();
|
|
msg->setBuffer("buffer", buf);
|
|
msg->post();
|
|
data_length = 0;
|
|
}
|
|
else
|
|
{
|
|
memcpy(mBuffer + data_length,buffer->data(),buffer->size());
|
|
data_length += buffer->size();
|
|
buffer->clear();
|
|
}
|
|
|
|
|
|
|
|
mPrev_packet_time = cur_time;
|
|
|
|
#else
|
|
//if(owner->getRender() == NULL)
|
|
//{
|
|
sp<AMessage> msg = mQueueBufferMsg->dup();
|
|
msg->setBuffer("buffer", buffer);
|
|
msg->post();
|
|
//}
|
|
//else
|
|
//{
|
|
// owner->getRender()->queueBuffer(buffer);
|
|
// owner->getRender()->doSomeWork();
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
}
|
|
|
|
void RTPSink::Source::addReportBlock(
|
|
uint32_t ssrc, const sp<ABuffer> &buf) {
|
|
uint32_t extMaxSeq = mMaxSeq | mCycles;
|
|
uint32_t expected = extMaxSeq - mBaseSeq + 1;
|
|
|
|
int64_t lost = (int64_t)expected - (int64_t)mReceived;
|
|
if (lost > 0x7fffff) {
|
|
lost = 0x7fffff;
|
|
} else if (lost < -0x800000) {
|
|
lost = -0x800000;
|
|
}
|
|
|
|
uint32_t expectedInterval = expected - mExpectedPrior;
|
|
mExpectedPrior = expected;
|
|
|
|
uint32_t receivedInterval = mReceived - mReceivedPrior;
|
|
mReceivedPrior = mReceived;
|
|
|
|
int64_t lostInterval = expectedInterval - receivedInterval;
|
|
|
|
uint8_t fractionLost;
|
|
if (expectedInterval == 0 || lostInterval <=0) {
|
|
fractionLost = 0;
|
|
} else {
|
|
fractionLost = (lostInterval << 8) / expectedInterval;
|
|
}
|
|
|
|
uint8_t *ptr = buf->data() + buf->size();
|
|
|
|
ptr[0] = ssrc >> 24;
|
|
ptr[1] = (ssrc >> 16) & 0xff;
|
|
ptr[2] = (ssrc >> 8) & 0xff;
|
|
ptr[3] = ssrc & 0xff;
|
|
|
|
ptr[4] = fractionLost;
|
|
|
|
ptr[5] = (lost >> 16) & 0xff;
|
|
ptr[6] = (lost >> 8) & 0xff;
|
|
ptr[7] = lost & 0xff;
|
|
|
|
ptr[8] = extMaxSeq >> 24;
|
|
ptr[9] = (extMaxSeq >> 16) & 0xff;
|
|
ptr[10] = (extMaxSeq >> 8) & 0xff;
|
|
ptr[11] = extMaxSeq & 0xff;
|
|
|
|
// XXX TODO:
|
|
|
|
ptr[12] = 0x00; // interarrival jitter
|
|
ptr[13] = 0x00;
|
|
ptr[14] = 0x00;
|
|
ptr[15] = 0x00;
|
|
|
|
ptr[16] = 0x00; // last SR
|
|
ptr[17] = 0x00;
|
|
ptr[18] = 0x00;
|
|
ptr[19] = 0x00;
|
|
|
|
ptr[20] = 0x00; // delay since last SR
|
|
ptr[21] = 0x00;
|
|
ptr[22] = 0x00;
|
|
ptr[23] = 0x00;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
RTPSink::RTPSink(
|
|
const sp<ANetworkSession> &netSession)
|
|
: mNetSession(netSession),
|
|
mRTPPort(0),
|
|
mRTPSessionID(0),
|
|
mRTCPSessionID(0),
|
|
mFirstArrivalTimeUs(-1ll),
|
|
mNumPacketsReceived(0ll),
|
|
mRegression(1000),
|
|
mMaxDelayMs(-1ll) {
|
|
renderLooper = new ALooper;
|
|
renderLooper->setName("renderLooper");
|
|
renderLooper->start(false /* runOnCallingThread */,
|
|
false /* canCallJava */,
|
|
PRIORITY_AUDIO);
|
|
}
|
|
void* RTPSink::ALooper_func()
|
|
{
|
|
renderLooper->start(true);
|
|
return NULL;
|
|
}
|
|
void* RTPSink::ThreadLoop(void *me )
|
|
{
|
|
return (void *) static_cast<RTPSink *>(me)->ALooper_func();
|
|
}
|
|
RTPSink::~RTPSink() {
|
|
void* retval1;
|
|
renderLooper->stop();
|
|
pthread_join(mThread, &retval1);
|
|
ALOGD("RTPSink::~RTPSink");
|
|
/*if (mRTCPSessionID != 0) {
|
|
ALOGD("RTPSink::~RTPSink mRTCPSessionID %d",mRTCPSessionID);
|
|
mNetSession->destroySession(mRTCPSessionID);
|
|
}
|
|
|
|
if (mRTPSessionID != 0) {
|
|
ALOGD("RTPSink::~RTPSink mRTCPSessionID %d",mRTPSessionID);
|
|
mNetSession->destroySession(mRTPSessionID);
|
|
}*/
|
|
}
|
|
|
|
status_t RTPSink::init(bool useTCPInterleaving) {
|
|
if (useTCPInterleaving) {
|
|
return OK;
|
|
}
|
|
|
|
int clientRtp;
|
|
|
|
sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, this);
|
|
sp<AMessage> rtcpNotify = new AMessage(kWhatRTCPNotify, this);
|
|
for (clientRtp = 15550;; clientRtp += 2) {
|
|
int32_t rtpSession;
|
|
status_t err = mNetSession->createUDPSession(
|
|
clientRtp, rtpNotify, &rtpSession);
|
|
|
|
if (err != OK) {
|
|
ALOGI("failed to create RTP socket on port %d", clientRtp);
|
|
continue;
|
|
}
|
|
|
|
int32_t rtcpSession;
|
|
err = mNetSession->createUDPSession(
|
|
clientRtp + 1, rtcpNotify, &rtcpSession);
|
|
|
|
if (err == OK) {
|
|
mRTPPort = clientRtp;
|
|
mRTPSessionID = rtpSession;
|
|
mRTCPSessionID = rtcpSession;
|
|
break;
|
|
}
|
|
|
|
ALOGI("failed to create RTCP socket on port %d", clientRtp + 1);
|
|
mNetSession->destroySession(rtpSession);
|
|
}
|
|
|
|
//mNetSession->setRtpSink(this);
|
|
if (mRTPPort == 0) {
|
|
return UNKNOWN_ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
int32_t RTPSink::getRTPPort() const {
|
|
return mRTPPort;
|
|
}
|
|
void RTPSink::Processdata(sp<ABuffer> &data,int sessionId)
|
|
{
|
|
#if 1
|
|
|
|
|
|
status_t err;
|
|
|
|
if (sessionId == mRTPSessionID) {
|
|
err = parseRTP(data);
|
|
|
|
} else {
|
|
if(sessionId == mRTCPSessionID)
|
|
{
|
|
err = parseRTCP(data);
|
|
}
|
|
else
|
|
ALOGD("Processdata error:sessionId %d",sessionId);
|
|
}
|
|
#else
|
|
|
|
{
|
|
int32_t sessionID;
|
|
CHECK(msg->findInt32("sessionID", &sessionID));
|
|
|
|
sp<ABuffer> data;
|
|
CHECK(msg->findBuffer("data", &data));
|
|
|
|
status_t err;
|
|
|
|
if (msg->what() == kWhatRTPNotify) {
|
|
err = parseRTP(data);
|
|
} else {
|
|
err = parseRTCP(data);
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
}
|
|
void RTPSink::onMessageReceived(const sp<AMessage> &msg) {
|
|
switch (msg->what()) {
|
|
case kWhatRTPNotify:
|
|
case kWhatRTCPNotify:
|
|
{
|
|
int32_t reason;
|
|
CHECK(msg->findInt32("reason", &reason));
|
|
|
|
switch (reason) {
|
|
case ANetworkSession::kWhatError:
|
|
{
|
|
int32_t sessionID;
|
|
CHECK(msg->findInt32("sessionID", &sessionID));
|
|
|
|
int32_t err;
|
|
CHECK(msg->findInt32("err", &err));
|
|
|
|
AString detail;
|
|
CHECK(msg->findString("detail", &detail));
|
|
|
|
ALOGE("An error occurred in session %d (%d, '%s/%s').",
|
|
sessionID,
|
|
err,
|
|
detail.c_str(),
|
|
strerror(-err));
|
|
|
|
mNetSession->destroySession(sessionID);
|
|
|
|
if (sessionID == mRTPSessionID) {
|
|
mRTPSessionID = 0;
|
|
} else if (sessionID == mRTCPSessionID) {
|
|
mRTCPSessionID = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ANetworkSession::kWhatDatagram:
|
|
{
|
|
int32_t sessionID;
|
|
CHECK(msg->findInt32("sessionID", &sessionID));
|
|
|
|
sp<ABuffer> data;
|
|
CHECK(msg->findBuffer("data", &data));
|
|
|
|
status_t err;
|
|
if (msg->what() == kWhatRTPNotify) {
|
|
err = parseRTP(data);
|
|
} else {
|
|
err = parseRTCP(data);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TRESPASS();
|
|
}
|
|
break;
|
|
}
|
|
|
|
case kWhatSendRR:
|
|
{
|
|
onSendRR();
|
|
break;
|
|
}
|
|
|
|
case kWhatPacketLost:
|
|
{
|
|
onPacketLost(msg);
|
|
break;
|
|
}
|
|
|
|
case kWhatInject:
|
|
{
|
|
int32_t isRTP;
|
|
CHECK(msg->findInt32("isRTP", &isRTP));
|
|
|
|
sp<ABuffer> buffer;
|
|
CHECK(msg->findBuffer("buffer", &buffer));
|
|
|
|
status_t err;
|
|
if (isRTP) {
|
|
err = parseRTP(buffer);
|
|
} else {
|
|
err = parseRTCP(buffer);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
TRESPASS();
|
|
}
|
|
}
|
|
|
|
status_t RTPSink::injectPacket(bool isRTP, const sp<ABuffer> &buffer) {
|
|
sp<AMessage> msg = new AMessage(kWhatInject, this);
|
|
msg->setInt32("isRTP", isRTP);
|
|
msg->setBuffer("buffer", buffer);
|
|
msg->post();
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t RTPSink::parseRTP(const sp<ABuffer> &buffer) {
|
|
size_t size = buffer->size();
|
|
if (size < 12) {
|
|
// Too short to be a valid RTP header.
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
const uint8_t *data = buffer->data();
|
|
|
|
if ((data[0] >> 6) != 2) {
|
|
// Unsupported version.
|
|
return ERROR_UNSUPPORTED;
|
|
}
|
|
|
|
if (data[0] & 0x20) {
|
|
// Padding present.
|
|
|
|
size_t paddingLength = data[size - 1];
|
|
|
|
if (paddingLength + 12 > size) {
|
|
// If we removed this much padding we'd end up with something
|
|
// that's too short to be a valid RTP header.
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
size -= paddingLength;
|
|
}
|
|
|
|
int numCSRCs = data[0] & 0x0f;
|
|
|
|
size_t payloadOffset = 12 + 4 * numCSRCs;
|
|
|
|
if (size < payloadOffset) {
|
|
// Not enough data to fit the basic header and all the CSRC entries.
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
if (data[0] & 0x10) {
|
|
// Header eXtension present.
|
|
|
|
if (size < payloadOffset + 4) {
|
|
// Not enough data to fit the basic header, all CSRC entries
|
|
// and the first 4 bytes of the extension header.
|
|
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
const uint8_t *extensionData = &data[payloadOffset];
|
|
|
|
size_t extensionLength =
|
|
4 * (extensionData[2] << 8 | extensionData[3]);
|
|
|
|
if (size < payloadOffset + 4 + extensionLength) {
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
payloadOffset += 4 + extensionLength;
|
|
}
|
|
|
|
uint32_t srcId = U32_AT_EXT(&data[8]);
|
|
uint32_t rtpTime = U32_AT_EXT(&data[4]);
|
|
uint16_t seqNo = U16_AT_EXT(&data[2]);
|
|
|
|
int64_t arrivalTimeUs;
|
|
CHECK(buffer->meta()->findInt64("arrivalTimeUs", &arrivalTimeUs));
|
|
|
|
if (mFirstArrivalTimeUs < 0ll) {
|
|
mFirstArrivalTimeUs = arrivalTimeUs;
|
|
}
|
|
arrivalTimeUs -= mFirstArrivalTimeUs;
|
|
|
|
int64_t arrivalTimeMedia = (arrivalTimeUs * 9ll) / 100ll;
|
|
|
|
ALOGV("seqNo: %d, SSRC 0x%08x, diff %" PRId64,
|
|
seqNo, srcId, rtpTime - arrivalTimeMedia);
|
|
|
|
mRegression.addPoint((float)rtpTime, (float)arrivalTimeMedia);
|
|
|
|
++mNumPacketsReceived;
|
|
|
|
float n1, n2, b;
|
|
if(0)//jmj
|
|
{
|
|
if (mRegression.approxLine(&n1, &n2, &b)) {
|
|
ALOGV("Line %" PRId64 " : %.2f %.2f %.2f, slope %.2f",
|
|
mNumPacketsReceived, n1, n2, b, -n1 / n2);
|
|
|
|
float expectedArrivalTimeMedia = (b - n1 * (float)rtpTime) / n2;
|
|
float latenessMs = (arrivalTimeMedia - expectedArrivalTimeMedia) / 90.0;
|
|
|
|
if (mMaxDelayMs < 0ll || latenessMs > mMaxDelayMs) {
|
|
mMaxDelayMs = latenessMs;
|
|
ALOGI("packet was %.2f ms late", latenessMs);
|
|
}
|
|
}
|
|
}
|
|
sp<AMessage> meta = buffer->meta();
|
|
meta->setInt32("ssrc", srcId);
|
|
meta->setInt32("rtp-time", rtpTime);
|
|
meta->setInt32("PT", data[1] & 0x7f);
|
|
meta->setInt32("M", data[1] >> 7);
|
|
|
|
buffer->setRange(payloadOffset, size - payloadOffset);
|
|
|
|
ssize_t index = mSources.indexOfKey(srcId);
|
|
if (index < 0) {
|
|
#if 1 // jmj
|
|
if (mRenderer == NULL) {
|
|
sp<AMessage> notifyLost = new AMessage(kWhatPacketLost, this);
|
|
notifyLost->setInt32("ssrc", srcId);
|
|
|
|
mRenderer = new TunnelRenderer(notifyLost);
|
|
renderLooper->registerHandler(mRenderer);
|
|
}
|
|
#endif
|
|
sp<AMessage> queueBufferMsg =
|
|
new AMessage(TunnelRenderer::kWhatQueueBuffer, mRenderer);
|
|
|
|
sp<Source> source = new Source(seqNo, buffer, queueBufferMsg,this);
|
|
mSources.add(srcId, source);
|
|
} else {
|
|
mSources.valueAt(index)->updateSeq(seqNo, buffer);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t RTPSink::parseRTCP(const sp<ABuffer> &buffer) {
|
|
const uint8_t *data = buffer->data();
|
|
size_t size = buffer->size();
|
|
|
|
//android::CallStack stack;
|
|
//stack.update();
|
|
// stack.dump();
|
|
//ALOGD("%s",stack.toString().string());
|
|
ALOGD("%s:%d size %zu", __FUNCTION__,__LINE__,size);
|
|
while (size > 0) {
|
|
if (size < 8) {
|
|
// Too short to be a valid RTCP header
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
if ((data[0] >> 6) != 2) {
|
|
// Unsupported version.
|
|
return ERROR_UNSUPPORTED;
|
|
}
|
|
|
|
if (data[0] & 0x20) {
|
|
// Padding present.
|
|
|
|
size_t paddingLength = data[size - 1];
|
|
|
|
if (paddingLength + 12 > size) {
|
|
// If we removed this much padding we'd end up with something
|
|
// that's too short to be a valid RTP header.
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
size -= paddingLength;
|
|
}
|
|
|
|
size_t headerLength = 4 * (data[2] << 8 | data[3]) + 4;
|
|
|
|
if (size < headerLength) {
|
|
// Only received a partial packet?
|
|
return ERROR_MALFORMED;
|
|
}
|
|
switch (data[1]) {
|
|
|
|
ALOGD("%s:%d data[1] %d", __FUNCTION__,__LINE__,data[1]);
|
|
case 200:
|
|
{
|
|
parseSR(data, headerLength);
|
|
break;
|
|
}
|
|
|
|
case 201: // RR
|
|
case 202: // SDES
|
|
case 204: // APP
|
|
break;
|
|
|
|
case 205: // TSFB (transport layer specific feedback)
|
|
case 206: // PSFB (payload specific feedback)
|
|
// hexdump(data, headerLength);
|
|
break;
|
|
|
|
case 203:
|
|
{
|
|
parseBYE(data, headerLength);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
ALOGW("Unknown RTCP packet type %u of size %zu",
|
|
(unsigned)data[1], headerLength);
|
|
break;
|
|
}
|
|
}
|
|
|
|
data += headerLength;
|
|
size -= headerLength;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t RTPSink::parseBYE(const uint8_t *data, size_t size) {
|
|
size_t SC = data[0] & 0x3f;
|
|
|
|
if (SC == 0 || size < (4 + SC * 4)) {
|
|
// Packet too short for the minimal BYE header.
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
//uint32_t id = U32_AT_EXT(&data[4]);
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t RTPSink::parseSR(const uint8_t *data, size_t size) {
|
|
size_t RC = data[0] & 0x1f;
|
|
|
|
if (size < (7 + RC * 6) * 4) {
|
|
// Packet too short for the minimal SR header.
|
|
return ERROR_MALFORMED;
|
|
}
|
|
|
|
uint32_t id = U32_AT_EXT(&data[4]);
|
|
uint64_t ntpTime = U64_AT_EXT(&data[8]);
|
|
uint32_t rtpTime = U32_AT_EXT(&data[16]);
|
|
|
|
ALOGV("SR: ssrc 0x%08x, ntpTime 0x%016" SCNx64", rtpTime 0x%08x",
|
|
id, ntpTime, rtpTime);
|
|
|
|
return OK;
|
|
}
|
|
|
|
status_t RTPSink::connect(
|
|
const char *host, int32_t remoteRtpPort, int32_t remoteRtcpPort) {
|
|
ALOGI("connecting RTP/RTCP sockets to %s:{%d,%d}",
|
|
host, remoteRtpPort, remoteRtcpPort);
|
|
|
|
status_t err =
|
|
mNetSession->connectUDPSession(mRTPSessionID, host, remoteRtpPort);
|
|
|
|
if (err != OK) {
|
|
return err;
|
|
}
|
|
|
|
err = mNetSession->connectUDPSession(mRTCPSessionID, host, remoteRtcpPort);
|
|
|
|
if (err != OK) {
|
|
return err;
|
|
}
|
|
|
|
#if 0
|
|
sp<ABuffer> buf = new ABuffer(1500);
|
|
memset(buf->data(), 0, buf->size());
|
|
|
|
mNetSession->sendRequest(
|
|
mRTPSessionID, buf->data(), buf->size());
|
|
|
|
mNetSession->sendRequest(
|
|
mRTCPSessionID, buf->data(), buf->size());
|
|
#endif
|
|
|
|
scheduleSendRR();
|
|
|
|
return OK;
|
|
}
|
|
|
|
void RTPSink::scheduleSendRR() {
|
|
(new AMessage(kWhatSendRR, this))->post(2000000ll);
|
|
}
|
|
|
|
void RTPSink::addSDES(const sp<ABuffer> &buffer) {
|
|
uint8_t *data = buffer->data() + buffer->size();
|
|
data[0] = 0x80 | 1;
|
|
data[1] = 202; // SDES
|
|
data[4] = 0xde; // SSRC
|
|
data[5] = 0xad;
|
|
data[6] = 0xbe;
|
|
data[7] = 0xef;
|
|
|
|
size_t offset = 8;
|
|
|
|
data[offset++] = 1; // CNAME
|
|
|
|
AString cname = "stagefright@somewhere";
|
|
data[offset++] = cname.size();
|
|
|
|
memcpy(&data[offset], cname.c_str(), cname.size());
|
|
offset += cname.size();
|
|
|
|
data[offset++] = 6; // TOOL
|
|
|
|
AString tool = "stagefright/1.0";
|
|
data[offset++] = tool.size();
|
|
|
|
memcpy(&data[offset], tool.c_str(), tool.size());
|
|
offset += tool.size();
|
|
|
|
data[offset++] = 0;
|
|
|
|
if ((offset % 4) > 0) {
|
|
size_t count = 4 - (offset % 4);
|
|
switch (count) {
|
|
case 3:
|
|
data[offset++] = 0;
|
|
break;
|
|
case 2:
|
|
data[offset++] = 0;
|
|
break;
|
|
case 1:
|
|
data[offset++] = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
size_t numWords = (offset / 4) - 1;
|
|
data[2] = numWords >> 8;
|
|
data[3] = numWords & 0xff;
|
|
|
|
buffer->setRange(buffer->offset(), buffer->size() + offset);
|
|
}
|
|
|
|
void RTPSink::onSendRR() {
|
|
sp<ABuffer> buf = new ABuffer(1500);
|
|
buf->setRange(0, 0);
|
|
|
|
uint8_t *ptr = buf->data();
|
|
ptr[0] = 0x80 | 0;
|
|
ptr[1] = 201; // RR
|
|
ptr[2] = 0;
|
|
ptr[3] = 1;
|
|
ptr[4] = 0xde; // SSRC
|
|
ptr[5] = 0xad;
|
|
ptr[6] = 0xbe;
|
|
ptr[7] = 0xef;
|
|
|
|
buf->setRange(0, 8);
|
|
|
|
size_t numReportBlocks = 0;
|
|
for (size_t i = 0; i < mSources.size(); ++i) {
|
|
uint32_t ssrc = mSources.keyAt(i);
|
|
sp<Source> source = mSources.valueAt(i);
|
|
|
|
if (numReportBlocks > 31 || buf->size() + 24 > buf->capacity()) {
|
|
// Cannot fit another report block.
|
|
break;
|
|
}
|
|
|
|
source->addReportBlock(ssrc, buf);
|
|
++numReportBlocks;
|
|
}
|
|
|
|
ptr[0] |= numReportBlocks; // 5 bit
|
|
|
|
size_t sizeInWordsMinus1 = 1 + 6 * numReportBlocks;
|
|
ptr[2] = sizeInWordsMinus1 >> 8;
|
|
ptr[3] = sizeInWordsMinus1 & 0xff;
|
|
|
|
buf->setRange(0, (sizeInWordsMinus1 + 1) * 4);
|
|
|
|
addSDES(buf);
|
|
|
|
mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());
|
|
|
|
scheduleSendRR();
|
|
}
|
|
|
|
void RTPSink::onPacketLost(const sp<AMessage> &msg) {
|
|
uint32_t srcId;
|
|
CHECK(msg->findInt32("ssrc", (int32_t *)&srcId));
|
|
|
|
int32_t seqNo;
|
|
CHECK(msg->findInt32("seqNo", &seqNo));
|
|
|
|
int32_t blp = 0;
|
|
|
|
sp<ABuffer> buf = new ABuffer(1500);
|
|
buf->setRange(0, 0);
|
|
|
|
uint8_t *ptr = buf->data();
|
|
ptr[0] = 0x80 | 1; // generic NACK
|
|
ptr[1] = 205; // RTPFB
|
|
ptr[2] = 0;
|
|
ptr[3] = 3;
|
|
ptr[4] = 0xde; // sender SSRC
|
|
ptr[5] = 0xad;
|
|
ptr[6] = 0xbe;
|
|
ptr[7] = 0xef;
|
|
ptr[8] = (srcId >> 24) & 0xff;
|
|
ptr[9] = (srcId >> 16) & 0xff;
|
|
ptr[10] = (srcId >> 8) & 0xff;
|
|
ptr[11] = (srcId & 0xff);
|
|
ptr[12] = (seqNo >> 8) & 0xff;
|
|
ptr[13] = (seqNo & 0xff);
|
|
ptr[14] = (blp >> 8) & 0xff;
|
|
ptr[15] = (blp & 0xff);
|
|
|
|
buf->setRange(0, 16);
|
|
|
|
mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());
|
|
}
|
|
|
|
void RTPSink::clear_mNetSession()
|
|
{
|
|
mNetSession.clear();
|
|
}
|
|
|
|
// add by lance for getting mRTPSessionID 2013.06.01
|
|
int32_t RTPSink::get_mRTPSessionID() const
|
|
{
|
|
return mRTPSessionID;
|
|
}
|
|
|
|
// add by lance for getting mRTCPSessionID 2013.06.01
|
|
int32_t RTPSink::get_mRTCPSessionID() const
|
|
{
|
|
return mRTCPSessionID;
|
|
}
|
|
|
|
// add by lance for getting mNetSession 2013.06.01
|
|
sp<ANetworkSession>& RTPSink::get_mNetSession()
|
|
{
|
|
return mNetSession;
|
|
}
|
|
} // namespace android
|
|
|