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-2012 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 char const*
00064 PassiveServerMediaSubsession::sdpLines() {
00065   if (fSDPLines == NULL ) {
00066     // Construct a set of SDP lines that describe this subsession:
00067     // Use the components from "rtpSink":
00068     Groupsock const& gs = fRTPSink.groupsockBeingUsed();
00069     AddressString groupAddressStr(gs.groupAddress());
00070     unsigned short portNum = ntohs(gs.port().num());
00071     unsigned char ttl = gs.ttl();
00072     unsigned char rtpPayloadType = fRTPSink.rtpPayloadType();
00073     char const* mediaType = fRTPSink.sdpMediaType();
00074     unsigned estBitrate
00075       = fRTCPInstance == NULL ? 50 : fRTCPInstance->totSessionBW();
00076     char* rtpmapLine = fRTPSink.rtpmapLine();
00077     char const* rangeLine = rangeSDPLine();
00078     char const* auxSDPLine = fRTPSink.auxSDPLine();
00079     if (auxSDPLine == NULL) auxSDPLine = "";
00080 
00081     char const* const sdpFmt =
00082       "m=%s %d RTP/AVP %d\r\n"
00083       "c=IN IP4 %s/%d\r\n"
00084       "b=AS:%u\r\n"
00085       "%s"
00086       "%s"
00087       "%s"
00088       "a=control:%s\r\n";
00089     unsigned sdpFmtSize = strlen(sdpFmt)
00090       + strlen(mediaType) + 5 /* max short len */ + 3 /* max char len */
00091       + strlen(groupAddressStr.val()) + 3 /* max char len */
00092       + 20 /* max int len */
00093       + strlen(rtpmapLine)
00094       + strlen(rangeLine)
00095       + strlen(auxSDPLine)
00096       + strlen(trackId());
00097     char* sdpLines = new char[sdpFmtSize];
00098     sprintf(sdpLines, sdpFmt,
00099             mediaType, // m= <media>
00100             portNum, // m= <port>
00101             rtpPayloadType, // m= <fmt list>
00102             groupAddressStr.val(), // c= <connection address>
00103             ttl, // c= TTL
00104             estBitrate, // b=AS:<bandwidth>
00105             rtpmapLine, // a=rtpmap:... (if present)
00106             rangeLine, // a=range:... (if present)
00107             auxSDPLine, // optional extra SDP line
00108             trackId()); // a=control:<track-id>
00109     delete[] (char*)rangeLine; delete[] rtpmapLine;
00110 
00111     fSDPLines = strDup(sdpLines);
00112     delete[] sdpLines;
00113   }
00114 
00115   return fSDPLines;
00116 }
00117 
00118 void PassiveServerMediaSubsession
00119 ::getStreamParameters(unsigned clientSessionId,
00120                       netAddressBits clientAddress,
00121                       Port const& /*clientRTPPort*/,
00122                       Port const& clientRTCPPort,
00123                       int /*tcpSocketNum*/,
00124                       unsigned char /*rtpChannelId*/,
00125                       unsigned char /*rtcpChannelId*/,
00126                       netAddressBits& destinationAddress,
00127                       u_int8_t& destinationTTL,
00128                       Boolean& isMulticast,
00129                       Port& serverRTPPort,
00130                       Port& serverRTCPPort,
00131                       void*& streamToken) {
00132   isMulticast = True;
00133   Groupsock& gs = fRTPSink.groupsockBeingUsed();
00134   if (destinationTTL == 255) destinationTTL = gs.ttl();
00135   if (destinationAddress == 0) { // normal case
00136     destinationAddress = gs.groupAddress().s_addr;
00137   } else { // use the client-specified destination address instead:
00138     struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress;
00139     gs.changeDestinationParameters(destinationAddr, 0, destinationTTL);
00140     if (fRTCPInstance != NULL) {
00141       Groupsock* rtcpGS = fRTCPInstance->RTCPgs();
00142       rtcpGS->changeDestinationParameters(destinationAddr, 0, destinationTTL);
00143     }
00144   }
00145   serverRTPPort = gs.port();
00146   if (fRTCPInstance != NULL) {
00147     Groupsock* rtcpGS = fRTCPInstance->RTCPgs();
00148     serverRTCPPort = rtcpGS->port();
00149   }
00150   streamToken = NULL; // not used
00151 
00152   // Make a record of this client's source - for RTCP RR handling:
00153   RTCPSourceRecord* source = new RTCPSourceRecord(clientAddress, clientRTCPPort);
00154   fClientRTCPSourceRecords->Add((char const*)clientSessionId, source);
00155 }
00156 
00157 void PassiveServerMediaSubsession::startStream(unsigned clientSessionId,
00158                                                void* /*streamToken*/,
00159                                                TaskFunc* rtcpRRHandler,
00160                                                void* rtcpRRHandlerClientData,
00161                                                unsigned short& rtpSeqNum,
00162                                                unsigned& rtpTimestamp,
00163                                                ServerRequestAlternativeByteHandler* /*serverRequestAlternativeByteHandler*/,
00164                                                void* /*serverRequestAlternativeByteHandlerClientData*/) {
00165   rtpSeqNum = fRTPSink.currentSeqNo();
00166   rtpTimestamp = fRTPSink.presetNextTimestamp();
00167 
00168   // Try to use a big send buffer for RTP -  at least 0.1 second of
00169   // specified bandwidth and at least 50 KB
00170   unsigned streamBitrate = fRTCPInstance == NULL ? 50 : fRTCPInstance->totSessionBW(); // in kbps
00171   unsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
00172   if (rtpBufSize < 50 * 1024) rtpBufSize = 50 * 1024;
00173   increaseSendBufferTo(envir(), fRTPSink.groupsockBeingUsed().socketNum(), rtpBufSize);
00174 
00175   // Set up the handler for incoming RTCP "RR" packets from this client:
00176   if (fRTCPInstance != NULL) {
00177     RTCPSourceRecord* source = (RTCPSourceRecord*)(fClientRTCPSourceRecords->Lookup((char const*)clientSessionId));
00178     if (source != NULL) {
00179       fRTCPInstance->setSpecificRRHandler(source->addr, source->port,
00180                                           rtcpRRHandler, rtcpRRHandlerClientData);
00181     }
00182   }
00183 }
00184 
00185 void PassiveServerMediaSubsession::deleteStream(unsigned clientSessionId, void*& /*streamToken*/) {
00186   // Lookup and remove the 'RTCPSourceRecord' for this client.  Also turn off RTCP "RR" handling:
00187   RTCPSourceRecord* source = (RTCPSourceRecord*)(fClientRTCPSourceRecords->Lookup((char const*)clientSessionId));
00188   if (source != NULL) {
00189     if (fRTCPInstance != NULL) {
00190       fRTCPInstance->unsetSpecificRRHandler(source->addr, source->port);
00191     }
00192 
00193     fClientRTCPSourceRecords->Remove((char const*)clientSessionId);
00194     delete source;
00195   }
00196 }

Generated on Thu Feb 2 23:51:31 2012 for live by  doxygen 1.5.2