00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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;
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), fResultString(NULL) {
00076 }
00077
00078 DarwinInjector::~DarwinInjector() {
00079 if (fSession != NULL) {
00080 fRTSPClient->sendTeardownCommand(*fSession, NULL);
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;
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
00104 class RTSPClientForDarwinInjector: public RTSPClient {
00105 public:
00106 RTSPClientForDarwinInjector(UsageEnvironment& env, char const* rtspURL, int verbosityLevel, char const* applicationName,
00107 DarwinInjector* ourDarwinInjector)
00108 : RTSPClient(env, rtspURL, verbosityLevel, applicationName, 0),
00109 fOurDarwinInjector(ourDarwinInjector) {}
00110 virtual ~RTSPClientForDarwinInjector() {}
00111 DarwinInjector* fOurDarwinInjector;
00112 };
00113
00114 Boolean DarwinInjector
00115 ::setDestination(char const* remoteRTSPServerNameOrAddress,
00116 char const* remoteFileName,
00117 char const* sessionName,
00118 char const* sessionInfo,
00119 portNumBits remoteRTSPServerPortNumber,
00120 char const* remoteUserName,
00121 char const* remotePassword,
00122 char const* sessionAuthor,
00123 char const* sessionCopyright,
00124 int timeout) {
00125 char* sdp = NULL;
00126 char* url = NULL;
00127 Boolean success = False;
00128
00129 do {
00130
00131 char const* const urlFmt = "rtsp://%s:%u/%s";
00132 unsigned urlLen
00133 = strlen(urlFmt) + strlen(remoteRTSPServerNameOrAddress) + 5 + strlen(remoteFileName);
00134 url = new char[urlLen];
00135 sprintf(url, urlFmt, remoteRTSPServerNameOrAddress, remoteRTSPServerPortNumber, remoteFileName);
00136
00137
00138 fRTSPClient = new RTSPClientForDarwinInjector(envir(), url, fVerbosityLevel, fApplicationName, this);
00139 if (fRTSPClient == NULL) break;
00140
00141
00142 struct in_addr addr;
00143 {
00144 NetAddressList addresses(remoteRTSPServerNameOrAddress);
00145 if (addresses.numAddresses() == 0) break;
00146 NetAddress const* address = addresses.firstAddress();
00147 addr.s_addr = *(unsigned*)(address->data());
00148 }
00149 AddressString remoteRTSPServerAddressStr(addr);
00150
00151
00152 char const* const sdpFmt =
00153 "v=0\r\n"
00154 "o=- %u %u IN IP4 127.0.0.1\r\n"
00155 "s=%s\r\n"
00156 "i=%s\r\n"
00157 "c=IN IP4 %s\r\n"
00158 "t=0 0\r\n"
00159 "a=x-qt-text-nam:%s\r\n"
00160 "a=x-qt-text-inf:%s\r\n"
00161 "a=x-qt-text-cmt:source application:%s\r\n"
00162 "a=x-qt-text-aut:%s\r\n"
00163 "a=x-qt-text-cpy:%s\r\n";
00164
00165 unsigned sdpLen = strlen(sdpFmt)
00166 + 20 + 20
00167 + strlen(sessionName)
00168 + strlen(sessionInfo)
00169 + strlen(remoteRTSPServerAddressStr.val())
00170 + strlen(sessionName)
00171 + strlen(sessionInfo)
00172 + strlen(fApplicationName)
00173 + strlen(sessionAuthor)
00174 + strlen(sessionCopyright)
00175 + fSubstreamSDPSizes;
00176 unsigned const sdpSessionId = our_random32();
00177 unsigned const sdpVersion = sdpSessionId;
00178 sdp = new char[sdpLen];
00179 sprintf(sdp, sdpFmt,
00180 sdpSessionId, sdpVersion,
00181 sessionName,
00182 sessionInfo,
00183 remoteRTSPServerAddressStr.val(),
00184 sessionName,
00185 sessionInfo,
00186 fApplicationName,
00187 sessionAuthor,
00188 sessionCopyright
00189 );
00190 char* p = &sdp[strlen(sdp)];
00191 SubstreamDescriptor* ss;
00192 for (ss = fHeadSubstream; ss != NULL; ss = ss->next()) {
00193 sprintf(p, "%s", ss->sdpLines());
00194 p += strlen(p);
00195 }
00196
00197
00198 Authenticator auth;
00199 Authenticator* authToUse = NULL;
00200 if (remoteUserName[0] != '\0' || remotePassword[0] != '\0') {
00201 auth.setUsernameAndPassword(remoteUserName, remotePassword);
00202 authToUse = &auth;
00203 }
00204 fWatchVariable = 0;
00205 (void)fRTSPClient->sendAnnounceCommand(sdp, genericResponseHandler, authToUse);
00206
00207
00208 envir().taskScheduler().doEventLoop(&fWatchVariable);
00209
00210 delete[] fResultString;
00211 if (fResultCode != 0) break;
00212
00213
00214
00215 fSession = MediaSession::createNew(envir(), sdp);
00216 if (fSession == NULL) break;
00217
00218 ss = fHeadSubstream;
00219 MediaSubsessionIterator iter(*fSession);
00220 MediaSubsession* subsession;
00221 ss = fHeadSubstream;
00222 unsigned streamChannelId = 0;
00223 while ((subsession = iter.next()) != NULL) {
00224 if (!subsession->initiate()) break;
00225
00226 fWatchVariable = 0;
00227 (void)fRTSPClient->sendSetupCommand(*subsession, genericResponseHandler,
00228 True ,
00229 True );
00230
00231 envir().taskScheduler().doEventLoop(&fWatchVariable);
00232
00233 delete[] fResultString;
00234 if (fResultCode != 0) break;
00235
00236
00237
00238 ss->rtpSink()->setStreamSocket(fRTSPClient->socketNum(), streamChannelId++);
00239 if (ss->rtcpInstance() != NULL) {
00240 ss->rtcpInstance()->setStreamSocket(fRTSPClient->socketNum(),
00241 streamChannelId++);
00242 }
00243 ss = ss->next();
00244 }
00245 if (subsession != NULL) break;
00246
00247
00248 fWatchVariable = 0;
00249 (void)fRTSPClient->sendPlayCommand(*fSession, genericResponseHandler);
00250
00251
00252 envir().taskScheduler().doEventLoop(&fWatchVariable);
00253
00254 delete[] fResultString;
00255 if (fResultCode != 0) break;
00256
00257
00258 increaseSendBufferTo(envir(), fRTSPClient->socketNum(), 100*1024);
00259
00260 success = True;
00261 } while (0);
00262
00263 delete[] sdp;
00264 delete[] url;
00265 return success;
00266 }
00267
00268 Boolean DarwinInjector::isDarwinInjector() const {
00269 return True;
00270 }
00271
00272 void DarwinInjector::genericResponseHandler(RTSPClient* rtspClient, int responseCode, char* responseString) {
00273 DarwinInjector* di = ((RTSPClientForDarwinInjector*)rtspClient)-> fOurDarwinInjector;
00274 di->genericResponseHandler1(responseCode, responseString);
00275 }
00276
00277 void DarwinInjector::genericResponseHandler1(int responseCode, char* responseString) {
00278
00279 fResultCode = responseCode;
00280 fResultString = responseString;
00281
00282
00283 fWatchVariable = ~0;
00284 }
00285
00287
00288 SubstreamDescriptor::SubstreamDescriptor(RTPSink* rtpSink,
00289 RTCPInstance* rtcpInstance, unsigned trackId)
00290 : fNext(NULL), fRTPSink(rtpSink), fRTCPInstance(rtcpInstance) {
00291
00292 char const* mediaType = fRTPSink->sdpMediaType();
00293 unsigned char rtpPayloadType = fRTPSink->rtpPayloadType();
00294 char const* rtpPayloadFormatName = fRTPSink->rtpPayloadFormatName();
00295 unsigned rtpTimestampFrequency = fRTPSink->rtpTimestampFrequency();
00296 unsigned numChannels = fRTPSink->numChannels();
00297 char* rtpmapLine;
00298 if (rtpPayloadType >= 96) {
00299 char* encodingParamsPart;
00300 if (numChannels != 1) {
00301 encodingParamsPart = new char[1 + 20 ];
00302 sprintf(encodingParamsPart, "/%d", numChannels);
00303 } else {
00304 encodingParamsPart = strDup("");
00305 }
00306 char const* const rtpmapFmt = "a=rtpmap:%d %s/%d%s\r\n";
00307 unsigned rtpmapFmtSize = strlen(rtpmapFmt)
00308 + 3 + strlen(rtpPayloadFormatName)
00309 + 20 + strlen(encodingParamsPart);
00310 rtpmapLine = new char[rtpmapFmtSize];
00311 sprintf(rtpmapLine, rtpmapFmt,
00312 rtpPayloadType, rtpPayloadFormatName,
00313 rtpTimestampFrequency, encodingParamsPart);
00314 delete[] encodingParamsPart;
00315 } else {
00316
00317 rtpmapLine = strDup("");
00318 }
00319 unsigned rtpmapLineSize = strlen(rtpmapLine);
00320 char const* auxSDPLine = fRTPSink->auxSDPLine();
00321 if (auxSDPLine == NULL) auxSDPLine = "";
00322 unsigned auxSDPLineSize = strlen(auxSDPLine);
00323
00324 char const* const sdpFmt =
00325 "m=%s 0 RTP/AVP %u\r\n"
00326 "%s"
00327 "%s"
00328 "a=control:trackID=%u\r\n";
00329 unsigned sdpFmtSize = strlen(sdpFmt)
00330 + strlen(mediaType) + 3
00331 + rtpmapLineSize
00332 + auxSDPLineSize
00333 + 20 ;
00334 char* sdpLines = new char[sdpFmtSize];
00335 sprintf(sdpLines, sdpFmt,
00336 mediaType,
00337 rtpPayloadType,
00338 rtpmapLine,
00339 auxSDPLine,
00340 trackId);
00341 fSDPLines = strDup(sdpLines);
00342 delete[] sdpLines;
00343 delete[] rtpmapLine;
00344 }
00345
00346 SubstreamDescriptor::~SubstreamDescriptor() {
00347 delete fSDPLines;
00348 delete fNext;
00349 }