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 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2008 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(True),
00055     fNumChannels(numChannels) {
00056   fRTPPayloadFormatName
00057     = strDup(rtpPayloadFormatName == NULL ? "???" : rtpPayloadFormatName);
00058   gettimeofday(&fCreationTime, NULL);
00059   fTotalOctetCountStartTime = fCreationTime;
00060 
00061   fSeqNo = (u_int16_t)our_random();
00062   fSSRC = our_random32();
00063   fTimestampBase = our_random32();
00064 
00065   fTransmissionStatsDB = new RTPTransmissionStatsDB(*this);
00066 }
00067 
00068 RTPSink::~RTPSink() {
00069   delete fTransmissionStatsDB;
00070   delete[] (char*)fRTPPayloadFormatName;
00071 }
00072 
00073 u_int32_t RTPSink::convertToRTPTimestamp(struct timeval tv) {
00074   // Begin by converting from "struct timeval" units to RTP timestamp units:
00075   u_int32_t timestampIncrement = (fTimestampFrequency*tv.tv_sec);
00076   timestampIncrement += (u_int32_t)((2.0*fTimestampFrequency*tv.tv_usec + 1000000.0)/2000000);
00077        // 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 char const* RTPSink::sdpMediaType() const {
00121   return "data";
00122   // default SDP media (m=) type, unless redefined by subclasses
00123 }
00124 
00125 char* RTPSink::rtpmapLine() const {
00126   if (rtpPayloadType() >= 96) { // the payload format type is dynamic
00127     char* encodingParamsPart;
00128     if (numChannels() != 1) {
00129       encodingParamsPart = new char[1 + 20 /* max int len */];
00130       sprintf(encodingParamsPart, "/%d", numChannels());
00131     } else {
00132       encodingParamsPart = strDup("");
00133     }
00134     char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n";
00135     unsigned rtpmapFmtSize = strlen(rtpmapFmt)
00136       + 3 /* max char len */ + strlen(rtpPayloadFormatName())
00137       + 20 /* max int len */ + strlen(encodingParamsPart);
00138     char* rtpmapLine = new char[rtpmapFmtSize];
00139     sprintf(rtpmapLine, rtpmapFmt,
00140             rtpPayloadType(), rtpPayloadFormatName(),
00141             rtpTimestampFrequency(), encodingParamsPart);
00142     delete[] encodingParamsPart;
00143 
00144     return rtpmapLine;
00145   } else {
00146     // The payload format is staic, so there's no "a=rtpmap:" line:
00147     return strDup("");
00148   }
00149 }
00150 
00151 char const* RTPSink::auxSDPLine() {
00152   return NULL; // by default
00153 }
00154 
00155 
00157 
00158 RTPTransmissionStatsDB::RTPTransmissionStatsDB(RTPSink& rtpSink)
00159   : fOurRTPSink(rtpSink),
00160     fTable(HashTable::create(ONE_WORD_HASH_KEYS)) {
00161   fNumReceivers=0;
00162 }
00163 
00164 RTPTransmissionStatsDB::~RTPTransmissionStatsDB() {
00165   // First, remove and delete all stats records from the table:
00166   RTPTransmissionStats* stats;
00167   while ((stats = (RTPTransmissionStats*)fTable->RemoveNext()) != NULL) {
00168     delete stats;
00169   }
00170 
00171   // Then, delete the table itself:
00172   delete fTable;
00173 }
00174 
00175 void RTPTransmissionStatsDB
00176 ::noteIncomingRR(u_int32_t SSRC, struct sockaddr_in const& lastFromAddress,
00177                  unsigned lossStats, unsigned lastPacketNumReceived,
00178                  unsigned jitter, unsigned lastSRTime, unsigned diffSR_RRTime) {
00179   RTPTransmissionStats* stats = lookup(SSRC);
00180   if (stats == NULL) {
00181     // This is the first time we've heard of this SSRC.
00182     // Create a new record for it:
00183     stats = new RTPTransmissionStats(fOurRTPSink, SSRC);
00184     if (stats == NULL) return;
00185     add(SSRC, stats);
00186 #ifdef DEBUG_RR
00187     fprintf(stderr, "Adding new entry for SSRC %x in RTPTransmissionStatsDB\n", SSRC);
00188 #endif
00189   }
00190 
00191   stats->noteIncomingRR(lastFromAddress,
00192                         lossStats, lastPacketNumReceived, jitter,
00193                         lastSRTime, diffSR_RRTime);
00194 }
00195 
00196 void RTPTransmissionStatsDB::removeRecord(u_int32_t SSRC) {
00197   RTPTransmissionStats* stats = lookup(SSRC);
00198   if (stats != NULL) {
00199     long SSRC_long = (long)SSRC;
00200     fTable->Remove((char const*)SSRC_long);
00201     --fNumReceivers;
00202     delete stats;
00203   }
00204 }
00205 
00206 RTPTransmissionStatsDB::Iterator
00207 ::Iterator(RTPTransmissionStatsDB& receptionStatsDB)
00208   : fIter(HashTable::Iterator::create(*(receptionStatsDB.fTable))) {
00209 }
00210 
00211 RTPTransmissionStatsDB::Iterator::~Iterator() {
00212   delete fIter;
00213 }
00214 
00215 RTPTransmissionStats*
00216 RTPTransmissionStatsDB::Iterator::next() {
00217   char const* key; // dummy
00218  
00219   return (RTPTransmissionStats*)(fIter->next(key));
00220 }
00221 
00222 RTPTransmissionStats* RTPTransmissionStatsDB::lookup(u_int32_t SSRC) const {
00223   long SSRC_long = (long)SSRC;
00224   return (RTPTransmissionStats*)(fTable->Lookup((char const*)SSRC_long));
00225 }
00226 
00227 void RTPTransmissionStatsDB::add(u_int32_t SSRC, RTPTransmissionStats* stats) {
00228   long SSRC_long = (long)SSRC;
00229   fTable->Add((char const*)SSRC_long, stats);
00230   ++fNumReceivers;
00231 }
00232 
00233 
00235 
00236 RTPTransmissionStats::RTPTransmissionStats(RTPSink& rtpSink, u_int32_t SSRC)
00237   : fOurRTPSink(rtpSink), fSSRC(SSRC), fLastPacketNumReceived(0),
00238     fPacketLossRatio(0), fTotNumPacketsLost(0), fJitter(0),
00239     fLastSRTime(0), fDiffSR_RRTime(0), fFirstPacket(True),
00240     fTotalOctetCount_hi(0), fTotalOctetCount_lo(0), 
00241     fTotalPacketCount_hi(0), fTotalPacketCount_lo(0) {
00242   gettimeofday(&fTimeCreated, NULL);
00243 
00244   fLastOctetCount = rtpSink.octetCount();
00245   fLastPacketCount = rtpSink.packetCount();
00246 }
00247 
00248 RTPTransmissionStats::~RTPTransmissionStats() {}
00249 
00250 void RTPTransmissionStats
00251 ::noteIncomingRR(struct sockaddr_in const& lastFromAddress,
00252                  unsigned lossStats, unsigned lastPacketNumReceived,
00253                  unsigned jitter, unsigned lastSRTime,
00254                  unsigned diffSR_RRTime) {
00255   if (fFirstPacket) {
00256     fFirstPacket = False;
00257     fFirstPacketNumReported = lastPacketNumReceived;
00258   } else {
00259     fOldValid = True;
00260     fOldLastPacketNumReceived = fLastPacketNumReceived;
00261     fOldTotNumPacketsLost = fTotNumPacketsLost;
00262   }
00263   gettimeofday(&fTimeReceived, NULL);
00264 
00265   fLastFromAddress = lastFromAddress;
00266   fPacketLossRatio = lossStats>>24;
00267   fTotNumPacketsLost = lossStats&0xFFFFFF;
00268   fLastPacketNumReceived = lastPacketNumReceived;
00269   fJitter = jitter;
00270   fLastSRTime = lastSRTime;
00271   fDiffSR_RRTime = diffSR_RRTime;
00272 #ifdef DEBUG_RR
00273   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",
00274           fTimeReceived.tv_sec, fTimeReceived.tv_usec, lossStats, lastPacketNumReceived, jitter, lastSRTime, diffSR_RRTime);
00275   unsigned rtd = roundTripDelay(); 
00276   fprintf(stderr, "=> round-trip delay: 0x%04x (== %f seconds)\n", rtd, rtd/65536.0);
00277 #endif
00278 
00279   // Update our counts of the total number of octets and packets sent towards
00280   // this receiver:
00281   u_int32_t newOctetCount = fOurRTPSink.octetCount();
00282   u_int32_t octetCountDiff = newOctetCount - fLastOctetCount;
00283   fLastOctetCount = newOctetCount;
00284   u_int32_t prevTotalOctetCount_lo = fTotalOctetCount_lo;
00285   fTotalOctetCount_lo += octetCountDiff;
00286   if (fTotalOctetCount_lo < prevTotalOctetCount_lo) { // wrap around
00287     ++fTotalOctetCount_hi;
00288   }
00289 
00290   u_int32_t newPacketCount = fOurRTPSink.packetCount();
00291   u_int32_t packetCountDiff = newPacketCount - fLastPacketCount;
00292   fLastPacketCount = newPacketCount;
00293   u_int32_t prevTotalPacketCount_lo = fTotalPacketCount_lo;
00294   fTotalPacketCount_lo += packetCountDiff;
00295   if (fTotalPacketCount_lo < prevTotalPacketCount_lo) { // wrap around
00296     ++fTotalPacketCount_hi;
00297   }
00298 }
00299 
00300 unsigned RTPTransmissionStats::roundTripDelay() const {
00301   // Compute the round-trip delay that was indicated by the most recently-received
00302   // RTCP RR packet.  Use the method noted in the RTP/RTCP specification (RFC 3350).
00303   
00304   if (fLastSRTime == 0) {
00305     // Either no RTCP RR packet has been received yet, or else the
00306     // reporting receiver has not yet received any RTCP SR packets from us:
00307     return 0;
00308   }
00309 
00310   // First, convert the time that we received the last RTCP RR packet to NTP format,
00311   // in units of 1/65536 (2^-16) seconds:
00312   unsigned lastReceivedTimeNTP_high
00313     = fTimeReceived.tv_sec + 0x83AA7E80; // 1970 epoch -> 1900 epoch
00314   double fractionalPart = (fTimeReceived.tv_usec*0x0400)/15625.0; // 2^16/10^6
00315   unsigned lastReceivedTimeNTP
00316     = (unsigned)((lastReceivedTimeNTP_high<<16) + fractionalPart + 0.5);
00317 
00318   int rawResult = lastReceivedTimeNTP - fLastSRTime - fDiffSR_RRTime;
00319   if (rawResult < 0) {
00320     // This can happen if there's clock drift between the sender and receiver,
00321     // and if the round-trip time was very small.
00322     rawResult = 0;
00323   }
00324   return (unsigned)rawResult;
00325 }
00326 
00327 void RTPTransmissionStats::getTotalOctetCount(u_int32_t& hi, u_int32_t& lo) {
00328   hi = fTotalOctetCount_hi;
00329   lo = fTotalOctetCount_lo;
00330 }
00331 
00332 void RTPTransmissionStats::getTotalPacketCount(u_int32_t& hi, u_int32_t& lo) {
00333   hi = fTotalPacketCount_hi;
00334   lo = fTotalPacketCount_lo;
00335 }
00336 
00337 unsigned RTPTransmissionStats::packetsReceivedSinceLastRR() const {
00338   if (!fOldValid) return 0;
00339 
00340   return fLastPacketNumReceived-fOldLastPacketNumReceived;
00341 }
00342 
00343 int RTPTransmissionStats::packetsLostBetweenRR() const {
00344   if (!fOldValid) return 0;
00345 
00346   return fTotNumPacketsLost - fOldTotNumPacketsLost;
00347 }

Generated on Tue Jul 22 06:39:06 2008 for live by  doxygen 1.5.2