00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "ServerMediaSession.hh"
00025 #include <GroupsockHelper.hh>
00026 #include <math.h>
00027
00029
00030 ServerMediaSession* ServerMediaSession
00031 ::createNew(UsageEnvironment& env,
00032 char const* streamName, char const* info,
00033 char const* description, Boolean isSSM, char const* miscSDPLines) {
00034 return new ServerMediaSession(env, streamName, info, description,
00035 isSSM, miscSDPLines);
00036 }
00037
00038 Boolean ServerMediaSession
00039 ::lookupByName(UsageEnvironment& env, char const* mediumName,
00040 ServerMediaSession*& resultSession) {
00041 resultSession = NULL;
00042
00043 Medium* medium;
00044 if (!Medium::lookupByName(env, mediumName, medium)) return False;
00045
00046 if (!medium->isServerMediaSession()) {
00047 env.setResultMsg(mediumName, " is not a 'ServerMediaSession' object");
00048 return False;
00049 }
00050
00051 resultSession = (ServerMediaSession*)medium;
00052 return True;
00053 }
00054
00055 static char const* const libNameStr = "LIVE555 Streaming Media v";
00056 char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;
00057
00058 ServerMediaSession::ServerMediaSession(UsageEnvironment& env,
00059 char const* streamName,
00060 char const* info,
00061 char const* description,
00062 Boolean isSSM, char const* miscSDPLines)
00063 : Medium(env), fIsSSM(isSSM), fSubsessionsHead(NULL),
00064 fSubsessionsTail(NULL), fSubsessionCounter(0),
00065 fReferenceCount(0), fDeleteWhenUnreferenced(False) {
00066 fStreamName = strDup(streamName == NULL ? "" : streamName);
00067
00068 char* libNamePlusVersionStr = NULL;
00069 if (info == NULL || description == NULL) {
00070 libNamePlusVersionStr = new char[strlen(libNameStr) + strlen(libVersionStr) + 1];
00071 sprintf(libNamePlusVersionStr, "%s%s", libNameStr, libVersionStr);
00072 }
00073 fInfoSDPString = strDup(info == NULL ? libNamePlusVersionStr : info);
00074 fDescriptionSDPString = strDup(description == NULL ? libNamePlusVersionStr : description);
00075 delete[] libNamePlusVersionStr;
00076
00077 fMiscSDPLines = strDup(miscSDPLines == NULL ? "" : miscSDPLines);
00078
00079 gettimeofday(&fCreationTime, NULL);
00080 }
00081
00082 ServerMediaSession::~ServerMediaSession() {
00083 deleteAllSubsessions();
00084 delete[] fStreamName;
00085 delete[] fInfoSDPString;
00086 delete[] fDescriptionSDPString;
00087 delete[] fMiscSDPLines;
00088 }
00089
00090 Boolean
00091 ServerMediaSession::addSubsession(ServerMediaSubsession* subsession) {
00092 if (subsession->fParentSession != NULL) return False;
00093
00094 if (fSubsessionsTail == NULL) {
00095 fSubsessionsHead = subsession;
00096 } else {
00097 fSubsessionsTail->fNext = subsession;
00098 }
00099 fSubsessionsTail = subsession;
00100
00101 subsession->fParentSession = this;
00102 subsession->fTrackNumber = ++fSubsessionCounter;
00103 return True;
00104 }
00105
00106 void ServerMediaSession::testScaleFactor(float& scale) {
00107
00108
00109
00110
00111 float minSSScale = 1.0;
00112 float maxSSScale = 1.0;
00113 float bestSSScale = 1.0;
00114 float bestDistanceTo1 = 0.0;
00115 ServerMediaSubsession* subsession;
00116 for (subsession = fSubsessionsHead; subsession != NULL;
00117 subsession = subsession->fNext) {
00118 float ssscale = scale;
00119 subsession->testScaleFactor(ssscale);
00120 if (subsession == fSubsessionsHead) {
00121 minSSScale = maxSSScale = bestSSScale = ssscale;
00122 bestDistanceTo1 = (float)fabs(ssscale - 1.0f);
00123 } else {
00124 if (ssscale < minSSScale) {
00125 minSSScale = ssscale;
00126 } else if (ssscale > maxSSScale) {
00127 maxSSScale = ssscale;
00128 }
00129
00130 float distanceTo1 = (float)fabs(ssscale - 1.0f);
00131 if (distanceTo1 < bestDistanceTo1) {
00132 bestSSScale = ssscale;
00133 bestDistanceTo1 = distanceTo1;
00134 }
00135 }
00136 }
00137 if (minSSScale == maxSSScale) {
00138
00139 scale = minSSScale;
00140 return;
00141 }
00142
00143
00144
00145 for (subsession = fSubsessionsHead; subsession != NULL;
00146 subsession = subsession->fNext) {
00147 float ssscale = bestSSScale;
00148 subsession->testScaleFactor(ssscale);
00149 if (ssscale != bestSSScale) break;
00150 }
00151 if (subsession == NULL) {
00152
00153 scale = bestSSScale;
00154 return;
00155 }
00156
00157
00158 for (subsession = fSubsessionsHead; subsession != NULL;
00159 subsession = subsession->fNext) {
00160 float ssscale = 1;
00161 subsession->testScaleFactor(ssscale);
00162 }
00163 scale = 1;
00164 }
00165
00166 float ServerMediaSession::duration() const {
00167 float minSubsessionDuration = 0.0;
00168 float maxSubsessionDuration = 0.0;
00169 for (ServerMediaSubsession* subsession = fSubsessionsHead; subsession != NULL;
00170 subsession = subsession->fNext) {
00171
00172
00173 char* absStartTime = NULL; char* absEndTime = NULL;
00174 subsession->getAbsoluteTimeRange(absStartTime, absEndTime);
00175 if (absStartTime != NULL) return -1.0f;
00176
00177 float ssduration = subsession->duration();
00178 if (subsession == fSubsessionsHead) {
00179 minSubsessionDuration = maxSubsessionDuration = ssduration;
00180 } else if (ssduration < minSubsessionDuration) {
00181 minSubsessionDuration = ssduration;
00182 } else if (ssduration > maxSubsessionDuration) {
00183 maxSubsessionDuration = ssduration;
00184 }
00185 }
00186
00187 if (maxSubsessionDuration != minSubsessionDuration) {
00188 return -maxSubsessionDuration;
00189 } else {
00190 return maxSubsessionDuration;
00191 }
00192 }
00193
00194 void ServerMediaSession::deleteAllSubsessions() {
00195 Medium::close(fSubsessionsHead);
00196 fSubsessionsHead = fSubsessionsTail = NULL;
00197 fSubsessionCounter = 0;
00198 }
00199
00200 Boolean ServerMediaSession::isServerMediaSession() const {
00201 return True;
00202 }
00203
00204 char* ServerMediaSession::generateSDPDescription() {
00205 AddressString ipAddressStr(ourIPAddress(envir()));
00206 unsigned ipAddressStrSize = strlen(ipAddressStr.val());
00207
00208
00209 char* sourceFilterLine;
00210 if (fIsSSM) {
00211 char const* const sourceFilterFmt =
00212 "a=source-filter: incl IN IP4 * %s\r\n"
00213 "a=rtcp-unicast: reflection\r\n";
00214 unsigned const sourceFilterFmtSize = strlen(sourceFilterFmt) + ipAddressStrSize + 1;
00215
00216 sourceFilterLine = new char[sourceFilterFmtSize];
00217 sprintf(sourceFilterLine, sourceFilterFmt, ipAddressStr.val());
00218 } else {
00219 sourceFilterLine = strDup("");
00220 }
00221
00222 char* rangeLine = NULL;
00223 char* sdp = NULL;
00224
00225 do {
00226
00227
00228
00229 unsigned sdpLength = 0;
00230 ServerMediaSubsession* subsession;
00231 for (subsession = fSubsessionsHead; subsession != NULL;
00232 subsession = subsession->fNext) {
00233 char const* sdpLines = subsession->sdpLines();
00234 if (sdpLines == NULL) continue;
00235 sdpLength += strlen(sdpLines);
00236 }
00237 if (sdpLength == 0) break;
00238
00239
00240 float dur = duration();
00241 if (dur == 0.0) {
00242 rangeLine = strDup("a=range:npt=0-\r\n");
00243 } else if (dur > 0.0) {
00244 char buf[100];
00245 sprintf(buf, "a=range:npt=0-%.3f\r\n", dur);
00246 rangeLine = strDup(buf);
00247 } else {
00248 rangeLine = strDup("");
00249 }
00250
00251 char const* const sdpPrefixFmt =
00252 "v=0\r\n"
00253 "o=- %ld%06ld %d IN IP4 %s\r\n"
00254 "s=%s\r\n"
00255 "i=%s\r\n"
00256 "t=0 0\r\n"
00257 "a=tool:%s%s\r\n"
00258 "a=type:broadcast\r\n"
00259 "a=control:*\r\n"
00260 "%s"
00261 "%s"
00262 "a=x-qt-text-nam:%s\r\n"
00263 "a=x-qt-text-inf:%s\r\n"
00264 "%s";
00265 sdpLength += strlen(sdpPrefixFmt)
00266 + 20 + 6 + 20 + ipAddressStrSize
00267 + strlen(fDescriptionSDPString)
00268 + strlen(fInfoSDPString)
00269 + strlen(libNameStr) + strlen(libVersionStr)
00270 + strlen(sourceFilterLine)
00271 + strlen(rangeLine)
00272 + strlen(fDescriptionSDPString)
00273 + strlen(fInfoSDPString)
00274 + strlen(fMiscSDPLines);
00275 sdp = new char[sdpLength];
00276 if (sdp == NULL) break;
00277
00278
00279 sprintf(sdp, sdpPrefixFmt,
00280 fCreationTime.tv_sec, fCreationTime.tv_usec,
00281 1,
00282 ipAddressStr.val(),
00283 fDescriptionSDPString,
00284 fInfoSDPString,
00285 libNameStr, libVersionStr,
00286 sourceFilterLine,
00287 rangeLine,
00288 fDescriptionSDPString,
00289 fInfoSDPString,
00290 fMiscSDPLines);
00291
00292
00293 char* mediaSDP = sdp;
00294 for (subsession = fSubsessionsHead; subsession != NULL;
00295 subsession = subsession->fNext) {
00296 mediaSDP += strlen(mediaSDP);
00297 char const* sdpLines = subsession->sdpLines();
00298 if (sdpLines != NULL) sprintf(mediaSDP, "%s", sdpLines);
00299 }
00300 } while (0);
00301
00302 delete[] rangeLine; delete[] sourceFilterLine;
00303 return sdp;
00304 }
00305
00306
00308
00309 ServerMediaSubsessionIterator
00310 ::ServerMediaSubsessionIterator(ServerMediaSession& session)
00311 : fOurSession(session) {
00312 reset();
00313 }
00314
00315 ServerMediaSubsessionIterator::~ServerMediaSubsessionIterator() {
00316 }
00317
00318 ServerMediaSubsession* ServerMediaSubsessionIterator::next() {
00319 ServerMediaSubsession* result = fNextPtr;
00320
00321 if (fNextPtr != NULL) fNextPtr = fNextPtr->fNext;
00322
00323 return result;
00324 }
00325
00326 void ServerMediaSubsessionIterator::reset() {
00327 fNextPtr = fOurSession.fSubsessionsHead;
00328 }
00329
00330
00332
00333 ServerMediaSubsession::ServerMediaSubsession(UsageEnvironment& env)
00334 : Medium(env),
00335 fParentSession(NULL), fServerAddressForSDP(0), fPortNumForSDP(0),
00336 fNext(NULL), fTrackNumber(0), fTrackId(NULL) {
00337 }
00338
00339 ServerMediaSubsession::~ServerMediaSubsession() {
00340 delete[] (char*)fTrackId;
00341 Medium::close(fNext);
00342 }
00343
00344 char const* ServerMediaSubsession::trackId() {
00345 if (fTrackNumber == 0) return NULL;
00346
00347 if (fTrackId == NULL) {
00348 char buf[100];
00349 sprintf(buf, "track%d", fTrackNumber);
00350 fTrackId = strDup(buf);
00351 }
00352 return fTrackId;
00353 }
00354
00355 void ServerMediaSubsession::pauseStream(unsigned ,
00356 void* ) {
00357
00358 }
00359 void ServerMediaSubsession::seekStream(unsigned ,
00360 void* , double& , double , u_int64_t& numBytes) {
00361
00362 numBytes = 0;
00363 }
00364 void ServerMediaSubsession::seekStream(unsigned ,
00365 void* , char*& absStart, char*& absEnd) {
00366
00367 delete[] absStart; absStart = NULL;
00368 delete[] absEnd; absEnd = NULL;
00369 }
00370 void ServerMediaSubsession::nullSeekStream(unsigned , void* ) {
00371
00372 }
00373 void ServerMediaSubsession::setStreamScale(unsigned ,
00374 void* , float ) {
00375
00376 }
00377 float ServerMediaSubsession::getCurrentNPT(void* ) {
00378
00379 return 0.0;
00380 }
00381 FramedSource* ServerMediaSubsession::getStreamSource(void* ) {
00382
00383 return NULL;
00384 }
00385 void ServerMediaSubsession::deleteStream(unsigned ,
00386 void*& ) {
00387
00388 }
00389
00390 void ServerMediaSubsession::testScaleFactor(float& scale) {
00391
00392 scale = 1;
00393 }
00394
00395 float ServerMediaSubsession::duration() const {
00396
00397 return 0.0;
00398 }
00399
00400 void ServerMediaSubsession::getAbsoluteTimeRange(char*& absStartTime, char*& absEndTime) const {
00401
00402 absStartTime = absEndTime = NULL;
00403 }
00404
00405 void ServerMediaSubsession::setServerAddressAndPortForSDP(netAddressBits addressBits,
00406 portNumBits portBits) {
00407 fServerAddressForSDP = addressBits;
00408 fPortNumForSDP = portBits;
00409 }
00410
00411 char const*
00412 ServerMediaSubsession::rangeSDPLine() const {
00413
00414 char* absStart = NULL; char* absEnd = NULL;
00415 getAbsoluteTimeRange(absStart, absEnd);
00416 if (absStart != NULL) {
00417 char buf[100];
00418
00419 if (absEnd != NULL) {
00420 sprintf(buf, "a=range:clock=%s-%s\r\n", absStart, absEnd);
00421 } else {
00422 sprintf(buf, "a=range:clock=%s-\r\n", absStart);
00423 }
00424 return strDup(buf);
00425 }
00426
00427 if (fParentSession == NULL) return NULL;
00428
00429
00430
00431 if (fParentSession->duration() >= 0.0) return strDup("");
00432
00433
00434 float ourDuration = duration();
00435 if (ourDuration == 0.0) {
00436 return strDup("a=range:npt=0-\r\n");
00437 } else {
00438 char buf[100];
00439 sprintf(buf, "a=range:npt=0-%.3f\r\n", ourDuration);
00440 return strDup(buf);
00441 }
00442 }