liveMedia/DarwinInjector.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-2008 Live Networks, Inc.  All rights reserved.
00018 // An object that redirects one or more RTP/RTCP streams - forming a single
00019 // multimedia session - into a 'Darwin Streaming Server' (for subsequent
00020 // reflection to potentially arbitrarily many remote RTSP clients).
00021 // Implementation
00022 
00023 #include "DarwinInjector.hh"
00024 #include <GroupsockHelper.hh>
00025 
00027 
00028 class SubstreamDescriptor {
00029 public:
00030   SubstreamDescriptor(RTPSink* rtpSink, RTCPInstance* rtcpInstance, unsigned trackId);
00031   ~SubstreamDescriptor();
00032 
00033   SubstreamDescriptor*& next() { return fNext; }
00034   RTPSink* rtpSink() const { return fRTPSink; }
00035   RTCPInstance* rtcpInstance() const { return fRTCPInstance; }
00036   char const* sdpLines() const { return fSDPLines; }
00037 
00038 private:
00039   SubstreamDescriptor* fNext;
00040   RTPSink* fRTPSink;
00041   RTCPInstance* fRTCPInstance;
00042   char* fSDPLines;
00043 };
00044 
00045 
00047 
00048 DarwinInjector* DarwinInjector::createNew(UsageEnvironment& env,
00049                                           char const* applicationName,
00050                                           int verbosityLevel) {
00051   return new DarwinInjector(env, applicationName, verbosityLevel);
00052 }
00053 
00054 Boolean DarwinInjector::lookupByName(UsageEnvironment& env, char const* name,
00055                                      DarwinInjector*& result) {
00056   result = NULL; // unless we succeed
00057 
00058   Medium* medium;
00059   if (!Medium::lookupByName(env, name, medium)) return False;
00060 
00061   if (!medium->isDarwinInjector()) {
00062     env.setResultMsg(name, " is not a 'Darwin injector'");
00063     return False;
00064   }
00065 
00066   result = (DarwinInjector*)medium;
00067   return True;
00068 }
00069 
00070 DarwinInjector::DarwinInjector(UsageEnvironment& env,
00071                                char const* applicationName, int verbosityLevel)
00072   : Medium(env),
00073     fApplicationName(strDup(applicationName)), fVerbosityLevel(verbosityLevel),
00074     fRTSPClient(NULL), fSubstreamSDPSizes(0),
00075     fHeadSubstream(NULL), fTailSubstream(NULL), fSession(NULL), fLastTrackId(0) {
00076 }
00077 
00078 DarwinInjector::~DarwinInjector() {
00079   if (fSession != NULL) { // close down and delete the session
00080     fRTSPClient->teardownMediaSession(*fSession);
00081     Medium::close(fSession);
00082   }
00083 
00084   delete fHeadSubstream;
00085   delete[] (char*)fApplicationName;
00086   Medium::close(fRTSPClient);
00087 }
00088 
00089 void DarwinInjector::addStream(RTPSink* rtpSink, RTCPInstance* rtcpInstance) {
00090   if (rtpSink == NULL) return; // "rtpSink" should be non-NULL
00091 
00092   SubstreamDescriptor* newDescriptor = new SubstreamDescriptor(rtpSink, rtcpInstance, ++fLastTrackId);
00093   if (fHeadSubstream == NULL) {
00094     fHeadSubstream = fTailSubstream = newDescriptor;
00095   } else {
00096     fTailSubstream->next() = newDescriptor;
00097     fTailSubstream = newDescriptor;
00098   }
00099 
00100   fSubstreamSDPSizes += strlen(newDescriptor->sdpLines());
00101 }
00102 
00103 Boolean DarwinInjector
00104 ::setDestination(char const* remoteRTSPServerNameOrAddress,
00105                  char const* remoteFileName,
00106                  char const* sessionName,
00107                  char const* sessionInfo,
00108                  portNumBits remoteRTSPServerPortNumber,
00109                  char const* remoteUserName,
00110                  char const* remotePassword,
00111                  char const* sessionAuthor,
00112                  char const* sessionCopyright) {
00113   char* sdp = NULL;
00114   char* url = NULL;
00115   Boolean success = False; // until we learn otherwise
00116 
00117   do {
00118     // Begin by creating our RTSP client object:
00119     fRTSPClient = RTSPClient::createNew(envir(), fVerbosityLevel, fApplicationName);
00120     if (fRTSPClient == NULL) break;
00121 
00122     // Get the remote RTSP server's IP address:
00123     struct in_addr addr;
00124     {
00125       NetAddressList addresses(remoteRTSPServerNameOrAddress);
00126       if (addresses.numAddresses() == 0) break;
00127       NetAddress const* address = addresses.firstAddress();
00128       addr.s_addr = *(unsigned*)(address->data());
00129     }
00130     char const* remoteRTSPServerAddressStr = our_inet_ntoa(addr);
00131 
00132     // Construct a SDP description for the session that we'll be streaming:
00133     char const* const sdpFmt =
00134       "v=0\r\n"
00135       "o=- %u %u IN IP4 127.0.0.1\r\n"
00136       "s=%s\r\n"
00137       "i=%s\r\n"
00138       "c=IN IP4 %s\r\n"
00139       "t=0 0\r\n"
00140       "a=x-qt-text-nam:%s\r\n"
00141       "a=x-qt-text-inf:%s\r\n"
00142       "a=x-qt-text-cmt:source application:%s\r\n"
00143       "a=x-qt-text-aut:%s\r\n"
00144       "a=x-qt-text-cpy:%s\r\n";
00145       // plus, %s for each substream SDP
00146     unsigned sdpLen = strlen(sdpFmt)
00147       + 20 /* max int len */ + 20 /* max int len */
00148       + strlen(sessionName)
00149       + strlen(sessionInfo)
00150       + strlen(remoteRTSPServerAddressStr)
00151       + strlen(sessionName)
00152       + strlen(sessionInfo)
00153       + strlen(fApplicationName)
00154       + strlen(sessionAuthor)
00155       + strlen(sessionCopyright)
00156       + fSubstreamSDPSizes;
00157     unsigned const sdpSessionId = our_random();
00158     unsigned const sdpVersion = sdpSessionId;
00159     sdp = new char[sdpLen];
00160     sprintf(sdp, sdpFmt,
00161             sdpSessionId, sdpVersion, // o= line
00162             sessionName, // s= line
00163             sessionInfo, // i= line
00164             remoteRTSPServerAddressStr, // c= line
00165             sessionName, // a=x-qt-text-nam: line
00166             sessionInfo, // a=x-qt-text-inf: line
00167             fApplicationName, // a=x-qt-text-cmt: line
00168             sessionAuthor, // a=x-qt-text-aut: line
00169             sessionCopyright // a=x-qt-text-cpy: line
00170             );
00171     char* p = &sdp[strlen(sdp)];
00172     SubstreamDescriptor* ss;
00173     for (ss = fHeadSubstream; ss != NULL; ss = ss->next()) {
00174       sprintf(p, "%s", ss->sdpLines());
00175       p += strlen(p);
00176     }
00177 
00178     // Construct a RTSP URL for the remote stream:
00179     char const* const urlFmt = "rtsp://%s:%u/%s";
00180     unsigned urlLen
00181       = strlen(urlFmt) + strlen(remoteRTSPServerNameOrAddress) + 5 /* max short len */ + strlen(remoteFileName);
00182     url = new char[urlLen];
00183     sprintf(url, urlFmt, remoteRTSPServerNameOrAddress, remoteRTSPServerPortNumber, remoteFileName);
00184 
00185     // Do a RTSP "ANNOUNCE" with this SDP description:
00186     Boolean announceSuccess;
00187     if (remoteUserName[0] != '\0' || remotePassword[0] != '\0') {
00188       announceSuccess
00189         = fRTSPClient->announceWithPassword(url, sdp, remoteUserName, remotePassword);
00190     } else {
00191       announceSuccess = fRTSPClient->announceSDPDescription(url, sdp);
00192     }
00193     if (!announceSuccess) break;
00194 
00195     // Tell the remote server to start receiving the stream from us.
00196     // (To do this, we first create a "MediaSession" object from the SDP description.)
00197     fSession = MediaSession::createNew(envir(), sdp);
00198     if (fSession == NULL) break;
00199 
00200     ss = fHeadSubstream;
00201     MediaSubsessionIterator iter(*fSession);
00202     MediaSubsession* subsession;
00203     ss = fHeadSubstream;
00204     unsigned streamChannelId = 0;
00205     while ((subsession = iter.next()) != NULL) {
00206       if (!subsession->initiate()) break;
00207 
00208       if (!fRTSPClient->setupMediaSubsession(*subsession,
00209                                              True /*streamOutgoing*/,
00210                                              True /*streamUsingTCP*/)) {
00211         break;
00212       }
00213 
00214       // Tell this subsession's RTPSink and RTCPInstance to use
00215       // the RTSP TCP connection:
00216       ss->rtpSink()->setStreamSocket(fRTSPClient->socketNum(), streamChannelId++);
00217       if (ss->rtcpInstance() != NULL) {
00218         ss->rtcpInstance()->setStreamSocket(fRTSPClient->socketNum(),
00219                                             streamChannelId++);
00220       }
00221       ss = ss->next();
00222     }
00223     if (subsession != NULL) break; // an error occurred above
00224 
00225     // Tell the RTSP server to start:
00226     if (!fRTSPClient->playMediaSession(*fSession)) break;
00227 
00228     // Finally, make sure that the output TCP buffer is a reasonable size:
00229     increaseSendBufferTo(envir(), fRTSPClient->socketNum(), 100*1024);
00230 
00231     success = True;
00232   } while (0);
00233 
00234   delete[] sdp;
00235   delete[] url;
00236   return success;
00237 }
00238 
00239 Boolean DarwinInjector::isDarwinInjector() const {
00240   return True;
00241 }
00242 
00243 
00245 
00246 SubstreamDescriptor::SubstreamDescriptor(RTPSink* rtpSink,
00247                                          RTCPInstance* rtcpInstance, unsigned trackId)
00248   : fNext(NULL), fRTPSink(rtpSink), fRTCPInstance(rtcpInstance) {
00249   // Create the SDP description for this substream
00250   char const* mediaType = fRTPSink->sdpMediaType();
00251   unsigned char rtpPayloadType = fRTPSink->rtpPayloadType();
00252   char const* rtpPayloadFormatName = fRTPSink->rtpPayloadFormatName();
00253   unsigned rtpTimestampFrequency = fRTPSink->rtpTimestampFrequency();
00254   unsigned numChannels = fRTPSink->numChannels();
00255   char* rtpmapLine;
00256   if (rtpPayloadType >= 96) {
00257     char* encodingParamsPart;
00258     if (numChannels != 1) {
00259       encodingParamsPart = new char[1 + 20 /* max int len */];
00260       sprintf(encodingParamsPart, "/%d", numChannels);
00261     } else {
00262       encodingParamsPart = strDup("");
00263     }
00264     char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n";
00265     unsigned rtpmapFmtSize = strlen(rtpmapFmt)
00266       + 3 /* max char len */ + strlen(rtpPayloadFormatName)
00267       + 20 /* max int len */ + strlen(encodingParamsPart);
00268     rtpmapLine = new char[rtpmapFmtSize];
00269     sprintf(rtpmapLine, rtpmapFmt,
00270             rtpPayloadType, rtpPayloadFormatName,
00271             rtpTimestampFrequency, encodingParamsPart);
00272     delete[] encodingParamsPart;
00273   } else {
00274     // Static payload type => no "a=rtpmap:" line
00275     rtpmapLine = strDup("");
00276   }
00277   unsigned rtpmapLineSize = strlen(rtpmapLine);
00278   char const* auxSDPLine = fRTPSink->auxSDPLine();
00279   if (auxSDPLine == NULL) auxSDPLine = "";
00280   unsigned auxSDPLineSize = strlen(auxSDPLine);
00281 
00282   char const* const sdpFmt =
00283     "m=%s 0 RTP/AVP %u\r\n"
00284     "%s" // "a=rtpmap:" line (if present)
00285     "%s" // auxilliary (e.g., "a=fmtp:") line (if present)
00286     "a=control:trackID=%u\r\n";
00287   unsigned sdpFmtSize = strlen(sdpFmt)
00288     + strlen(mediaType) + 3 /* max char len */
00289     + rtpmapLineSize
00290     + auxSDPLineSize
00291     + 20 /* max int len */;
00292   char* sdpLines = new char[sdpFmtSize];
00293   sprintf(sdpLines, sdpFmt,
00294           mediaType, // m= <media>
00295           rtpPayloadType, // m= <fmt list>
00296           rtpmapLine, // a=rtpmap:... (if present)
00297           auxSDPLine, // optional extra SDP line
00298           trackId); // a=control:<track-id>
00299   fSDPLines = strDup(sdpLines);
00300   delete[] sdpLines;
00301   delete[] rtpmapLine;
00302 }
00303 
00304 SubstreamDescriptor::~SubstreamDescriptor() {
00305   delete fSDPLines;
00306   delete fNext;
00307 }

Generated on Tue Oct 7 15:38:08 2008 for live by  doxygen 1.5.2