liveMedia/PassiveServerMediaSubsession.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-2014 Live Networks, Inc.  All rights reserved.
00018 // A 'ServerMediaSubsession' object that represents an existing
00019 // 'RTPSink', rather than one that creates new 'RTPSink's on demand.
00020 // Implementation
00021 
00022 #include "PassiveServerMediaSubsession.hh"
00023 #include <GroupsockHelper.hh>
00024 
00026 
00027 PassiveServerMediaSubsession*
00028 PassiveServerMediaSubsession::createNew(RTPSink& rtpSink,
00029                                         RTCPInstance* rtcpInstance) {
00030   return new PassiveServerMediaSubsession(rtpSink, rtcpInstance);
00031 }
00032 
00033 PassiveServerMediaSubsession
00034 ::PassiveServerMediaSubsession(RTPSink& rtpSink, RTCPInstance* rtcpInstance)
00035   : ServerMediaSubsession(rtpSink.envir()),
00036     fSDPLines(NULL), fRTPSink(rtpSink), fRTCPInstance(rtcpInstance) {
00037   fClientRTCPSourceRecords = HashTable::create(ONE_WORD_HASH_KEYS);
00038 }
00039 
00040 class RTCPSourceRecord {
00041 public:
00042   RTCPSourceRecord(netAddressBits addr, Port const& port)
00043     : addr(addr), port(port) {
00044   }
00045 
00046   netAddressBits addr;
00047   Port port;
00048 };
00049 
00050 PassiveServerMediaSubsession::~PassiveServerMediaSubsession() {
00051   delete[] fSDPLines;
00052 
00053   // Clean out the RTCPSourceRecord table:
00054   while (1) {
00055     RTCPSourceRecord* source = (RTCPSourceRecord*)(fClientRTCPSourceRecords->RemoveNext());
00056     if (source == NULL) break;
00057     delete source;
00058   }
00059 
00060   delete fClientRTCPSourceRecords;
00061 }
00062 
00063 Boolean PassiveServerMediaSubsession::rtcpIsMuxed() {
00064   if (fRTCPInstance == NULL) return False;
00065 
00066   // Check whether RTP and RTCP use the same "groupsock" object:
00067   return &(fRTPSink.groupsockBeingUsed()) == fRTCPInstance->RTCPgs();
00068 }
00069 
00070 char const*
00071 PassiveServerMediaSubsession::sdpLines() {
00072   if (fSDPLines == NULL ) {
00073     // Construct a set of SDP lines that describe this subsession:
00074     // Use the components from "rtpSink":
00075     Groupsock const& gs = fRTPSink.groupsockBeingUsed();
00076     AddressString groupAddressStr(gs.groupAddress());
00077     unsigned short portNum = ntohs(gs.port().num());
00078     unsigned char ttl = gs.ttl();
00079     unsigned char rtpPayloadType = fRTPSink.rtpPayloadType();
00080     char const* mediaType = fRTPSink.sdpMediaType();
00081     unsigned estBitrate
00082       = fRTCPInstance == NULL ? 50 : fRTCPInstance->totSessionBW();
00083     char* rtpmapLine = fRTPSink.rtpmapLine();
00084     char const* rtcpmuxLine = rtcpIsMuxed() ? "a=rtcp-mux\r\n" : "";
00085     char const* rangeLine = rangeSDPLine();
00086     char const* auxSDPLine = fRTPSink.auxSDPLine();
00087     if (auxSDPLine == NULL) auxSDPLine = "";
00088 
00089     char const* const sdpFmt =
00090       "m=%s %d RTP/AVP %d\r\n"
00091       "c=IN IP4 %s/%d\r\n"
00092       "b=AS:%u\r\n"
00093       "%s"
00094       "%s"
00095       "%s"
00096       "%s"
00097       "a=control:%s\r\n";
00098     unsigned sdpFmtSize = strlen(sdpFmt)
00099       + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */
00100       + strlen(groupAddressStr.val()) + 3 /* max char len */
00101       + 20 /* max int len */
00102       + strlen(rtpmapLine)
00103       + strlen(rtcpmuxLine)
00104       + strlen(rangeLine)
00105       + strlen(auxSDPLine)
00106       + strlen(trackId());
00107     char* sdpLines = new char[sdpFmtSize];
00108     sprintf(sdpLines, sdpFmt,
00109             mediaType, // m= <media>
00110             portNum, // m= <port>
00111             rtpPayloadType, // m= <fmt list>
00112             groupAddressStr.val(), // c= <connection address>
00113             ttl, // c= TTL
00114             estBitrate, // b=AS:<bandwidth>
00115             rtpmapLine, // a=rtpmap:... (if present)
00116             rtcpmuxLine, // a=rtcp-mux:... (if present)
00117             rangeLine, // a=range:... (if present)
00118             auxSDPLine, // optional extra SDP line
00119             trackId()); // a=control:<track-id>
00120     delete[] (char*)rangeLine; delete[] rtpmapLine;
00121 
00122     fSDPLines = strDup(sdpLines);
00123     delete[] sdpLines;
00124   }
00125 
00126   return fSDPLines;
00127 }
00128 
00129 void PassiveServerMediaSubsession
00130 ::getStreamParameters(unsigned clientSessionId,
00131                       netAddressBits clientAddress,
00132                       Port const& /*clientRTPPort*/,
00133                       Port const& clientRTCPPort,
00134                       int /*tcpSocketNum*/,
00135                       unsigned char /*rtpChannelId*/,
00136                       unsigned char /*rtcpChannelId*/,
00137                       netAddressBits& destinationAddress,
00138                       u_int8_t& destinationTTL,
00139                       Boolean& isMulticast,
00140                       Port& serverRTPPort,
00141                       Port& serverRTCPPort,
00142                       void*& streamToken) {
00143   isMulticast = True;
00144   Groupsock& gs = fRTPSink.groupsockBeingUsed();
00145   if (destinationTTL == 255) destinationTTL = gs.ttl();
00146   if (destinationAddress == 0) { // normal case
00147     destinationAddress = gs.groupAddress().s_addr;
00148   } else { // use the client-specified destination address instead:
00149     struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress;
00150     gs.changeDestinationParameters(destinationAddr, 0, destinationTTL);
00151     if (fRTCPInstance != NULL) {
00152       Groupsock* rtcpGS = fRTCPInstance->RTCPgs();
00153       rtcpGS->changeDestinationParameters(destinationAddr, 0, destinationTTL);
00154     }
00155   }
00156   serverRTPPort = gs.port();
00157   if (fRTCPInstance != NULL) {
00158     Groupsock* rtcpGS = fRTCPInstance->RTCPgs();
00159     serverRTCPPort = rtcpGS->port();
00160   }
00161   streamToken = NULL; // not used
00162 
00163   // Make a record of this client's source - for RTCP RR handling:
00164   RTCPSourceRecord* source = new RTCPSourceRecord(clientAddress, clientRTCPPort);
00165   fClientRTCPSourceRecords->Add((char const*)clientSessionId, source);
00166 }
00167 
00168 void PassiveServerMediaSubsession::startStream(unsigned clientSessionId,
00169                                                void* /*streamToken*/,
00170                                                TaskFunc* rtcpRRHandler,
00171                                                void* rtcpRRHandlerClientData,
00172                                                unsigned short& rtpSeqNum,
00173                                                unsigned& rtpTimestamp,
00174                                                ServerRequestAlternativeByteHandler* /*serverRequestAlternativeByteHandler*/,
00175                                                void* /*serverRequestAlternativeByteHandlerClientData*/) {
00176   rtpSeqNum = fRTPSink.currentSeqNo();
00177   rtpTimestamp = fRTPSink.presetNextTimestamp();
00178 
00179   // Try to use a big send buffer for RTP -  at least 0.1 second of
00180   // specified bandwidth and at least 50 KB
00181   unsigned streamBitrate = fRTCPInstance == NULL ? 50 : fRTCPInstance->totSessionBW(); // in kbps
00182   unsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
00183   if (rtpBufSize < 50 * 1024) rtpBufSize = 50 * 1024;
00184   increaseSendBufferTo(envir(), fRTPSink.groupsockBeingUsed().socketNum(), rtpBufSize);
00185 
00186   if (fRTCPInstance != NULL) {
00187     // Hack: Send a RTCP "SR" packet now, so that receivers will (likely) be able to
00188     // get RTCP-synchronized presentation times immediately:
00189     fRTCPInstance->sendReport();
00190 
00191     // Set up the handler for incoming RTCP "RR" packets from this client:
00192     RTCPSourceRecord* source = (RTCPSourceRecord*)(fClientRTCPSourceRecords->Lookup((char const*)clientSessionId));
00193     if (source != NULL) {
00194       fRTCPInstance->setSpecificRRHandler(source->addr, source->port,
00195                                           rtcpRRHandler, rtcpRRHandlerClientData);
00196     }
00197   }
00198 }
00199 
00200 float PassiveServerMediaSubsession::getCurrentNPT(void* streamToken) {
00201   // Return the elapsed time between our "RTPSink"s creation time, and the current time:
00202   struct timeval const& creationTime  = fRTPSink.creationTime(); // alias
00203 
00204   struct timeval timeNow;
00205   gettimeofday(&timeNow, NULL);
00206 
00207   return (float)(timeNow.tv_sec - creationTime.tv_sec + (timeNow.tv_usec - creationTime.tv_usec)/1000000.0);
00208 }
00209 
00210 void PassiveServerMediaSubsession::deleteStream(unsigned clientSessionId, void*& /*streamToken*/) {
00211   // Lookup and remove the 'RTCPSourceRecord' for this client.  Also turn off RTCP "RR" handling:
00212   RTCPSourceRecord* source = (RTCPSourceRecord*)(fClientRTCPSourceRecords->Lookup((char const*)clientSessionId));
00213   if (source != NULL) {
00214     if (fRTCPInstance != NULL) {
00215       fRTCPInstance->unsetSpecificRRHandler(source->addr, source->port);
00216     }
00217 
00218     fClientRTCPSourceRecords->Remove((char const*)clientSessionId);
00219     delete source;
00220   }
00221 }

Generated on Tue Mar 25 14:35:36 2014 for live by  doxygen 1.5.2