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) {
00076 }
00077
00078 DarwinInjector::~DarwinInjector() {
00079 if (fSession != NULL) {
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;
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;
00116
00117 do {
00118
00119 fRTSPClient = RTSPClient::createNew(envir(), fVerbosityLevel, fApplicationName);
00120 if (fRTSPClient == NULL) break;
00121
00122
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
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
00146 unsigned sdpLen = strlen(sdpFmt)
00147 + 20 + 20
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,
00162 sessionName,
00163 sessionInfo,
00164 remoteRTSPServerAddressStr,
00165 sessionName,
00166 sessionInfo,
00167 fApplicationName,
00168 sessionAuthor,
00169 sessionCopyright
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
00179 char const* const urlFmt = "rtsp://%s:%u/%s";
00180 unsigned urlLen
00181 = strlen(urlFmt) + strlen(remoteRTSPServerNameOrAddress) + 5 + strlen(remoteFileName);
00182 url = new char[urlLen];
00183 sprintf(url, urlFmt, remoteRTSPServerNameOrAddress, remoteRTSPServerPortNumber, remoteFileName);
00184
00185
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
00196
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 ,
00210 True )) {
00211 break;
00212 }
00213
00214
00215
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;
00224
00225
00226 if (!fRTSPClient->playMediaSession(*fSession)) break;
00227
00228
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
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 ];
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 + strlen(rtpPayloadFormatName)
00267 + 20 + strlen(encodingParamsPart);
00268 rtpmapLine = new char[rtpmapFmtSize];
00269 sprintf(rtpmapLine, rtpmapFmt,
00270 rtpPayloadType, rtpPayloadFormatName,
00271 rtpTimestampFrequency, encodingParamsPart);
00272 delete[] encodingParamsPart;
00273 } else {
00274
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"
00285 "%s"
00286 "a=control:trackID=%u\r\n";
00287 unsigned sdpFmtSize = strlen(sdpFmt)
00288 + strlen(mediaType) + 3
00289 + rtpmapLineSize
00290 + auxSDPLineSize
00291 + 20 ;
00292 char* sdpLines = new char[sdpFmtSize];
00293 sprintf(sdpLines, sdpFmt,
00294 mediaType,
00295 rtpPayloadType,
00296 rtpmapLine,
00297 auxSDPLine,
00298 trackId);
00299 fSDPLines = strDup(sdpLines);
00300 delete[] sdpLines;
00301 delete[] rtpmapLine;
00302 }
00303
00304 SubstreamDescriptor::~SubstreamDescriptor() {
00305 delete fSDPLines;
00306 delete fNext;
00307 }