·您当前的位置:首页 > 技术教程 > live555技术 >

[live555]live555笔记-RTSP流媒体服务(2)

时间:2015-03-26 10:54酷播
voidRTSPServer::incomingConnectionHandler(intserverSocket) { structsockaddr_inclientAddr; SOCKLEN_T clientAddrLen = sizeof clientAddr; //接受连接 int clientSocket = accept (serverSocket, (structsocka

  1. void RTSPServer::incomingConnectionHandler(int serverSocket)    
  2. {   
  3.     struct sockaddr_in clientAddr;   
  4.     SOCKLEN_T clientAddrLen = sizeof clientAddr;   
  5.        
  6.     //接受连接   
  7.     int clientSocket = accept(serverSocket,   
  8.             (struct sockaddr*) &clientAddr,   
  9.             &clientAddrLen);   
  10.        
  11.     if (clientSocket < 0) {   
  12.         int err = envir().getErrno();   
  13.         if (err != EWOULDBLOCK) {   
  14.             envir().setResultErrMsg("accept() failed: ");   
  15.         }   
  16.         return;   
  17.     }   
  18.        
  19.     //设置socket的参数   
  20.     makeSocketNonBlocking(clientSocket);   
  21.     increaseSendBufferTo(envir(), clientSocket, 50 * 1024);   
  22.    
  23. #ifdef DEBUG   
  24.     envir() << "accept()ed connection from " << our_inet_ntoa(clientAddr.sin_addr) << "\n";   
  25. #endif   
  26.    
  27.     //产生一个sesson id   
  28.        
  29.     // Create a new object for this RTSP session.   
  30.     // (Choose a random 32-bit integer for the session id (it will be encoded as a 8-digit hex number).  We don't bother checking for   
  31.     //  a collision; the probability of two concurrent sessions getting the same session id is very low.)   
  32.     // (We do, however, avoid choosing session id 0, because that has a special use (by "OnDemandServerMediaSubsession").)   
  33.     unsigned sessionId;   
  34.     do {   
  35.         sessionId = (unsigned) our_random();   
  36.     } while (sessionId == 0);   
  37.        
  38.     //创建RTSPClientSession,注意传入的参数   
  39.     (void) createNewClientSession(sessionId, clientSocket, clientAddr);   
  40. }   

RTSPClientSession要提供什么功能呢?可以想象:需要监听客户端的rtsp请求并回应它,需要在DESCRIBE请求中返回所请求的流的信息,需要在SETUP请求中建立起RTP会话,需要在TEARDOWN请求中关闭RTP会话,等等... RTSPClientSession要侦听客户端的请求,就需把自己的socket handler加入计划任务。证据如下:

  1. RTSPServer::RTSPClientSession::RTSPClientSession(   
  2.             RTSPServer& ourServer,   
  3.             unsigned sessionId,   
  4.             int clientSocket,   
  5.             struct sockaddr_in clientAddr) :   
  6.         fOurServer(ourServer),   
  7.         fOurSessionId(sessionId),   
  8.         fOurServerMediaSession(NULL),   
  9.         fClientInputSocket(clientSocket),   
  10.         fClientOutputSocket(clientSocket),   
  11.         fClientAddr(clientAddr),   
  12.         fSessionCookie(NULL),   
  13.         fLivenessCheckTask(NULL),   
  14.         fIsMulticast(False),   
  15.         fSessionIsActive(True),   
  16.         fStreamAfterSETUP(False),   
  17.         fTCPStreamIdCount(0),   
  18.         fNumStreamStates(0),   
  19.         fStreamStates(NULL),   
  20.         fRecursionCount(0)   
  21. {   
  22.     // Arrange to handle incoming requests:   
  23.     resetRequestBuffer();   
  24.     envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket,   
  25.             (TaskScheduler::BackgroundHandlerProc*) &incomingRequestHandler,   
  26.             this);   
  27.     noteLiveness();   
  28. }   

下面重点讲一下下RTSPClientSession响应DESCRIBE请求的过程:

  1. void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE(   
  2.         char const* cseq,   
  3.         char const* urlPreSuffix,   
  4.         char const* urlSuffix,   
  5.         char const* fullRequestStr)   
  6. {   
  7.     char* sdpDescription = NULL;   
  8.     char* rtspURL = NULL;   
  9.     do {   
  10.         //整理一下下RTSP地址   
  11.         char urlTotalSuffix[RTSP_PARAM_STRING_MAX];   
  12.         if (strlen(urlPreSuffix) + strlen(urlSuffix) + 2   
  13.                 > sizeof urlTotalSuffix) {   
  14.             handleCmd_bad(cseq);   
  15.             break;   
  16.         }   
  17.         urlTotalSuffix[0] = '\0';   
  18.         if (urlPreSuffix[0] != '\0') {   
  19.             strcat(urlTotalSuffix, urlPreSuffix);   
  20.             strcat(urlTotalSuffix, "/");   
  21.         }   
  22.         strcat(urlTotalSuffix, urlSuffix);   
  23.    
  24.    
  25.         //验证帐户和密码   
  26.         if (!authenticationOK("DESCRIBE", cseq, urlTotalSuffix, fullRequestStr))   
  27.             break;   
  28.    
  29.    
  30.         // We should really check that the request contains an "Accept:" #####   
  31.         // for "application/sdp", because that's what we're sending back #####   
  32.    
  33.    
  34.         // Begin by looking up the "ServerMediaSession" object for the specified "urlTotalSuffix":   
  35.         //跟据流的名字查找ServerMediaSession,如果找不到,会创建一个。每个ServerMediaSession中至少要包含一个   
  36.         //ServerMediaSubsession。一个ServerMediaSession对应一个媒体,可以认为是Server上的一个文件,或一个实时获取设备。其包含的每个ServerMediaSubSession代表媒体中的一个Track。所以一个ServerMediaSession对应一个媒体,如果客户请求的媒体名相同,就使用已存在的ServerMediaSession,如果不同,就创建一个新的。一个流对应一个StreamState,StreamState与ServerMediaSubsession相关,但代表的是动态的,而ServerMediaSubsession代表静态的。   
  37.         ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlTotalSuffix);   
  38.         if (session == NULL) {   
  39.             handleCmd_notFound(cseq);   
  40.             break;   
  41.         }   
  42.    
  43.    
  44.         // Then, assemble a SDP description for this session:   
  45.         //获取SDP字符串,在函数内会依次获取每个ServerMediaSubSession的字符串然连接起来。   
  46.         sdpDescription = session->generateSDPDescription();   
  47.         if (sdpDescription == NULL) {   
  48.             // This usually means that a file name that was specified for a   
  49.             // "ServerMediaSubsession" does not exist.   
  50.             snprintf((char*) fResponseBuffer, sizeof fResponseBuffer,   
  51.                     "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n"   
  52.                     "CSeq: %s\r\n"   
  53.                     "%s\r\n", cseq, dateHeader());   
  54.             break;   
  55.         }   
  56.         unsigned sdpDescriptionSize = strlen(sdpDescription);   
  57.    
  58.    
  59.         // Also, generate our RTSP URL, for the "Content-Base:" header   
  60.         // (which is necessary to ensure that the correct URL gets used in   
  61.         // subsequent "SETUP" requests).   
  62.         rtspURL = fOurServer.rtspURL(session, fClientInputSocket);   
  63.    
  64.    
  65.         //形成响应DESCRIBE请求的RTSP字符串。   
  66.         snprintf((char*) fResponseBuffer, sizeof fResponseBuffer,   
  67.                 "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"   
  68.                 "%s"   
  69.                 "Content-Base: %s/\r\n"   
  70.                 "Content-Type: application/sdp\r\n"   
  71.                 "Content-Length: %d\r\n\r\n"   
  72.                 "%s", cseq, dateHeader(), rtspURL, sdpDescriptionSize,   
  73.                 sdpDescription);   
  74.     } while (0);   
  75.    
  76.    
  77.     delete[] sdpDescription;   
  78.     delete[] rtspURL;   
  79.    
  80.    
  81.     //返回后会被立即发送(没有把socket write操作放入计划任务中)。   
  82. }   

 

热门文章推荐

请稍候...

保利威视云平台-轻松实现点播直播视频应用

酷播云数据统计分析跨平台播放器