【live555】推流者使用的ServerMediaSession类,以及如何产生SDP

来源:互联网 发布:cache数据库 东华 编辑:程序博客网 时间:2024/06/07 02:56

对于我个人而言,可能比较关注的是SDP的生成,所以会对SDP的一些方法和属性,加颜色标示。


###############################

(1)推流者用的一个数据结构 server media session,这个session可以含有多个子(sub)session,每个子session可以是音频或者视频。

而接受者,用的是media session。注意,sever media session 和 media session 不同。

(2)server media session 是所有sub session的父类。

所代表的所有的sub session, 所共用的属性有:

【1】  Boolean fIsSSM;

【2】  char* fStreamName;  //流的名程
 【3】 char* fInfoSDPString;  // 是个字符串,表示infoSDP?不懂,这里头是啥呢?
  【4】char* fDescriptionSDPString;  //表示是个字符串,用处是描述SDP的
  【5】 char* fMiscSDPLines; //难道是表示其余各种各样的SDP的行?
  【5】struct timeval fCreationTime;  创建session的时间么?
  【6】 unsigned fReferenceCount;  //表示这个session被引用了多少次么?
  【7】  Boolean fDeleteWhenUnreferenced;


有一些共有的行为:

【1】 判断是否是 server media session      函数isServerMediaSession

【2 】得到流的名字

【3】 SDP相关

为整个session 产生SDP   函数 generateSDPDescription

  char* fInfoSDPString;  // 是个字符串,表示infoSDP?不懂,这里头是啥呢?
  char* fDescriptionSDPString;  //表示是个字符串,用处是描述SDP的
  char* fMiscSDPLines; //难道是表示其余各种各样的SDP的行?
  struct timeval fCreationTime;  创建session的时间么?

【4】  sub session 相关

添加 sub session 

删掉所有的 sub session

计算 sub session的 总数目

【5】 引用计数相关

增加引用计数

删除引用计数

统计引用计数数目

【6】   等等

testScaleFactor

【7】 遍历各个server media session ????

使用内置的类 ServerMediaSubsessionIterator


################################################################################

// "liveMedia"
// Copyright (c) 1996-2014 Live Networks, Inc.  All rights reserved.
// A data structure that represents a session that consists of
// potentially可能的 multiple (audio and/or video) sub-sessions
// (This data structure is used for media *streamers* - i.e., servers.
//  For media receivers, use "MediaSession" instead.)
// C++ header


#ifndef _SERVER_MEDIA_SESSION_HH
#define _SERVER_MEDIA_SESSION_HH


#ifndef _MEDIA_HH
#include "Media.hh"
#endif
#ifndef _FRAMED_SOURCE_HH
#include "FramedSource.hh"
#endif
#ifndef _GROUPEID_HH
#include "GroupEId.hh"
#endif
#ifndef _RTP_INTERFACE_HH
#include "RTPInterface.hh" // for ServerRequestAlternativeByteHandler
#endif


class ServerMediaSubsession; // forward


class ServerMediaSession: public Medium {
public:

//这个函数会调用构造函数。
  static ServerMediaSession* createNew(UsageEnvironment& env,
      char const* streamName = NULL,
      char const* info = NULL,
      char const* description = NULL,
      Boolean isSSM = False,
      char const* miscSDPLines= NULL);


  static Boolean lookupByName(UsageEnvironment& env,
                              char const* mediumName,
                              ServerMediaSession*& resultSession);

//基于整个session产生SDP描述信息
  char* generateSDPDescription(); // based on the entire session
      // Note: The caller is responsible for freeing the returned string


  char const* streamName() const { return fStreamName; } //stream的名字,这个是指啥?


  Boolean addSubsession(ServerMediaSubsession* subsession); //加入一个sub session
  unsigned numSubsessions() const { return fSubsessionCounter; } //sesssion数目


  void testScaleFactor(float& scale); // sets "scale" to the actual supported scale   //要缩放么???
  float duration() const; //session的持续时间
    // a result == 0 means an unbounded session (the default)  0表示无限制
    // a result < 0 means: subsession durations differ; the result is -(the largest).     负数,这个是啥意思呢???
    // a result > 0 means: this is the duration of a bounded session   有限制


//引用计数是对stream的?对session的???
  unsigned referenceCount() const { return fReferenceCount; }
  void incrementReferenceCount() { ++fReferenceCount; }
  void decrementReferenceCount() { if (fReferenceCount > 0) --fReferenceCount; }
  Boolean& deleteWhenUnreferenced() { return fDeleteWhenUnreferenced; }

//作为所有session的父类,就具有了删掉所有sub session的能力。
  void deleteAllSubsessions();
    // Removes and deletes all subsessions added by "addSubsession()", returning us to an 'empty' state  删掉所有add的sub session,将回退到empty 的状态。
    // Note: If you have already added this "ServerMediaSession" to a "RTSPServer" then, before calling this function,
    //   you must first close any client connections that use it,
    //   by calling "RTSPServer::closeAllClientSessionsForServerMediaSession()".


protected:

//这是构造函数
  ServerMediaSession(UsageEnvironment& env, char const* streamName,
    char const* info, char const* description,
    Boolean isSSM, char const* miscSDPLines);
  // called only by "createNew()"


  virtual ~ServerMediaSession();


private: // redefined virtual functions
  virtual Boolean isServerMediaSession() const;


private:
  Boolean fIsSSM;


  // Linkage fields:  这个链表域,用来遍历sub session的。

  friend class ServerMediaSubsessionIterator;
  ServerMediaSubsession* fSubsessionsHead;
  ServerMediaSubsession* fSubsessionsTail;
  unsigned fSubsessionCounter;


  char* fStreamName;  //流的名程
  char* fInfoSDPString;  // 是个字符串,表示infoSDP?不懂,这里头是啥呢?
  char* fDescriptionSDPString;  //表示是个字符串,用处是描述SDP的
  char* fMiscSDPLines; //难道是表示其余各种各样的SDP的行?
  struct timeval fCreationTime;  创建session的时间么?
  unsigned fReferenceCount;  //表示这个session被引用了多少次么?
  Boolean fDeleteWhenUnreferenced;
};


##########################ServerMediaSubsessionIterator  类#########################

class ServerMediaSubsessionIterator {
public:
  ServerMediaSubsessionIterator(ServerMediaSession& session);
  virtual ~ServerMediaSubsessionIterator();


  ServerMediaSubsession* next(); // NULL if none
  void reset();


private:
  ServerMediaSession& fOurSession;
  ServerMediaSubsession* fNextPtr;
};




#############ServerMediaSession实现####################




**********/
// "liveMedia"
// Copyright (c) 1996-2014 Live Networks, Inc.  All rights reserved.
// A data structure that represents a session that consists of
// potentially multiple (audio and/or video) sub-sessions
// (This data structure is used for media *streamers* - i.e., servers.
//  For media receivers, use "MediaSession" instead.)
// Implementation


#include "ServerMediaSession.hh"
#include <GroupsockHelper.hh>
#include <math.h>


////////// ServerMediaSession //////////


ServerMediaSession* ServerMediaSession
::createNew(UsageEnvironment& env,
   char const* streamName, char const* info,
   char const* description, Boolean isSSM, char const* miscSDPLines) {
  return new ServerMediaSession(env, streamName, info, description,
isSSM, miscSDPLines);
}


Boolean ServerMediaSession
::lookupByName(UsageEnvironment& env, char const* mediumName,
      ServerMediaSession*& resultSession) {
  resultSession = NULL; // unless we succeed   啥意思????


  Medium* medium;
  if (!Medium::lookupByName(env, mediumName, medium)) return False;


  if (!medium->isServerMediaSession()) {
    env.setResultMsg(mediumName, " is not a 'ServerMediaSession' object");
    return False;
  }


  resultSession = (ServerMediaSession*)medium;
  return True;
}


static charconst* const libNameStr = "LIVE555 Streaming Media v"; //staic的 ,居然还有俩const啊,都啥意思啊。
char const* const libVersionStr = LIVEMEDIA_LIBRARY_VERSION_STRING;

//构造函数
ServerMediaSession::ServerMediaSession(UsageEnvironment& env,
      char const* streamName,
      char const* info,
      char const* description,
      Boolean isSSM, char const* miscSDPLines)

//在构造函数中,初始化各个域

  : Medium(env), fIsSSM(isSSM), fSubsessionsHead(NULL),
    fSubsessionsTail(NULL), fSubsessionCounter(0),
    fReferenceCount(0), fDeleteWhenUnreferenced(False) {
  fStreamName = strDup(streamName== NULL ? "" : streamName);  //流的名字,可能是空的。


  char* libNamePlusVersionStr = NULL; // by default

  if (info == NULL || description == NULL) {
    libNamePlusVersionStr = new char[strlen(libNameStr) + strlen(libVersionStr) + 1];
    sprintf(libNamePlusVersionStr, "%s%s", libNameStr, libVersionStr);
  }

//咋这俩一开始的初始化指,都跟live555的版本号有关系啊。。。。
  fInfoSDPString= strDup(info == NULL ? libNamePlusVersionStr : info);
  fDescriptionSDPString = strDup(description == NULL ? libNamePlusVersionStr : description);

  delete[] libNamePlusVersionStr;


  fMiscSDPLines = strDup(miscSDPLines == NULL ? "" : miscSDPLines);


  gettimeofday(&fCreationTime, NULL);  //创建时间有了。
}


ServerMediaSession::~ServerMediaSession() {  //析构函数。。。删掉这些字符串。
  deleteAllSubsessions();
  delete[] fStreamName;
  delete[] fInfoSDPString;
  delete[] fDescriptionSDPString;
  delete[] fMiscSDPLines;
}


//好像维护了一个具有头尾指针的链表,也就是一个队列吧,头部删除,尾部加入。

Boolean
ServerMediaSession::addSubsession(ServerMediaSubsession* subsession) {
  if (subsession->fParentSession != NULL) return False; // it's already used


  if (fSubsessionsTail == NULL) {  //标示队列空。

    fSubsessionsHead = subsession;
  } else {
    fSubsessionsTail->fNext = subsession;
  }
  fSubsessionsTail = subsession;


  subsession->fParentSession = this;  //新加入的sub session的父亲是加入他的这个session
  subsession->fTrackNumber = ++fSubsessionCounter;  //track的序号是这么计算的,加入一个sub sessin,那么track就增加1
  return True;
}


//为啥要scale 啊????

void ServerMediaSession::testScaleFactor(float& scale) {
  // First, try setting all subsessions to the desired scale.
  // If the subsessions' actual scales differ from each other, choose the
  // value that's closest to 1, and then try re-setting all subsessions to that
  // value.  If the subsessions' actual scales still differ, re-set them all to 1.
  float minSSScale = 1.0;
  float maxSSScale = 1.0;
  float bestSSScale = 1.0;
  float bestDistanceTo1 = 0.0;
  ServerMediaSubsession* subsession;
  for (subsession = fSubsessionsHead; subsession != NULL;
       subsession = subsession->fNext) {
    float ssscale = scale;
    subsession->testScaleFactor(ssscale);
    if (subsession == fSubsessionsHead) { // this is the first subsession
      minSSScale = maxSSScale = bestSSScale = ssscale;
      bestDistanceTo1 = (float)fabs(ssscale - 1.0f);
    } else {
      if (ssscale < minSSScale) {
minSSScale = ssscale;
      } else if (ssscale > maxSSScale) {
maxSSScale = ssscale;
      }


      float distanceTo1 = (float)fabs(ssscale - 1.0f);
      if (distanceTo1 < bestDistanceTo1) {
bestSSScale = ssscale;
bestDistanceTo1 = distanceTo1;
      }
    }
  }
  if (minSSScale == maxSSScale) {
    // All subsessions are at the same scale: minSSScale == bestSSScale == maxSSScale
    scale = minSSScale;
    return;
  }


  // The scales for each subsession differ.  Try to set each one to the value
  // that's closest to 1:
  for (subsession = fSubsessionsHead; subsession != NULL;
       subsession = subsession->fNext) {
    float ssscale = bestSSScale;
    subsession->testScaleFactor(ssscale);
    if (ssscale != bestSSScale) break; // no luck
  }
  if (subsession == NULL) {
    // All subsessions are at the same scale: bestSSScale
    scale = bestSSScale;
    return;
  }


  // Still no luck.  Set each subsession's scale to 1:
  for (subsession = fSubsessionsHead; subsession != NULL;
       subsession = subsession->fNext) {
    float ssscale = 1;
    subsession->testScaleFactor(ssscale);
  }
  scale = 1;
}



float ServerMediaSession::duration() const {
  float minSubsessionDuration = 0.0;
  float maxSubsessionDuration = 0.0;

//这是在遍历sub session链表啊。
  for (ServerMediaSubsession* subsession = fSubsessionsHead; subsession != NULL;
       subsession = subsession->fNext) {
    // Hack: If any subsession supports seeking by 'absolute' time, then return a negative value, to indicate that only subsessions
    // will have a "a=range:" attribute:  如果有任意的sub session支持根据绝对时间来seek,那么返回一个负数,表示仅仅sub session 有 a=range: 属性
    char* absStartTime = NULL; char* absEndTime = NULL;
    subsession->getAbsoluteTimeRange(absStartTime, absEndTime);
    if (absStartTime != NULL) return -1.0f;


//选择所有子session中最大的那个,作为这个session 的duration
    float ssduration = subsession->duration();
    if (subsession == fSubsessionsHead) { // this is the first subsession
      minSubsessionDuration = maxSubsessionDuration = ssduration;
    } else if (ssduration < minSubsessionDuration) {
minSubsessionDuration = ssduration;
    } else if (ssduration > maxSubsessionDuration) {
maxSubsessionDuration = ssduration;
    }
  }


  if (maxSubsessionDuration != minSubsessionDuration) {
    return -maxSubsessionDuration; // because subsession durations differ
  } else {
    return maxSubsessionDuration; // all subsession durations are the same
  }
}


//咋个删掉所有的 sub session呢??
void ServerMediaSession::deleteAllSubsessions() {
  Medium::close(fSubsessionsHead);
  fSubsessionsHead = fSubsessionsTail = NULL;
  fSubsessionCounter = 0;

}


Boolean ServerMediaSession::isServerMediaSession() const {
  return True;
}


char* ServerMediaSession::generateSDPDescription() {
  AddressString ipAddressStr(ourIPAddress(envir()));  //ip 地址。。
  unsigned ipAddressStrSize = strlen(ipAddressStr.val());  //ip地址的长度


//填充sourceFilterLine  这个行。这个对ssm有效。
  // For a SSM sessions, we need a "a=source-filter: incl ..."line also:
  char* sourceFilterLine;
  if (fIsSSM) {
    char const* const sourceFilterFmt =
      "a=source-filter: incl IN IP4 * %s\r\n"
      "a=rtcp-unicast: reflection\r\n";
    unsigned const sourceFilterFmtSize = strlen(sourceFilterFmt) + ipAddressStrSize + 1;


    sourceFilterLine = new char[sourceFilterFmtSize];
    sprintf(sourceFilterLine, sourceFilterFmt, ipAddressStr.val());
  } else {
    sourceFilterLine = strDup("");
  }

//时间范围??
  char* rangeLine = NULL; // for now
  char* sdp = NULL; // for now


  do {
    // Count the lengths of each subsession's media-level SDP lines.
    // (We do this first, because the call to "subsession->sdpLines()"
    // causes correct subsession 'duration()'s to be calculated later.)
    unsigned sdpLength = 0;
    ServerMediaSubsession* subsession;
    for (subsession = fSubsessionsHead; subsession != NULL;
subsession = subsession->fNext) {
      char const* sdpLines = subsession->sdpLines();
      if (sdpLines == NULL) continue; // the media's not available
      sdpLength += strlen(sdpLines);
    }
    if (sdpLength == 0) break; // the session has no usable subsessions


    // Unless subsessions have differing durations, we also have a "a=range:" line:
    float dur = duration();
    if (dur == 0.0) {
      rangeLine = strDup("a=range:npt=0-\r\n");
    } else if (dur > 0.0) {
      char buf[100];
      sprintf(buf, "a=range:npt=0-%.3f\r\n", dur);
      rangeLine = strDup(buf);
    } else { // subsessions have differing durations, so "a=range:" lines go there
      rangeLine = strDup("");
    }


    char const* const sdpPrefixFmt =
      "v=0\r\n"
      "o=- %ld%06ld %d IN IP4 %s\r\n"
      "s=%s\r\n"
      "i=%s\r\n"
      "t=0 0\r\n"
      "a=tool:%s%s\r\n"
      "a=type:broadcast\r\n"
      "a=control:*\r\n"
      "%s"
      "%s"
      "a=x-qt-text-nam:%s\r\n"
      "a=x-qt-text-inf:%s\r\n"
      "%s";
    sdpLength += strlen(sdpPrefixFmt)
      + 20 + 6 + 20 + ipAddressStrSize
      + strlen(fDescriptionSDPString)
      + strlen(fInfoSDPString)
      + strlen(libNameStr) + strlen(libVersionStr)
      + strlen(sourceFilterLine)
      + strlen(rangeLine)
      + strlen(fDescriptionSDPString)
      + strlen(fInfoSDPString)
      + strlen(fMiscSDPLines);


    sdp = new char[sdpLength];
    if (sdp == NULL) break;



    // Generate the SDP prefix (session-level lines):
    sprintf(sdp, sdpPrefixFmt,
   fCreationTime.tv_sec, fCreationTime.tv_usec, // o= <session id>
   1, // o= <version>// (needs to change if params are modified)
   ipAddressStr.val(), // o= <address>
   fDescriptionSDPString, // s= <description>
   fInfoSDPString, // i= <info>
   libNameStr, libVersionStr, // a=tool:
   sourceFilterLine, // a=source-filter: incl (if a SSM session)
   rangeLine, // a=range: line
   fDescriptionSDPString, // a=x-qt-text-nam: line
   fInfoSDPString, // a=x-qt-text-inf: line
   fMiscSDPLines); // miscellaneous session SDP lines (if any)


    // Then, add the (media-level) lines foreachsubsession:
    char* mediaSDP = sdp;
    for (subsession = fSubsessionsHead; subsession != NULL;
subsession = subsession->fNext) {
      mediaSDP += strlen(mediaSDP);
      char const* sdpLines = subsession->sdpLines();
      if (sdpLines != NULL) sprintf(mediaSDP, "%s", sdpLines);
    }
  } while (0);


  delete[] rangeLine; delete[] sourceFilterLine;
  return sdp;
}




////////// ServerMediaSessionIterator //////////


ServerMediaSubsessionIterator
::ServerMediaSubsessionIterator(ServerMediaSession& session)
  : fOurSession(session) {
  reset();
}


ServerMediaSubsessionIterator::~ServerMediaSubsessionIterator() {
}


ServerMediaSubsession* ServerMediaSubsessionIterator::next() {
  ServerMediaSubsession* result = fNextPtr;


  if (fNextPtr != NULL) fNextPtr = fNextPtr->fNext;


  return result;
}


void ServerMediaSubsessionIterator::reset() {
  fNextPtr = fOurSession.fSubsessionsHead;
}





0 0
原创粉丝点击