live555 处理 sdp消息 四 "PLAY"

前言

live555 rtspserver端 创建并且接收客户端数据 根据rtsp 协议需要根据 handleRequestBytes 处理请求数据

而在 SETUP 请求中,已经准备好了 RTP_UDP 传输的socket,所以进行 PLAY 请求的处理
LIVE555 主要在函数 handleCmd_PLAY处理
但还是从handleRequestBytes 开始分析

PLAY请求数据 解析

首先是解析请求数据parseRTSPRequestString

log 如下:
···
PLAY rtsp://192.168.0.10:8554/H264Video.mkv/ RTSP/1.0
CSeq: 4

Range: npt=0-

Session: 817D3E3E

Date: Sat, 01 Jan 2000 04:50:00 GMT

cmdName “PLAY”, urlPreSuffix “H264Video.mkv”, urlSuffix “”, CSeq “4”, Content-Length 0, with 0 bytes following the message

sending REPORT
sending RTCP packet
80c80006 18be4fac bc17c32c 3d19dece 12d9fa8b 00000000 00000000 81ca0004 18be4fac 01096c6f 63616c68 6f737400

sending response:
RTSP/1.0 200 OK
CSeq: 4
Date: Sat, Jan 01 2000 00:05:00 GMT
Range: npt=0.000-
Session: 817D3E3E
RTP-Info: url=rtsp://192.168.0.10:8554/H264Video/track1;seq=30437;rtptime=316301736
···

处理 PLAY请求


clientSession->handleCmd_withinSession(this, cmdName, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer)
handleCmd_PLAY(ourClientConnection, subsession, fullRequestStr);
void RTSPServer::RTSPClientSession
::handleCmd_PLAY(RTSPServer::RTSPClientConnection* ourClientConnection,
         ServerMediaSubsession* subsession, char const* fullRequestStr) {

  // Create a "RTP-Info:" line.  It will get filled in from each subsession's state:
  char const* rtpInfoFmt =
    "%s" // "RTP-Info:", plus any preceding rtpInfo items
    "%s" // comma separator, if needed
    "url=%s/%s"
    ";seq=%d"
    ";rtptime=%u"
    ;  

  // Create the "Range:" header that we'll send back in our response.

  // Now, start streaming:
  for (i = 0; i < fNumStreamStates; ++i) {
    if (subsession == NULL /* means: aggregated operation */
    || subsession == fStreamStates[i].subsession) {

      fStreamStates[i].subsession->startStream(fOurSessionId,
                           fStreamStates[i].streamToken,
                           (TaskFunc*)noteClientLiveness, this,
                           rtpSeqNum, rtpTimestamp,
                           RTSPServer::RTSPClientConnection::handleAlternativeRequestByte, 
                           ourClientConnection);
    sprintf(rtpInfo, rtpInfoFmt, prevRTPInfo, numRTPInfoItems++ == 0 ? "" : ",",rtspURL, 
            urlSuffix,rtpSeqNum,rtpTimestamp);
    }
  }

  // Fill in the response:
  snprintf((char*)ourClientConnection->fResponseBuffer, 
  sizeof ourClientConnection->fResponseBuffer,
       "RTSP/1.0 200 OK\r\n"
       "CSeq: %s\r\n"
       "%s"
       "%s"
       "%s"
       "Session: %08X\r\n"
       "%s\r\n",
       ourClientConnection->fCurrentCSeq,
       dateHeader(),
       scaleHeader,
       rangeHeader,
       fOurSessionId,
       rtpInfo);
}

cmd play 请求的时候,会开始发送数据流
fStreamStates[i].subsession->startStream(…)

startStream 参数准备

下一步就是分析数据流,如何发送给客户端
传输的参数:
fOurSessionId,fStreamStates[i].streamToken
,(TaskFunc*)noteClientLiveness, this, rtpSeqNum, rtpTimestamp,
RTSPServer::RTSPClientConnection::handleAlternativeRequestByte, ourClientConnection

  • fOurSessionId :
    在CMD “SETUP”请求处理过程中在 createNewClientSessionWithId 创建ClientSession 产生的随机数
sessionId = (u_int32_t)our_random32();
  • fStreamStates[i].streamToken : 用来保存流的中状态 在”SETUP” 中创建
    struct streamState {
      ServerMediaSubsession* subsession;
      int tcpSocketNum;
      void* streamToken;
    } * fStreamStates;
void RTSPServer::RTSPClientSession
::handleCmd_SETUP(RTSPServer::RTSPClientConnection* ourClientConnection,
          char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr) {
    if (fStreamStates == NULL) {
      // This is the first "SETUP" for this session.  Set up our array of states for all of this session's subsessions (tracks):
      fStreamStates = new struct streamState[fNumStreamStates];

   for (unsigned i = 0; i < fNumStreamStates; ++i) {
    subsession = iter.next();
    fStreamStates[i].subsession = subsession;
    fStreamStates[i].tcpSocketNum = -1; // for now; may get set for RTP-over-TCP streaming
    fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later
      }
    }

}

而 session的建立 也是在SETUP中

ServerMediaSession* sms
      = fOurServer.lookupServerMediaSession(streamName, fOurServerMediaSession == NULL);

tcpSocketNum RTP-over-TCP 我们用的是RTP-over-UDP,不关心

streamToken: 在处理SETUP 请求handleCmd_SETUP会创建

void OnDemandServerMediaSubsession
::getStreamParameters(unsigned clientSessionId,
              netAddressBits clientAddress,
              Port const& clientRTPPort,
              Port const& clientRTCPPort,
              int tcpSocketNum,
              unsigned char rtpChannelId,
              unsigned char rtcpChannelId,
              netAddressBits& destinationAddress,
              u_int8_t& /*destinationTTL*/,
              Boolean& isMulticast,
              Port& serverRTPPort,
              Port& serverRTCPPort,
              void*& streamToken) {
    // Set up the state of the stream.  The stream will get started later:
    streamToken = fLastStreamToken
      = new StreamState(*this, serverRTPPort, serverRTCPPort, rtpSink, udpSink,
            streamBitrate, mediaSource,
            rtpGroupsock, rtcpGroupsock);
}
  • (TaskFunc*)noteClientLiveness
    回调函数 用来说明 session的connection , 还能判断是否超时rtcp处理 看log
Client session (id "817D3E3E", stream name "H264Video.mkv"): Liveness indication
  • rtpSeqNum = 0
  • rtpTimestamp 时间戳

  • RTSPServer::RTSPClientConnection::handleAlternativeRequestByte回调函数

  • ourClientConnection 指的是 RTSPServer::RTSPClientConnection 实例

开始传输视频流的流程

void OnDemandServerMediaSubsession::startStream(unsigned clientSessionId,
                        void* streamToken,
                        TaskFunc* rtcpRRHandler,
                        void* rtcpRRHandlerClientData,
                        unsigned short& rtpSeqNum,
                        unsigned& rtpTimestamp,
                        ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,
                        void* serverRequestAlternativeByteHandlerClientData) {
  StreamState* streamState = (StreamState*)streamToken;

  if (streamState != NULL) {
    streamState->startPlaying(destinations, clientSessionId,
                  rtcpRRHandler, rtcpRRHandlerClientData,
                  serverRequestAlternativeByteHandler, serverRequestAlternativeByteHandlerClientData);
  }
}
RTPSink->startPlaying(*fMediaSource, afterPlayingStreamState, this);  

/*
RTPSink ------------H264VideoRTPSink 
fMediaSource--------H264VideoStreamFramer / H264VideoStreamDiscreteFramer
this --------- StreamState
*/

最后走的方法是

MultiFramedRTPSink::buildAndSendPacket(Boolean isFirstPacket)

然后就是打包一帧

packFrame();

最后就是发送包

sendPacketIfNecessary();

上面的流程是大体的,还需要后面具体分析打包 过程

发送 RESPONSE 消息

上面的代码. fResponseBuffer 最后会被发送,通过 send 函数


猜你喜欢

转载自blog.csdn.net/engineer_james/article/details/81626673