RTPSink.cpp revision fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96
1fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber/* 2fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * Copyright 2012, The Android Open Source Project 3fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * 4fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * you may not use this file except in compliance with the License. 6fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * You may obtain a copy of the License at 7fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * 8fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * 10fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * Unless required by applicable law or agreed to in writing, software 11fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * See the License for the specific language governing permissions and 14fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber * limitations under the License. 15fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber */ 16fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 17fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber//#define LOG_NDEBUG 0 18fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#define LOG_TAG "RTPSink" 19fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <utils/Log.h> 20fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 21fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include "RTPSink.h" 22fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 23fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include "ANetworkSession.h" 24fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include "TunnelRenderer.h" 25fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 26fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/ABuffer.h> 27fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/ADebug.h> 28fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/AMessage.h> 29fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/foundation/hexdump.h> 30fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/MediaErrors.h> 31fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#include <media/stagefright/Utils.h> 32fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 33fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubernamespace android { 34fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 35fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstruct RTPSink::Source : public RefBase { 36fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber Source(uint16_t seq, const sp<ABuffer> &buffer, 37fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<AMessage> queueBufferMsg); 38fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 39fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber bool updateSeq(uint16_t seq, const sp<ABuffer> &buffer); 40fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 41fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber void addReportBlock(uint32_t ssrc, const sp<ABuffer> &buf); 42fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 43fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberprotected: 44fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber virtual ~Source(); 45fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 46fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberprivate: 47fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber static const uint32_t kMinSequential = 2; 48fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber static const uint32_t kMaxDropout = 3000; 49fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber static const uint32_t kMaxMisorder = 100; 50fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber static const uint32_t kRTPSeqMod = 1u << 16; 51fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 52fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> mQueueBufferMsg; 53fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 54fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint16_t mMaxSeq; 55fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mCycles; 56fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mBaseSeq; 57fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mBadSeq; 58fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mProbation; 59fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mReceived; 60fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mExpectedPrior; 61fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t mReceivedPrior; 62fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 63fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber void initSeq(uint16_t seq); 64fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber void queuePacket(const sp<ABuffer> &buffer); 65fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 66fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber DISALLOW_EVIL_CONSTRUCTORS(Source); 67fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber}; 68fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 69fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber//////////////////////////////////////////////////////////////////////////////// 70fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 71fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberRTPSink::Source::Source( 72fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint16_t seq, const sp<ABuffer> &buffer, 73fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<AMessage> queueBufferMsg) 74fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber : mQueueBufferMsg(queueBufferMsg), 75fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mProbation(kMinSequential) { 76fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber initSeq(seq); 77fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxSeq = seq - 1; 78fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 79fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer->setInt32Data(mCycles | seq); 80fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber queuePacket(buffer); 81fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 82fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 83fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberRTPSink::Source::~Source() { 84fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 85fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 86fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::Source::initSeq(uint16_t seq) { 87fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxSeq = seq; 88fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mCycles = 0; 89fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mBaseSeq = seq; 90fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mBadSeq = kRTPSeqMod + 1; 91fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mReceived = 0; 92fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mExpectedPrior = 0; 93fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mReceivedPrior = 0; 94fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 95fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 96fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberbool RTPSink::Source::updateSeq(uint16_t seq, const sp<ABuffer> &buffer) { 97fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint16_t udelta = seq - mMaxSeq; 98fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 99fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mProbation) { 100fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Startup phase 101fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 102fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (seq == mMaxSeq + 1) { 103fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer->setInt32Data(mCycles | seq); 104fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber queuePacket(buffer); 105fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 106fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber --mProbation; 107fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxSeq = seq; 108fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mProbation == 0) { 109fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber initSeq(seq); 110fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ++mReceived; 111fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 112fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return true; 113fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 114fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 115fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Packet out of sequence, restart startup phase 116fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 117fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mProbation = kMinSequential - 1; 118fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxSeq = seq; 119fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 120fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#if 0 121fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mPackets.clear(); 122fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mTotalBytesQueued = 0; 123fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("XXX cleared packets"); 124fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#endif 125fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 126fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer->setInt32Data(mCycles | seq); 127fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber queuePacket(buffer); 128fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 129fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 130fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return false; 131fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 132fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 133fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (udelta < kMaxDropout) { 134fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // In order, with permissible gap. 135fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 136fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (seq < mMaxSeq) { 137fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Sequence number wrapped - count another 64K cycle 138fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mCycles += kRTPSeqMod; 139fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 140fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 141fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxSeq = seq; 142fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else if (udelta <= kRTPSeqMod - kMaxMisorder) { 143fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // The sequence number made a very large jump 144fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 145fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (seq == mBadSeq) { 146fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Two sequential packets -- assume that the other side 147fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // restarted without telling us so just re-sync 148fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // (i.e. pretend this was the first packet) 149fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 150fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber initSeq(seq); 151fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 152fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mBadSeq = (seq + 1) & (kRTPSeqMod - 1); 153fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 154fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return false; 155fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 156fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 157fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Duplicate or reordered packet. 158fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 159fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 160fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ++mReceived; 161fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 162fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer->setInt32Data(mCycles | seq); 163fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber queuePacket(buffer); 164fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 165fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return true; 166fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 167fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 168fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::Source::queuePacket(const sp<ABuffer> &buffer) { 169fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> msg = mQueueBufferMsg->dup(); 170fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber msg->setBuffer("buffer", buffer); 171fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber msg->post(); 172fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 173fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 174fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::Source::addReportBlock( 175fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t ssrc, const sp<ABuffer> &buf) { 176fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t extMaxSeq = mMaxSeq | mCycles; 177fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t expected = extMaxSeq - mBaseSeq + 1; 178fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 179fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int64_t lost = (int64_t)expected - (int64_t)mReceived; 180fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (lost > 0x7fffff) { 181fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber lost = 0x7fffff; 182fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else if (lost < -0x800000) { 183fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber lost = -0x800000; 184fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 185fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 186fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t expectedInterval = expected - mExpectedPrior; 187fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mExpectedPrior = expected; 188fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 189fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t receivedInterval = mReceived - mReceivedPrior; 190fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mReceivedPrior = mReceived; 191fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 192fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int64_t lostInterval = expectedInterval - receivedInterval; 193fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 194fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint8_t fractionLost; 195fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (expectedInterval == 0 || lostInterval <=0) { 196fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber fractionLost = 0; 197fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 198fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber fractionLost = (lostInterval << 8) / expectedInterval; 199fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 200fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 201fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint8_t *ptr = buf->data() + buf->size(); 202fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 203fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[0] = ssrc >> 24; 204fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[1] = (ssrc >> 16) & 0xff; 205fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[2] = (ssrc >> 8) & 0xff; 206fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[3] = ssrc & 0xff; 207fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 208fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[4] = fractionLost; 209fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 210fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[5] = (lost >> 16) & 0xff; 211fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[6] = (lost >> 8) & 0xff; 212fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[7] = lost & 0xff; 213fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 214fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[8] = extMaxSeq >> 24; 215fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[9] = (extMaxSeq >> 16) & 0xff; 216fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[10] = (extMaxSeq >> 8) & 0xff; 217fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[11] = extMaxSeq & 0xff; 218fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 219fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // XXX TODO: 220fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 221fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[12] = 0x00; // interarrival jitter 222fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[13] = 0x00; 223fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[14] = 0x00; 224fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[15] = 0x00; 225fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 226fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[16] = 0x00; // last SR 227fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[17] = 0x00; 228fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[18] = 0x00; 229fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[19] = 0x00; 230fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 231fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[20] = 0x00; // delay since last SR 232fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[21] = 0x00; 233fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[22] = 0x00; 234fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[23] = 0x00; 235fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 236fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 237fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber//////////////////////////////////////////////////////////////////////////////// 238fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 239fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberRTPSink::RTPSink( 240fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<ANetworkSession> &netSession, 241fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const sp<ISurfaceTexture> &surfaceTex) 242fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber : mNetSession(netSession), 243fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSurfaceTex(surfaceTex), 244fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTPPort(0), 245fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTPSessionID(0), 246fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTCPSessionID(0), 247fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstArrivalTimeUs(-1ll), 248fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNumPacketsReceived(0ll), 249fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRegression(1000), 250fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxDelayMs(-1ll) { 251fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 252fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 253fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas HuberRTPSink::~RTPSink() { 254fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mRTCPSessionID != 0) { 255fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->destroySession(mRTCPSessionID); 256fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 257fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 258fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mRTPSessionID != 0) { 259fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->destroySession(mRTPSessionID); 260fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 261fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 262fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 263fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::init(bool useTCPInterleaving) { 264fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (useTCPInterleaving) { 265fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 266fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 267fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 268fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int clientRtp; 269fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 270fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id()); 271fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> rtcpNotify = new AMessage(kWhatRTCPNotify, id()); 272fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber for (clientRtp = 15550;; clientRtp += 2) { 273fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t rtpSession; 274fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber status_t err = mNetSession->createUDPSession( 275fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber clientRtp, rtpNotify, &rtpSession); 276fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 277fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (err != OK) { 278fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("failed to create RTP socket on port %d", clientRtp); 279fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber continue; 280fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 281fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 282fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t rtcpSession; 283fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err = mNetSession->createUDPSession( 284fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber clientRtp + 1, rtcpNotify, &rtcpSession); 285fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 286fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (err == OK) { 287fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTPPort = clientRtp; 288fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTPSessionID = rtpSession; 289fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTCPSessionID = rtcpSession; 290fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 291fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 292fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 293fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("failed to create RTCP socket on port %d", clientRtp + 1); 294fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->destroySession(rtpSession); 295fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 296fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 297fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mRTPPort == 0) { 298fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return UNKNOWN_ERROR; 299fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 300fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 301fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 302fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 303fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 304fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberint32_t RTPSink::getRTPPort() const { 305fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return mRTPPort; 306fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 307fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 308fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::onMessageReceived(const sp<AMessage> &msg) { 309fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber switch (msg->what()) { 310fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case kWhatRTPNotify: 311fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case kWhatRTCPNotify: 312fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 313fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t reason; 314fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("reason", &reason)); 315fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 316fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber switch (reason) { 317fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case ANetworkSession::kWhatError: 318fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 319fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t sessionID; 320fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("sessionID", &sessionID)); 321fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 322fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t err; 323fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("err", &err)); 324fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 325fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber AString detail; 326fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findString("detail", &detail)); 327fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 328fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGE("An error occurred in session %d (%d, '%s/%s').", 329fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sessionID, 330fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err, 331fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber detail.c_str(), 332fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber strerror(-err)); 333fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 334fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->destroySession(sessionID); 335fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 336fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (sessionID == mRTPSessionID) { 337fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTPSessionID = 0; 338fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else if (sessionID == mRTCPSessionID) { 339fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTCPSessionID = 0; 340fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 341fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 342fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 343fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 344fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case ANetworkSession::kWhatDatagram: 345fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 346fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t sessionID; 347fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("sessionID", &sessionID)); 348fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 349fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> data; 350fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findBuffer("data", &data)); 351fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 352fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber status_t err; 353fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (msg->what() == kWhatRTPNotify) { 354fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err = parseRTP(data); 355fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 356fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err = parseRTCP(data); 357fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 358fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 359fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 360fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 361fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber default: 362fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber TRESPASS(); 363fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 364fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 365fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 366fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 367fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case kWhatSendRR: 368fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 369fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber onSendRR(); 370fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 371fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 372fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 373fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case kWhatPacketLost: 374fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 375fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber onPacketLost(msg); 376fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 377fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 378fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 379fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case kWhatInject: 380fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 381fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t isRTP; 382fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("isRTP", &isRTP)); 383fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 384fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> buffer; 385fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findBuffer("buffer", &buffer)); 386fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 387fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber status_t err; 388fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (isRTP) { 389fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err = parseRTP(buffer); 390fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 391fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err = parseRTCP(buffer); 392fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 393fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 394fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 395fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 396fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber default: 397fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber TRESPASS(); 398fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 399fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 400fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 401fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::injectPacket(bool isRTP, const sp<ABuffer> &buffer) { 402fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> msg = new AMessage(kWhatInject, id()); 403fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber msg->setInt32("isRTP", isRTP); 404fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber msg->setBuffer("buffer", buffer); 405fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber msg->post(); 406fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 407fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 408fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 409fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 410fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::parseRTP(const sp<ABuffer> &buffer) { 411fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t size = buffer->size(); 412fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < 12) { 413fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Too short to be a valid RTP header. 414fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 415fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 416fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 417fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const uint8_t *data = buffer->data(); 418fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 419fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if ((data[0] >> 6) != 2) { 420fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Unsupported version. 421fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_UNSUPPORTED; 422fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 423fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 424fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (data[0] & 0x20) { 425fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Padding present. 426fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 427fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t paddingLength = data[size - 1]; 428fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 429fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (paddingLength + 12 > size) { 430fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // If we removed this much padding we'd end up with something 431fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // that's too short to be a valid RTP header. 432fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 433fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 434fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 435fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size -= paddingLength; 436fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 437fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 438fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int numCSRCs = data[0] & 0x0f; 439fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 440fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t payloadOffset = 12 + 4 * numCSRCs; 441fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 442fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < payloadOffset) { 443fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Not enough data to fit the basic header and all the CSRC entries. 444fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 445fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 446fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 447fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (data[0] & 0x10) { 448fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Header eXtension present. 449fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 450fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < payloadOffset + 4) { 451fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Not enough data to fit the basic header, all CSRC entries 452fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // and the first 4 bytes of the extension header. 453fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 454fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 455fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 456fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 457fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const uint8_t *extensionData = &data[payloadOffset]; 458fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 459fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t extensionLength = 460fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 4 * (extensionData[2] << 8 | extensionData[3]); 461fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 462fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < payloadOffset + 4 + extensionLength) { 463fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 464fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 465fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 466fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber payloadOffset += 4 + extensionLength; 467fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 468fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 469fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t srcId = U32_AT(&data[8]); 470fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t rtpTime = U32_AT(&data[4]); 471fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint16_t seqNo = U16_AT(&data[2]); 472fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 473fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int64_t arrivalTimeUs; 474fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(buffer->meta()->findInt64("arrivalTimeUs", &arrivalTimeUs)); 475fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 476fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mFirstArrivalTimeUs < 0ll) { 477fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mFirstArrivalTimeUs = arrivalTimeUs; 478fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 479fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber arrivalTimeUs -= mFirstArrivalTimeUs; 480fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 481fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int64_t arrivalTimeMedia = (arrivalTimeUs * 9ll) / 100ll; 482fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 483fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGV("seqNo: %d, SSRC 0x%08x, diff %lld", 484fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber seqNo, srcId, rtpTime - arrivalTimeMedia); 485fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 486fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRegression.addPoint((float)rtpTime, (float)arrivalTimeMedia); 487fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 488fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ++mNumPacketsReceived; 489fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 490fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber float n1, n2, b; 491fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mRegression.approxLine(&n1, &n2, &b)) { 492fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGV("Line %lld: %.2f %.2f %.2f, slope %.2f", 493fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNumPacketsReceived, n1, n2, b, -n1 / n2); 494fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 495fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber float expectedArrivalTimeMedia = (b - n1 * (float)rtpTime) / n2; 496fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber float latenessMs = (arrivalTimeMedia - expectedArrivalTimeMedia) / 90.0; 497fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 498fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mMaxDelayMs < 0ll || latenessMs > mMaxDelayMs) { 499fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mMaxDelayMs = latenessMs; 500fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("packet was %.2f ms late", latenessMs); 501fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 502fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 503fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 504fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> meta = buffer->meta(); 505fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber meta->setInt32("ssrc", srcId); 506fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber meta->setInt32("rtp-time", rtpTime); 507fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber meta->setInt32("PT", data[1] & 0x7f); 508fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber meta->setInt32("M", data[1] >> 7); 509fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 510fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer->setRange(payloadOffset, size - payloadOffset); 511fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 512fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ssize_t index = mSources.indexOfKey(srcId); 513fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (index < 0) { 514fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (mRenderer == NULL) { 515fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> notifyLost = new AMessage(kWhatPacketLost, id()); 516fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber notifyLost->setInt32("ssrc", srcId); 517fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 518fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRenderer = new TunnelRenderer(notifyLost, mSurfaceTex); 519fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber looper()->registerHandler(mRenderer); 520fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 521fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 522fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<AMessage> queueBufferMsg = 523fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber new AMessage(TunnelRenderer::kWhatQueueBuffer, mRenderer->id()); 524fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 525fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<Source> source = new Source(seqNo, buffer, queueBufferMsg); 526fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSources.add(srcId, source); 527fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } else { 528fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mSources.valueAt(index)->updateSeq(seqNo, buffer); 529fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 530fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 531fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 532fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 533fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 534fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::parseRTCP(const sp<ABuffer> &buffer) { 535fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const uint8_t *data = buffer->data(); 536fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t size = buffer->size(); 537fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 538fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber while (size > 0) { 539fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < 8) { 540fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Too short to be a valid RTCP header 541fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 542fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 543fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 544fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if ((data[0] >> 6) != 2) { 545fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Unsupported version. 546fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_UNSUPPORTED; 547fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 548fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 549fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (data[0] & 0x20) { 550fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Padding present. 551fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 552fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t paddingLength = data[size - 1]; 553fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 554fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (paddingLength + 12 > size) { 555fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // If we removed this much padding we'd end up with something 556fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // that's too short to be a valid RTP header. 557fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 558fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 559fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 560fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size -= paddingLength; 561fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 562fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 563fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t headerLength = 4 * (data[2] << 8 | data[3]) + 4; 564fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 565fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < headerLength) { 566fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Only received a partial packet? 567fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 568fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 569fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 570fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber switch (data[1]) { 571fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 200: 572fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 573fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber parseSR(data, headerLength); 574fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 575fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 576fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 577fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 201: // RR 578fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 202: // SDES 579fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 204: // APP 580fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 581fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 582fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 205: // TSFB (transport layer specific feedback) 583fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 206: // PSFB (payload specific feedback) 584fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // hexdump(data, headerLength); 585fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 586fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 587fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 203: 588fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 589fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber parseBYE(data, headerLength); 590fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 591fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 592fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 593fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber default: 594fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber { 595fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGW("Unknown RTCP packet type %u of size %d", 596fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber (unsigned)data[1], headerLength); 597fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 598fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 599fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 600fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 601fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data += headerLength; 602fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size -= headerLength; 603fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 604fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 605fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 606fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 607fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 608fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::parseBYE(const uint8_t *data, size_t size) { 609fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t SC = data[0] & 0x3f; 610fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 611fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (SC == 0 || size < (4 + SC * 4)) { 612fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Packet too short for the minimal BYE header. 613fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 614fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 615fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 616fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t id = U32_AT(&data[4]); 617fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 618fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 619fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 620fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 621fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::parseSR(const uint8_t *data, size_t size) { 622fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t RC = data[0] & 0x1f; 623fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 624fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (size < (7 + RC * 6) * 4) { 625fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Packet too short for the minimal SR header. 626fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return ERROR_MALFORMED; 627fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 628fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 629fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t id = U32_AT(&data[4]); 630fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint64_t ntpTime = U64_AT(&data[8]); 631fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t rtpTime = U32_AT(&data[16]); 632fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 633fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGV("SR: ssrc 0x%08x, ntpTime 0x%016llx, rtpTime 0x%08x", 634fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber id, ntpTime, rtpTime); 635fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 636fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 637fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 638fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 639fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huberstatus_t RTPSink::connect( 640fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber const char *host, int32_t remoteRtpPort, int32_t remoteRtcpPort) { 641fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ALOGI("connecting RTP/RTCP sockets to %s:{%d,%d}", 642fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber host, remoteRtpPort, remoteRtcpPort); 643fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 644fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber status_t err = 645fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->connectUDPSession(mRTPSessionID, host, remoteRtpPort); 646fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 647fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (err != OK) { 648fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return err; 649fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 650fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 651fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber err = mNetSession->connectUDPSession(mRTCPSessionID, host, remoteRtcpPort); 652fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 653fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (err != OK) { 654fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return err; 655fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 656fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 657fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#if 0 658fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> buf = new ABuffer(1500); 659fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber memset(buf->data(), 0, buf->size()); 660fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 661fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->sendRequest( 662fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTPSessionID, buf->data(), buf->size()); 663fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 664fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->sendRequest( 665fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mRTCPSessionID, buf->data(), buf->size()); 666fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber#endif 667fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 668fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber scheduleSendRR(); 669fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 670fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber return OK; 671fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 672fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 673fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::scheduleSendRR() { 674fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber (new AMessage(kWhatSendRR, id()))->post(2000000ll); 675fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 676fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 677fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::addSDES(const sp<ABuffer> &buffer) { 678fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint8_t *data = buffer->data() + buffer->size(); 679fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[0] = 0x80 | 1; 680fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[1] = 202; // SDES 681fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[4] = 0xde; // SSRC 682fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[5] = 0xad; 683fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[6] = 0xbe; 684fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[7] = 0xef; 685fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 686fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t offset = 8; 687fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 688fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = 1; // CNAME 689fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 690fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber AString cname = "stagefright@somewhere"; 691fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = cname.size(); 692fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 693fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber memcpy(&data[offset], cname.c_str(), cname.size()); 694fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber offset += cname.size(); 695fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 696fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = 6; // TOOL 697fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 698fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber AString tool = "stagefright/1.0"; 699fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = tool.size(); 700fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 701fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber memcpy(&data[offset], tool.c_str(), tool.size()); 702fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber offset += tool.size(); 703fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 704fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = 0; 705fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 706fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if ((offset % 4) > 0) { 707fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t count = 4 - (offset % 4); 708fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber switch (count) { 709fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 3: 710fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = 0; 711fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 2: 712fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = 0; 713fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber case 1: 714fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[offset++] = 0; 715fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 716fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 717fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 718fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t numWords = (offset / 4) - 1; 719fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[2] = numWords >> 8; 720fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber data[3] = numWords & 0xff; 721fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 722fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buffer->setRange(buffer->offset(), buffer->size() + offset); 723fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 724fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 725fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::onSendRR() { 726fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> buf = new ABuffer(1500); 727fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buf->setRange(0, 0); 728fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 729fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint8_t *ptr = buf->data(); 730fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[0] = 0x80 | 0; 731fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[1] = 201; // RR 732fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[2] = 0; 733fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[3] = 1; 734fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[4] = 0xde; // SSRC 735fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[5] = 0xad; 736fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[6] = 0xbe; 737fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[7] = 0xef; 738fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 739fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buf->setRange(0, 8); 740fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 741fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t numReportBlocks = 0; 742fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber for (size_t i = 0; i < mSources.size(); ++i) { 743fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t ssrc = mSources.keyAt(i); 744fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<Source> source = mSources.valueAt(i); 745fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 746fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber if (numReportBlocks > 31 || buf->size() + 24 > buf->capacity()) { 747fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber // Cannot fit another report block. 748fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber break; 749fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 750fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 751fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber source->addReportBlock(ssrc, buf); 752fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ++numReportBlocks; 753fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber } 754fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 755fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[0] |= numReportBlocks; // 5 bit 756fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 757fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber size_t sizeInWordsMinus1 = 1 + 6 * numReportBlocks; 758fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[2] = sizeInWordsMinus1 >> 8; 759fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[3] = sizeInWordsMinus1 & 0xff; 760fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 761fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buf->setRange(0, (sizeInWordsMinus1 + 1) * 4); 762fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 763fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber addSDES(buf); 764fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 765fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size()); 766fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 767fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber scheduleSendRR(); 768fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 769fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 770fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Hubervoid RTPSink::onPacketLost(const sp<AMessage> &msg) { 771fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint32_t srcId; 772fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("ssrc", (int32_t *)&srcId)); 773fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 774fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t seqNo; 775fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber CHECK(msg->findInt32("seqNo", &seqNo)); 776fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 777fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber int32_t blp = 0; 778fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 779fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber sp<ABuffer> buf = new ABuffer(1500); 780fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buf->setRange(0, 0); 781fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 782fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber uint8_t *ptr = buf->data(); 783fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[0] = 0x80 | 1; // generic NACK 784fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[1] = 205; // RTPFB 785fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[2] = 0; 786fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[3] = 3; 787fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[4] = 0xde; // sender SSRC 788fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[5] = 0xad; 789fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[6] = 0xbe; 790fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[7] = 0xef; 791fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[8] = (srcId >> 24) & 0xff; 792fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[9] = (srcId >> 16) & 0xff; 793fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[10] = (srcId >> 8) & 0xff; 794fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[11] = (srcId & 0xff); 795fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[12] = (seqNo >> 8) & 0xff; 796fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[13] = (seqNo & 0xff); 797fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[14] = (blp >> 8) & 0xff; 798fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber ptr[15] = (blp & 0xff); 799fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 800fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber buf->setRange(0, 16); 801fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 802fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size()); 803fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} 804fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 805fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber} // namespace android 806fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96Andreas Huber 807