[live555]live555笔记-RTSP流媒体服务(2)
voidRTSPServer::incomingConnectionHandler(intserverSocket) { structsockaddr_inclientAddr; SOCKLEN_T clientAddrLen = sizeof clientAddr; //接受连接 int clientSocket = accept (serverSocket, (structsocka
- void RTSPServer::incomingConnectionHandler(int serverSocket)
- {
- struct sockaddr_in clientAddr;
- SOCKLEN_T clientAddrLen = sizeof clientAddr;
- //接受连接
- int clientSocket = accept(serverSocket,
- (struct sockaddr*) &clientAddr,
- &clientAddrLen);
- if (clientSocket < 0) {
- int err = envir().getErrno();
- if (err != EWOULDBLOCK) {
- envir().setResultErrMsg("accept() failed: ");
- }
- return;
- }
- //设置socket的参数
- makeSocketNonBlocking(clientSocket);
- increaseSendBufferTo(envir(), clientSocket, 50 * 1024);
- #ifdef DEBUG
- envir() << "accept()ed connection from " << our_inet_ntoa(clientAddr.sin_addr) << "\n";
- #endif
- //产生一个sesson id
- // Create a new object for this RTSP session.
- // (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
- // a collision; the probability of two concurrent sessions getting the same session id is very low.)
- // (We do, however, avoid choosing session id 0, because that has a special use (by "OnDemandServerMediaSubsession").)
- unsigned sessionId;
- do {
- sessionId = (unsigned) our_random();
- } while (sessionId == 0);
- //创建RTSPClientSession,注意传入的参数
- (void) createNewClientSession(sessionId, clientSocket, clientAddr);
- }
RTSPClientSession要提供什么功能呢?可以想象:需要监听客户端的rtsp请求并回应它,需要在DESCRIBE请求中返回所请求的流的信息,需要在SETUP请求中建立起RTP会话,需要在TEARDOWN请求中关闭RTP会话,等等... RTSPClientSession要侦听客户端的请求,就需把自己的socket handler加入计划任务。证据如下:
- RTSPServer::RTSPClientSession::RTSPClientSession(
- RTSPServer& ourServer,
- unsigned sessionId,
- int clientSocket,
- struct sockaddr_in clientAddr) :
- fOurServer(ourServer),
- fOurSessionId(sessionId),
- fOurServerMediaSession(NULL),
- fClientInputSocket(clientSocket),
- fClientOutputSocket(clientSocket),
- fClientAddr(clientAddr),
- fSessionCookie(NULL),
- fLivenessCheckTask(NULL),
- fIsMulticast(False),
- fSessionIsActive(True),
- fStreamAfterSETUP(False),
- fTCPStreamIdCount(0),
- fNumStreamStates(0),
- fStreamStates(NULL),
- fRecursionCount(0)
- {
- // Arrange to handle incoming requests:
- resetRequestBuffer();
- envir().taskScheduler().turnOnBackgroundReadHandling(fClientInputSocket,
- (TaskScheduler::BackgroundHandlerProc*) &incomingRequestHandler,
- this);
- noteLiveness();
- }
下面重点讲一下下RTSPClientSession响应DESCRIBE请求的过程:
- void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE(
- char const* cseq,
- char const* urlPreSuffix,
- char const* urlSuffix,
- char const* fullRequestStr)
- {
- char* sdpDescription = NULL;
- char* rtspURL = NULL;
- do {
- //整理一下下RTSP地址
- char urlTotalSuffix[RTSP_PARAM_STRING_MAX];
- if (strlen(urlPreSuffix) + strlen(urlSuffix) + 2
- > sizeof urlTotalSuffix) {
- handleCmd_bad(cseq);
- break;
- }
- urlTotalSuffix[0] = '\0';
- if (urlPreSuffix[0] != '\0') {
- strcat(urlTotalSuffix, urlPreSuffix);
- strcat(urlTotalSuffix, "/");
- }
- strcat(urlTotalSuffix, urlSuffix);
- //验证帐户和密码
- if (!authenticationOK("DESCRIBE", cseq, urlTotalSuffix, fullRequestStr))
- break;
- // We should really check that the request contains an "Accept:" #####
- // for "application/sdp", because that's what we're sending back #####
- // Begin by looking up the "ServerMediaSession" object for the specified "urlTotalSuffix":
- //跟据流的名字查找ServerMediaSession,如果找不到,会创建一个。每个ServerMediaSession中至少要包含一个
- //ServerMediaSubsession。一个ServerMediaSession对应一个媒体,可以认为是Server上的一个文件,或一个实时获取设备。其包含的每个ServerMediaSubSession代表媒体中的一个Track。所以一个ServerMediaSession对应一个媒体,如果客户请求的媒体名相同,就使用已存在的ServerMediaSession,如果不同,就创建一个新的。一个流对应一个StreamState,StreamState与ServerMediaSubsession相关,但代表的是动态的,而ServerMediaSubsession代表静态的。
- ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlTotalSuffix);
- if (session == NULL) {
- handleCmd_notFound(cseq);
- break;
- }
- // Then, assemble a SDP description for this session:
- //获取SDP字符串,在函数内会依次获取每个ServerMediaSubSession的字符串然连接起来。
- sdpDescription = session->generateSDPDescription();
- if (sdpDescription == NULL) {
- // This usually means that a file name that was specified for a
- // "ServerMediaSubsession" does not exist.
- snprintf((char*) fResponseBuffer, sizeof fResponseBuffer,
- "RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n"
- "CSeq: %s\r\n"
- "%s\r\n", cseq, dateHeader());
- break;
- }
- unsigned sdpDescriptionSize = strlen(sdpDescription);
- // Also, generate our RTSP URL, for the "Content-Base:" header
- // (which is necessary to ensure that the correct URL gets used in
- // subsequent "SETUP" requests).
- rtspURL = fOurServer.rtspURL(session, fClientInputSocket);
- //形成响应DESCRIBE请求的RTSP字符串。
- snprintf((char*) fResponseBuffer, sizeof fResponseBuffer,
- "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
- "%s"
- "Content-Base: %s/\r\n"
- "Content-Type: application/sdp\r\n"
- "Content-Length: %d\r\n\r\n"
- "%s", cseq, dateHeader(), rtspURL, sdpDescriptionSize,
- sdpDescription);
- } while (0);
- delete[] sdpDescription;
- delete[] rtspURL;
- //返回后会被立即发送(没有把socket write操作放入计划任务中)。
- }
热门文章推荐
- [live555]live555直播rtsp流
- [live555]Live555学习资料及下载
- [live555]rtsp直播基于live555的实现
- [rtsp]海康Hikvision Tools(SADP搜索摄像头工具)下载
- [Live555]live555中处理mpeg4
- [NVR]海康网络摄像机录像时间怎么自定义设置
- [RTSP]RTSP常用方法实例
- [udp]为什么视频数据一般都用UDP协议进行传输
请稍候...