live555MediaServer几个构造过程详解

菜鸟初看live555,故做下笔记

MediaServer的主函数,代码没多少,但是前面的几个构造过程可谓是完成了大部分的工作啊

#include 
#include "DynamicRTSPServer.hh"
#include "version.hh"

int main(int argc, char** argv) {
  // Begin by setting up our usage environment:
  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);

  UserAuthenticationDatabase* authDB = NULL;
#ifdef ACCESS_CONTROL
  // To implement client access control to the RTSP server, do the following:
  authDB = new UserAuthenticationDatabase;
  authDB->addUserRecord("username1", "password1"); // replace these with real strings
  // Repeat the above with each ,  that you wish to allow
  // access to the server.
#endif

  // Create the RTSP server.  Try first with the default port number (554),
  // and then with the alternative port number (8554):
  RTSPServer* rtspServer;
  portNumBits rtspServerPortNum = 554;
  rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
  if (rtspServer == NULL) {
    rtspServerPortNum = 8554;
    rtspServer = DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);
  }
  if (rtspServer == NULL) {
    *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
    exit(1);
  }

  *env << "LIVE555 Media Server\n";
  *env << "\tversion " << MEDIA_SERVER_VERSION_STRING
       << " (LIVE555 Streaming Media library version "
       << LIVEMEDIA_LIBRARY_VERSION_STRING << ").\n";

  char* urlPrefix = rtspServer->rtspURLPrefix();
  *env << "Play streams from this server using the URL\n\t"
       << urlPrefix << "\nwhere  is a file present in the current directory.\n";
  *env << "Each file's type is inferred from its name suffix:\n";
  *env << "\t\".aac\" => an AAC Audio (ADTS format) file\n";
  *env << "\t\".amr\" => an AMR Audio file\n";
  *env << "\t\".m4e\" => a MPEG-4 Video Elementary Stream file\n";
  *env << "\t\".264\" => a H.264 Video Elementary Stream file\n";
  *env << "\t\".dv\" => a DV Video file\n";
  *env << "\t\".mp3\" => a MPEG-1 or 2 Audio file\n";
  *env << "\t\".mpg\" => a MPEG-1 or 2 Program Stream (audio+video) file\n";
  *env << "\t\".ts\" => a MPEG Transport Stream file\n";
  *env << "\t\t(a \".tsx\" index file - if present - provides server 'trick play' support)\n";
  *env << "\t\".wav\" => a WAV Audio file\n";
  *env << "See http://www.live555.com/mediaServer/ for additional documentation.\n";

  // Also, attempt to create a HTTP server for RTSP-over-HTTP tunneling.
  // Try first with the default HTTP port (80), and then with the alternative HTTP
  // port numbers (8000 and 8080).

  if (rtspServer->setUpTunnelingOverHTTP(80) || rtspServer->setUpTunnelingOverHTTP(8000) || rtspServer->setUpTunnelingOverHTTP(8080)) {
    *env << "(We use port " << rtspServer->httpServerPortNum() << " for optional RTSP-over-HTTP tunneling.)\n";
  } else {
    *env << "(RTSP-over-HTTP tunneling is not available.)\n";
  }

  env->taskScheduler().doEventLoop(); // does not return

  return 0; // only to prevent compiler warning
}

分析前面三个构造过程

一、BasicTaskScheduler初始化的构造过程
BasicTaskScheduler* BasicTaskScheduler::createNew() {
	return new BasicTaskScheduler();
}
/**************************************************/
BasicTaskScheduler::BasicTaskScheduler()
  : fMaxNumSockets(0) {
  FD_ZERO(&fReadSet);
  FD_ZERO(&fWriteSet);
  FD_ZERO(&fExceptionSet);

  schedulerTickTask(this); // ensures that we handle events frequently
							//这个函数没看懂
}
/**************************************************/
#define MAX_SCHEDULER_GRANULARITY 10000 // 10 microseconds: We will return to the event loop at least this often
static void schedulerTickTask(void* clientData) {
  ((BasicTaskScheduler*)clientData)->scheduleDelayedTask(MAX_SCHEDULER_GRANULARITY, schedulerTickTask, clientData);
}


二、BasicUsageEnvironment初始化的构造过程
BasicUsageEnvironment*
BasicUsageEnvironment::createNew(TaskScheduler& taskScheduler) {
  return new BasicUsageEnvironment(taskScheduler);
}
/**************************************************/
BasicUsageEnvironment::BasicUsageEnvironment(TaskScheduler& taskScheduler)
: BasicUsageEnvironment0(taskScheduler) {
#if defined(__WIN32__) || defined(_WIN32)//如果在window32系统下就进行winsock的初始化,否则就是一个宏直接返回1
  if (!initializeWinsockIfNecessary()) {
    setResultErrMsg("Failed to initialize 'winsock': ");//初始化失败则向标准错误输出错误信息
    reportBackgroundError();//把错误fputs到标准错误输出
    internalError();//终止程序
  }
#endif
}
/**************************************************/
BasicUsageEnvironment0(TaskScheduler& taskScheduler)
  : UsageEnvironment(taskScheduler),
    fBufferMaxSize(RESULT_MSG_BUFFER_MAX) {//最大的fBufferMaxSize初始化为1000
  reset();//将当前值设置为""只有'\0'空字符串
}
/**************************************************/
UsageEnvironment::UsageEnvironment(TaskScheduler& scheduler)
  : liveMediaPriv(NULL), groupsockPriv(NULL), fScheduler(scheduler) {//fScheduler 是TaskScheduler类的引用,无数据,
  //TaskScheduler类的构造函数是空函数,也执行了
}

三、DynamicRTSPServer初始化的构造过程


static DynamicRTSPServer* createNew(UsageEnvironment& env, Port ourPort,
				      UserAuthenticationDatabase* authDatabase,
				      unsigned reclamationTestSeconds = 65);//声明,最后一个参数如果不指定的话就是65
/**************************************************/															
DynamicRTSPServer*
DynamicRTSPServer::createNew(UsageEnvironment& env, Port ourPort,
			     UserAuthenticationDatabase* authDatabase,
			     unsigned reclamationTestSeconds) {
  int ourSocket = -1;

  do {
    int ourSocket = setUpOurSocket(env, ourPort);
    if (ourSocket == -1) break;

    return new DynamicRTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds);
  } while (0);

  if (ourSocket != -1) ::closeSocket(ourSocket);//如果前面break了也就是出错了,就会返回NULL
  return NULL;
}

/**************************************************/
int RTSPServer::setUpOurSocket(UsageEnvironment& env, Port& ourPort) {
  int ourSocket = -1;

  do {
    NoReuse dummy; // Don't use this socket if there's already a local server using it
					//定义了则会调用NoReuse()构造函数,将全局变量reuseFlag置为0,即不重用,析构函数将reuseFlag置为1

    ourSocket = setupStreamSocket(env, ourPort);//建立TCP的socket并绑定端口和INADDR_ANY,设置非阻塞
    if (ourSocket < 0) break;

    // Make sure we have a big send buffer:
    if (!increaseSendBufferTo(env, ourSocket, 50*1024)) break;//先获取原来的缓冲如果请求的缓冲大于原来的
																//则设置发送缓冲为所请求的缓冲大小

    // Allow multiple simultaneous connections:
    if (listen(ourSocket, LISTEN_BACKLOG_SIZE) < 0) {//监听最大的队列为20
      env.setResultErrMsg("listen() failed: ");
      break;
    }

    if (ourPort.num() == 0) {
      // bind() will have chosen a port for us; return it also:
      if (!getSourcePort(env, ourSocket, ourPort)) break;
    }

    return ourSocket;
  } while (0);

  if (ourSocket != -1) ::closeSocket(ourSocket);//没看懂
  return -1;
}

/**************************************************/
int setupStreamSocket(UsageEnvironment& env,
                      Port port, Boolean makeNonBlocking) {//makeNonBlocking不指定默认为非阻塞即为1
  if (!initializeWinsockIfNecessary()) {//window32系统下就进行winsock的初始化,否则就是一个宏直接返回1
    socketErr(env, "Failed to initialize 'winsock': ");
    return -1;
  }

  int newSocket = socket(AF_INET, SOCK_STREAM, 0);
  if (newSocket < 0) {
    socketErr(env, "unable to create stream socket: ");
    return newSocket;
  }

  if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR,
		 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {
    socketErr(env, "setsockopt(SO_REUSEADDR) error: ");
    closeSocket(newSocket);
    return -1;
  }

  // SO_REUSEPORT doesn't really make sense for TCP sockets, so we
  // normally don't set them.  However, if you really want to do this
  // #define REUSE_FOR_TCP
#ifdef REUSE_FOR_TCP
#if defined(__WIN32__) || defined(_WIN32)
  // Windoze doesn't properly handle SO_REUSEPORT
#else
#ifdef SO_REUSEPORT
  if (setsockopt(newSocket, SOL_SOCKET, SO_REUSEPORT,
		 (const char*)&reuseFlag, sizeof reuseFlag) < 0) {//reuseFlag为全局变量,初始值为1
    socketErr(env, "setsockopt(SO_REUSEPORT) error: ");
    closeSocket(newSocket);
    return -1;
  }
#endif
#endif
#endif

  // Note: Windoze requires binding, even if the port number is 0
#if defined(__WIN32__) || defined(_WIN32)
#else
  if (port.num() != 0 || ReceivingInterfaceAddr != INADDR_ANY) {
#endif
    MAKE_SOCKADDR_IN(name, ReceivingInterfaceAddr, port.num());//MAKE_SOCKADDR_IN为一个宏
    if (bind(newSocket, (struct sockaddr*)&name, sizeof name) != 0) {
      char tmpBuffer[100];
      sprintf(tmpBuffer, "bind() error (port number: %d): ",
	      ntohs(port.num()));
      socketErr(env, tmpBuffer);
      closeSocket(newSocket);
      return -1;
    }
#if defined(__WIN32__) || defined(_WIN32)
#else
  }
#endif

  if (makeNonBlocking) {
    if (!makeSocketNonBlocking(newSocket)) {
      socketErr(env, "failed to make non-blocking: ");
      closeSocket(newSocket);
      return -1;
    }
  }

  return newSocket;
}

/**************************************************/
DynamicRTSPServer::DynamicRTSPServer(UsageEnvironment& env, int ourSocket,
				     Port ourPort,
				     UserAuthenticationDatabase* authDatabase, unsigned reclamationTestSeconds)
  : RTSPServer(env, ourSocket, ourPort, authDatabase, reclamationTestSeconds) {//没啥好看的,只是起到一个过度作用调用父类的构造函数
}

/**************************************************/
RTSPServer::RTSPServer(UsageEnvironment& env,
		       int ourSocket, Port ourPort,
		       UserAuthenticationDatabase* authDatabase,
		       unsigned reclamationTestSeconds)
  : Medium(env),//调用父类的构造函数
    fRTSPServerSocket(ourSocket), fRTSPServerPort(ourPort),//把我们创建的socket交给RTSPServer来管理
    fHTTPServerSocket(-1), fHTTPServerPort(0), fClientSessionsForHTTPTunneling(NULL),//默认不用HTTP
    fAuthDB(authDatabase), fReclamationTestSeconds(reclamationTestSeconds),//这个值默认为65
    fServerMediaSessions(HashTable::create(STRING_HASH_KEYS)) {//STRING_HASH_KEYS为0,有重复生成了一份供RTSPServer使用
#ifdef USE_SIGNALS
  // Ignore the SIGPIPE signal, so that clients on the same host that are killed
  // don't also kill us:
  signal(SIGPIPE, SIG_IGN);//服务端必须忽略客户端死掉的信号,否则默认服务端也会终止
#endif

  // Arrange to handle connections from others:
  env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket,//中间过度了一下,请往下看278
						   (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this);
}

/**************************************************/
Medium::Medium(UsageEnvironment& env)
	: fEnviron(env), fNextTask(NULL) {//fEnviron 是UsageEnvironment的引用,fNextTask是void*指针
  // First generate a name for the new medium:
  MediaLookupTable::ourMedia(env)->generateNewName(fMediumName, mediumNameMaxLen);//MediaLookupTable是Medium的友元类
									//生成fMediumName名字,为liveMedia1,第一次fNameGenerator初始值为0,自增后为1
  env.setResultMsg(fMediumName);

  // Then add it to our table:
  MediaLookupTable::ourMedia(env)->addNew(this, fMediumName);//请往下看258行
}//回看188行
/**************************************************/
MediaLookupTable* MediaLookupTable::ourMedia(UsageEnvironment& env) {
  _Tables* ourTables = _Tables::getOurTables(env);//创建表, 请看行225
  if (ourTables->mediaTable == NULL) {//由行234可知这时候是NULL的
    // Create a new table to record the media that are to be created in
    // this environment:
    ourTables->mediaTable = new MediaLookupTable(env);//创建媒体查找表,用mediaTable指针来保存MediaLookupTable的指针,请往下看行237
  }
  return (MediaLookupTable*)(ourTables->mediaTable);//得到初始化创建了哈希表的指针,回看208
}
/**************************************************/
_Tables* _Tables::getOurTables(UsageEnvironment& env, Boolean createIfNotPresent) {//如果不存在则创建
  if (env.liveMediaPriv == NULL && createIfNotPresent) {//第一次先创建
    env.liveMediaPriv = new _Tables(env);//建立env.liveMediaPriv指针指向_Tables的关系,请往下看行233
  }
  return (_Tables*)(env.liveMediaPriv);//返回指向_Tables的指针,因为env.liveMediaPriv是void*型,所以要强制类型转换,回看217
}

/**************************************************/
_Tables::_Tables(UsageEnvironment& env)//初始化_Tables类的指针,且置为NULL,回看227
  : mediaTable(NULL), socketTable(NULL), fEnv(env) {
}
/**************************************************/
MediaLookupTable::MediaLookupTable(UsageEnvironment& env)
  : fEnv(env), fTable(HashTable::create(STRING_HASH_KEYS)), fNameGenerator(0) {//创建哈希表STRING_HASH_KEYS为0
																				//请往下看242
}

/**************************************************/
HashTable* HashTable::create(int keyType) {
  return new BasicHashTable(keyType);//起到过度作用,调用构造函数,请往下看248
}

/**************************************************/
BasicHashTable::BasicHashTable(int keyType)//对哈希表的一系列初始化操作,具体的数据没看懂是为什么设置
  : fBuckets(fStaticBuckets), fNumBuckets(SMALL_HASH_TABLE_SIZE),
    fNumEntries(0), fRebuildSize(SMALL_HASH_TABLE_SIZE*REBUILD_MULTIPLIER),
    fDownShift(28), fMask(0x3), fKeyType(keyType) {
  for (unsigned i = 0; i < SMALL_HASH_TABLE_SIZE; ++i) {//所有的指针都设置为NULL,回看220
    fStaticBuckets[i] = NULL;
  }
}
/**************************************************/
void* BasicHashTable::Add(char const* key, void* value) {//暂且不管,回看213
  void* oldValue;
  unsigned index;
  TableEntry* entry = lookupKey(key, index);
  if (entry != NULL) {
    // There's already an item with this key
    oldValue = entry->value;
  } else {
    // There's no existing entry; create a new one:
    entry = insertNewEntry(index, key);
    oldValue = NULL;
  }
  entry->value = value;

  // If the table has become too large, rebuild it with more buckets:
  if (fNumEntries >= fRebuildSize) rebuild();

  return oldValue;
}

/**************************************************/
void turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void* clientData) {
    setBackgroundHandling(socketNum, SOCKET_READABLE, handlerProc, clientData);//SOCKET_READABLE值为(1<<1),往下看283
  }
/**************************************************/
void BasicTaskScheduler
  ::setBackgroundHandling(int socketNum, int conditionSet, BackgroundHandlerProc* handlerProc, void* clientData) {
  if (socketNum < 0) return;
  FD_CLR((unsigned)socketNum, &fReadSet);//在集合中删除socketNum描述符
  FD_CLR((unsigned)socketNum, &fWriteSet);
  FD_CLR((unsigned)socketNum, &fExceptionSet);
  if (conditionSet == 0) {//conditionSet此时为2
    fHandlers->clearHandler(socketNum);
    if (socketNum+1 == fMaxNumSockets) {
      --fMaxNumSockets;
    }
  } else {
    fHandlers->assignHandler(socketNum, conditionSet, handlerProc, clientData);//请往下305
    if (socketNum+1 > fMaxNumSockets) {//为了select
      fMaxNumSockets = socketNum+1;
    }
    if (conditionSet&SOCKET_READABLE) FD_SET((unsigned)socketNum, &fReadSet);//第一次是可读的,把socketNum加到可读集合里
    if (conditionSet&SOCKET_WRITABLE) FD_SET((unsigned)socketNum, &fWriteSet);
    if (conditionSet&SOCKET_EXCEPTION) FD_SET((unsigned)socketNum, &fExceptionSet);//回看200
  }
}
/**************************************************/
void HandlerSet
::assignHandler(int socketNum, int conditionSet, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData) {
  // First, see if there's already a handler for this socket:
  HandlerDescriptor* handler = lookupHandler(socketNum);//请往下看319,第一次是找不到的,返回NULL
  if (handler == NULL) { // No existing handler, so create a new descr:
    handler = new HandlerDescriptor(fHandlers.fNextHandler);//申请一个描述符,请往下328
    handler->socketNum = socketNum;//初始化
  }

  handler->conditionSet = conditionSet;//要select的集合
  handler->handlerProc = handlerProc;//函数指针
  handler->clientData = clientData;//函数的参数,回看295
}
/**************************************************/
HandlerDescriptor* HandlerSet::lookupHandler(int socketNum) {
  HandlerDescriptor* handler;
  HandlerIterator iter(*this);
  while ((handler = iter.next()) != NULL) {
    if (handler->socketNum == socketNum) break;
  }
  return handler; 
}

HandlerDescriptor::HandlerDescriptor(HandlerDescriptor* nextHandler)
  : conditionSet(0), handlerProc(NULL) {//函数指针
  // Link this descriptor into a doubly-linked list:
  if (nextHandler == this) { // initialization
							//如果HandlerSet中的HandlerDescriptor fHandlers和新创建的相等
    fNextHandler = fPrevHandler = this;
  } else {
    fNextHandler = nextHandler;
    fPrevHandler = nextHandler->fPrevHandler;//没搞懂
    nextHandler->fPrevHandler = this;
    fPrevHandler->fNextHandler = this;//回看310
  }
}


你可能感兴趣的:(live555)