liveMedia/RTPSink.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // RTP Sinks
00019 // Implementation
00020 
00021 #include "RTPSink.hh"
00022 #include "GroupsockHelper.hh"
00023 
00025 
00026 Boolean RTPSink::lookupByName(UsageEnvironment& env, char const* sinkName,
00027                                 RTPSink*& resultSink) {
00028   resultSink = NULL; // unless we succeed
00029 
00030   MediaSink* sink;
00031   if (!MediaSink::lookupByName(env, sinkName, sink)) return False;
00032 
00033   if (!sink->isRTPSink()) {
00034     env.setResultMsg(sinkName, " is not a RTP sink");
00035     return False;
00036   }
00037 
00038   resultSink = (RTPSink*)sink;
00039   return True;
00040 }
00041 
00042 Boolean RTPSink::isRTPSink() const {
00043   return True;
00044 }
00045 
00046 RTPSink::RTPSink(UsageEnvironment& env,
00047                  Groupsock* rtpGS, unsigned char rtpPayloadType,
00048                  unsigned rtpTimestampFrequency,
00049                  char const* rtpPayloadFormatName,
00050                  unsigned numChannels)
00051   : MediaSink(env), fRTPInterface(this, rtpGS),
00052     fRTPPayloadType(rtpPayloadType),
00053     fPacketCount(0), fOctetCount(0), fTotalOctetCount(0),
00054     fTimestampFrequency(rtpTimestampFrequency), fNextTimestampHasBeenPreset(False), fEnableRTCPReports(True),
00055     fNumChannels(numChannels) {
00056   fRTPPayloadFormatName
00057     = strDup(rtpPayloadFormatName == NULL ? "???" : rtpPayloadFormatName);
00058   gettimeofday(&fCreationTime, NULL);
00059   fTotalOctetCountStartTime = fCreationTime;
00060   resetPresentationTimes();
00061 
00062   fSeqNo = (u_int16_t)our_random();
00063   fSSRC = our_random32();
00064   fTimestampBase = our_random32();
00065 
00066   fTransmissionStatsDB = new RTPTransmissionStatsDB(*this);
00067 }
00068 
00069 RTPSink::~RTPSink() {
00070   delete fTransmissionStatsDB;
00071   delete[] (char*)fRTPPayloadFormatName;
00072 }
00073 
00074 u_int32_t RTPSink::convertToRTPTimestamp(struct timeval tv) {
00075   // Begin by converting from "struct timeval" units to RTP timestamp units:
00076   u_int32_t timestampIncrement = (fTimestampFrequency*tv.tv_sec);
00077   timestampIncrement += (u_int32_t)(fTimestampFrequency*(tv.tv_usec/1000000.0) + 0.5); // note: rounding
00078 
00079   // Then add this to our 'timestamp base':
00080   if (fNextTimestampHasBeenPreset) {
00081     // Make the returned timestamp the same as the current "fTimestampBase",
00082     // so that timestamps begin with the value that was previously preset:
00083     fTimestampBase -= timestampIncrement;
00084     fNextTimestampHasBeenPreset = False;
00085   }
00086 
00087   u_int32_t const rtpTimestamp = fTimestampBase + timestampIncrement;
00088 #ifdef DEBUG_TIMESTAMPS
00089   fprintf(stderr, "fTimestampBase: 0x%08x, tv: %lu.%06ld\n\t=> RTP timestamp: 0x%08x\n",
00090           fTimestampBase, tv.tv_sec, tv.tv_usec, rtpTimestamp);
00091   fflush(stderr);
00092 #endif
00093 
00094   return rtpTimestamp;
00095 }
00096 
00097 u_int32_t RTPSink::presetNextTimestamp() {
00098   struct timeval timeNow;
00099   gettimeofday(&timeNow, NULL);
00100 
00101   u_int32_t tsNow = convertToRTPTimestamp(timeNow);
00102   fTimestampBase = tsNow;
00103   fNextTimestampHasBeenPreset = True;
00104 
00105   return tsNow;
00106 }
00107 
00108 void RTPSink::getTotalBitrate(unsigned& outNumBytes, double& outElapsedTime) {
00109   struct timeval timeNow;
00110   gettimeofday(&timeNow, NULL);
00111 
00112   outNumBytes = fTotalOctetCount;
00113   outElapsedTime = (double)(timeNow.tv_sec-fTotalOctetCountStartTime.tv_sec)
00114     + (timeNow.tv_usec-fTotalOctetCountStartTime.tv_usec)/1000000.0;
00115 
00116   fTotalOctetCount = 0;
00117   fTotalOctetCountStartTime = timeNow;
00118 }
00119 
00120 void RTPSink::resetPresentationTimes() {
00121   fInitialPresentationTime.tv_sec = fMostRecentPresentationTime.tv_sec = 0;
00122   fInitialPresentationTime.tv_usec = fMostRecentPresentationTime.tv_usec = 0;
00123 }
00124 
00125 char const* RTPSink::sdpMediaType() const {
00126   return "data";
00127   // default SDP media (m=) type, unless redefined by subclasses
00128 }
00129 
00130 char* RTPSink::rtpmapLine() const {
00131   if (rtpPayloadType() >= 96) { // the payload format type is dynamic
00132     char* encodingParamsPart;
00133     if (numChannels() != 1) {
00134       encodingParamsPart = new char[1 + 20 /* max int len */];
00135       sprintf(encodingParamsPart, "/%d", numChannels());
00136     } else {
00137       encodingParamsPart = strDup("");
00138     }
00139     char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n";
00140     unsigned rtpmapFmtSize = strlen(rtpmapFmt)
00141       + 3 /* max char len */ + strlen(rtpPayloadFormatName())
00142       + 20 /* max int len */ + strlen(encodingParamsPart);
00143     char* rtpmapLine = new char[rtpmapFmtSize];
00144     sprintf(rtpmapLine, rtpmapFmt,
00145             rtpPayloadType(), rtpPayloadFormatName(),
00146             rtpTimestampFrequency(), encodingParamsPart);
00147     delete[] encodingParamsPart;
00148 
00149     return rtpmapLine;
00150   } else {
00151     // The payload format is staic, so there's no "a=rtpmap:" line:
00152     return strDup("");
00153   }
00154 }
00155 
00156 char const* RTPSink::auxSDPLine() {
00157   return NULL; // by default
00158 }
00159 
00160 
00162 
00163 RTPTransmissionStatsDB::RTPTransmissionStatsDB(RTPSink& rtpSink)
00164   : fOurRTPSink(rtpSink),
00165     fTable(HashTable::create(ONE_WORD_HASH_KEYS)) {
00166   fNumReceivers=0;
00167 }
00168 
00169 RTPTransmissionStatsDB::~RTPTransmissionStatsDB() {
00170   // First, remove and delete all stats records from the table:
00171   RTPTransmissionStats* stats;
00172   while ((stats = (RTPTransmissionStats*)fTable->RemoveNext()) != NULL) {
00173     delete stats;
00174   }
00175 
00176   // Then, delete the table itself:
00177   delete fTable;
00178 }
00179 
00180 void RTPTransmissionStatsDB
00181 ::noteIncomingRR(u_int32_t SSRC, struct sockaddr_in const& lastFromAddress,
00182                  unsigned lossStats, unsigned lastPacketNumReceived,
00183                  unsigned jitter, unsigned lastSRTime, unsigned diffSR_RRTime) {
00184   RTPTransmissionStats* stats = lookup(SSRC);
00185   if (stats == NULL) {
00186     // This is the first time we've heard of this SSRC.
00187     // Create a new record for it:
00188     stats = new RTPTransmissionStats(fOurRTPSink, SSRC);
00189     if (stats == NULL) return;
00190     add(SSRC, stats);
00191 #ifdef DEBUG_RR
00192     fprintf(stderr, "Adding new entry for SSRC %x in RTPTransmissionStatsDB\n", SSRC);
00193 #endif
00194   }
00195 
00196   stats->noteIncomingRR(lastFromAddress,
00197                         lossStats, lastPacketNumReceived, jitter,
00198                         lastSRTime, diffSR_RRTime);
00199 }
00200 
00201 void RTPTransmissionStatsDB::removeRecord(u_int32_t SSRC) {
00202   RTPTransmissionStats* stats = lookup(SSRC);
00203   if (stats != NULL) {
00204     long SSRC_long = (long)SSRC;
00205     fTable->Remove((char const*)SSRC_long);
00206     --fNumReceivers;
00207     delete stats;
00208   }
00209 }
00210 
00211 RTPTransmissionStatsDB::Iterator
00212 ::Iterator(RTPTransmissionStatsDB& receptionStatsDB)
00213   : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) {
00214 }
00215 
00216 RTPTransmissionStatsDB::Iterator::~Iterator() {
00217   delete fIter;
00218 }
00219 
00220 RTPTransmissionStats*
00221 RTPTransmissionStatsDB::Iterator::next() {
00222   char const* key; // dummy
00223 
00224   return (RTPTransmissionStats*)(fIter->next(key));
00225 }
00226 
00227 RTPTransmissionStats* RTPTransmissionStatsDB::lookup(u_int32_t SSRC) const {
00228   long SSRC_long = (long)SSRC;
00229   return (RTPTransmissionStats*)(fTable->Lookup((char const*)SSRC_long));
00230 }
00231 
00232 void RTPTransmissionStatsDB::add(u_int32_t SSRC, RTPTransmissionStats* stats) {
00233   long SSRC_long = (long)SSRC;
00234   fTable->Add((char const*)SSRC_long, stats);
00235   ++fNumReceivers;
00236 }
00237 
00238 
00240 
00241 RTPTransmissionStats::RTPTransmissionStats(RTPSink& rtpSink, u_int32_t SSRC)
00242   : fOurRTPSink(rtpSink), fSSRC(SSRC), fLastPacketNumReceived(0),
00243     fPacketLossRatio(0), fTotNumPacketsLost(0), fJitter(0),
00244     fLastSRTime(0), fDiffSR_RRTime(0), fAtLeastTwoRRsHaveBeenReceived(False), fFirstPacket(True),
00245     fTotalOctetCount_hi(0), fTotalOctetCount_lo(0),
00246     fTotalPacketCount_hi(0), fTotalPacketCount_lo(0) {
00247   gettimeofday(&fTimeCreated, NULL);
00248 
00249   fLastOctetCount = rtpSink.octetCount();
00250   fLastPacketCount = rtpSink.packetCount();
00251 }
00252 
00253 RTPTransmissionStats::~RTPTransmissionStats() {}
00254 
00255 void RTPTransmissionStats
00256 ::noteIncomingRR(struct sockaddr_in const& lastFromAddress,
00257                  unsigned lossStats, unsigned lastPacketNumReceived,
00258                  unsigned jitter, unsigned lastSRTime,
00259                  unsigned diffSR_RRTime) {
00260   if (fFirstPacket) {
00261     fFirstPacket = False;
00262     fFirstPacketNumReported = lastPacketNumReceived;
00263   } else {
00264     fAtLeastTwoRRsHaveBeenReceived = True;
00265     fOldLastPacketNumReceived = fLastPacketNumReceived;
00266     fOldTotNumPacketsLost = fTotNumPacketsLost;
00267   }
00268   gettimeofday(&fTimeReceived, NULL);
00269 
00270   fLastFromAddress = lastFromAddress;
00271   fPacketLossRatio = lossStats>>24;
00272   fTotNumPacketsLost = lossStats&0xFFFFFF;
00273   fLastPacketNumReceived = lastPacketNumReceived;
00274   fJitter = jitter;
00275   fLastSRTime = lastSRTime;
00276   fDiffSR_RRTime = diffSR_RRTime;
00277 #ifdef DEBUG_RR
00278   fprintf(stderr, "RTCP RR data (received at %lu.%06ld): lossStats 0x%08x, lastPacketNumReceived 0x%08x, jitter 0x%08x, lastSRTime 0x%08x, diffSR_RRTime 0x%08x\n",
00279           fTimeReceived.tv_sec, fTimeReceived.tv_usec, lossStats, lastPacketNumReceived, jitter, lastSRTime, diffSR_RRTime);
00280   unsigned rtd = roundTripDelay();
00281   fprintf(stderr, "=> round-trip delay: 0x%04x (== %f seconds)\n", rtd, rtd/65536.0);
00282 #endif
00283 
00284   // Update our counts of the total number of octets and packets sent towards
00285   // this receiver:
00286   u_int32_t newOctetCount = fOurRTPSink.octetCount();
00287   u_int32_t octetCountDiff = newOctetCount - fLastOctetCount;
00288   fLastOctetCount = newOctetCount;
00289   u_int32_t prevTotalOctetCount_lo = fTotalOctetCount_lo;
00290   fTotalOctetCount_lo += octetCountDiff;
00291   if (fTotalOctetCount_lo < prevTotalOctetCount_lo) { // wrap around
00292     ++fTotalOctetCount_hi;
00293   }
00294 
00295   u_int32_t newPacketCount = fOurRTPSink.packetCount();
00296   u_int32_t packetCountDiff = newPacketCount - fLastPacketCount;
00297   fLastPacketCount = newPacketCount;
00298   u_int32_t prevTotalPacketCount_lo = fTotalPacketCount_lo;
00299   fTotalPacketCount_lo += packetCountDiff;
00300   if (fTotalPacketCount_lo < prevTotalPacketCount_lo) { // wrap around
00301     ++fTotalPacketCount_hi;
00302   }
00303 }
00304 
00305 unsigned RTPTransmissionStats::roundTripDelay() const {
00306   // Compute the round-trip delay that was indicated by the most recently-received
00307   // RTCP RR packet.  Use the method noted in the RTP/RTCP specification (RFC 3350).
00308 
00309   if (fLastSRTime == 0) {
00310     // Either no RTCP RR packet has been received yet, or else the
00311     // reporting receiver has not yet received any RTCP SR packets from us:
00312     return 0;
00313   }
00314 
00315   // First, convert the time that we received the last RTCP RR packet to NTP format,
00316   // in units of 1/65536 (2^-16) seconds:
00317   unsigned lastReceivedTimeNTP_high
00318     = fTimeReceived.tv_sec + 0x83AA7E80; // 1970 epoch -> 1900 epoch
00319   double fractionalPart = (fTimeReceived.tv_usec*0x0400)/15625.0; // 2^16/10^6
00320   unsigned lastReceivedTimeNTP
00321     = (unsigned)((lastReceivedTimeNTP_high<<16) + fractionalPart + 0.5);
00322 
00323   int rawResult = lastReceivedTimeNTP - fLastSRTime - fDiffSR_RRTime;
00324   if (rawResult < 0) {
00325     // This can happen if there's clock drift between the sender and receiver,
00326     // and if the round-trip time was very small.
00327     rawResult = 0;
00328   }
00329   return (unsigned)rawResult;
00330 }
00331 
00332 void RTPTransmissionStats::getTotalOctetCount(u_int32_t& hi, u_int32_t& lo) {
00333   hi = fTotalOctetCount_hi;
00334   lo = fTotalOctetCount_lo;
00335 }
00336 
00337 void RTPTransmissionStats::getTotalPacketCount(u_int32_t& hi, u_int32_t& lo) {
00338   hi = fTotalPacketCount_hi;
00339   lo = fTotalPacketCount_lo;
00340 }
00341 
00342 unsigned RTPTransmissionStats::packetsReceivedSinceLastRR() const {
00343   if (!fAtLeastTwoRRsHaveBeenReceived) return 0;
00344 
00345   return fLastPacketNumReceived-fOldLastPacketNumReceived;
00346 }
00347 
00348 int RTPTransmissionStats::packetsLostBetweenRR() const {
00349   if (!fAtLeastTwoRRsHaveBeenReceived) return 0;
00350 
00351   return fTotNumPacketsLost - fOldTotNumPacketsLost;
00352 }

Generated on Mon Apr 29 13:28:03 2013 for live by  doxygen 1.5.2