国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

live555學(xué)習(xí)筆記6-建立RTP會話

2019-11-08 18:28:16
字體:
供稿:網(wǎng)友
六 建立RTP會話首先更正一個概念:ServerMediasession原先說代表一個流,其實(shí)是不準(zhǔn)確的。它代表的是server端的一個媒體的名字,而說ServerMediaSubsession代表一個Track是準(zhǔn)確的。以后流指的是那些有數(shù)據(jù)流動的組合。RTP的建立:RTP的建立過程無非是這樣:client告訴server自己的rtp/rtcp端口號,server建立自己的rtp/rtcp socket,然后在收到PLAY請求時向客戶端發(fā)數(shù)據(jù)。看起來非常簡單。在收到SETUP請求時才建立連接,讓我們看一下處理這個命令的函數(shù):[cpp] view plain copyvoid RTSPServer::RTSPClientSession::handleCmd_SETUP(          char const* cseq,          char const* url[cpp] view plain copyvoid 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)  {      if (destinationAddress == 0)          destinationAddress = clientAddress;          struct in_addr destinationAddr;      destinationAddr.s_addr = destinationAddress;      isMulticast = False;          //ServerMediaSubsession并沒有保存所有基于自己的數(shù)據(jù)流,而是只記錄了最后一次建立的數(shù)據(jù)流。      //利用這個變量和fReuseFirstSource可以實(shí)現(xiàn)多client連接到一個流的形式。      if (fLastStreamToken != NULL && fReuseFirstSource) {          //如果已經(jīng)基于這個ServerMediaSubsession創(chuàng)建了一個連接,并且希望使用這個連接          //則直接返回這個連接。          // Special case: Rather than creating a new 'StreamState',          // we reuse the one that we've already created:          serverRTPPort = ((StreamState*) fLastStreamToken)->serverRTPPort();          serverRTCPPort = ((StreamState*) fLastStreamToken)->serverRTCPPort();          ++((StreamState*) fLastStreamToken)->referenceCount();          streamToken = fLastStreamToken;      } else {          // Normal case: Create a new media source:          unsigned streamBitrate;          FramedSource* mediaSource = createNewStreamSource(clientSessionId,streamBitrate);              // Create 'groupsock' and 'sink' objects for the destination,          // using previously unused server port numbers:          RTPSink* rtpSink;          BasicUDPSink* udpSink;          Groupsock* rtpGroupsock;          Groupsock* rtcpGroupsock;          portNumBits serverPortNum;          if (clientRTCPPort.num() == 0) {              // We're streaming raw UDP (not RTP). Create a single groupsock:              NoReuse dummy; // ensures that we sk[cpp] view plain copyvoid RTSPServer::RTSPClientSession::handleCmd_PLAY(          ServerMediaSubsession* subsession,          char const* cseq,          char const* fullRequestStr)  {      char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession,fClientInputSocket);      unsigned rtspURLSize = strlen(rtspURL);          // Parse the client's "Scale:" header, if any:      float scale;      Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale);          // Try to set the stream's scale factor to this value:      if (subsession == NULL /*aggregate op*/) {          fOurServerMediaSession->testScaleFactor(scale);      } else {          subsession->testScaleFactor(scale);      }          char buf[100];      char* scaleHeader;      if (!sawScaleHeader) {          buf[0] = '/0'; // Because we didn't see a Scale: header, don't send one back      } else {          sprintf(buf, "Scale: %f/r/n", scale);      }      scaleHeader = strDup(buf);          //分析客戶端對于播放范圍的要求      // Parse the client's "Range:" header, if any:      double rangeStart = 0.0, rangeEnd = 0.0;      Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart,rangeEnd);          // Use this information, plus the stream's duration (if known), to create      // our own "Range:" header, for the response:      float duration = subsession == NULL /*aggregate op*/      ? fOurServerMediaSession->duration() : subsession->duration();      if (duration < 0.0) {          // We're an aggregate PLAY, but the subsessions have different durations.          // Use the largest of these durations in our header          duration = -duration;      }          // Make sure that "rangeStart" and "rangeEnd" (from the client's "Range:" header) have sane values      // before we send back our own "Range:" header in our response:      if (rangeStart < 0.0)          rangeStart = 0.0;      else if (rangeStart > duration)          rangeStart = duration;      if (rangeEnd < 0.0)          rangeEnd = 0.0;      else if (rangeEnd > duration)          rangeEnd = duration;      if ((scale > 0.0 && rangeStart > rangeEnd && rangeEnd > 0.0)              || (scale < 0.0 && rangeStart < rangeEnd)) {          // "rangeStart" and "rangeEnd" were the wrong way around; swap them:          double tmp = rangeStart;          rangeStart = rangeEnd;          rangeEnd = tmp;      }          char* rangeHeader;      if (!sawRangeHeader) {          buf[0] = '/0'; // Because we didn't see a Range: header, don't send one back      } else if (rangeEnd == 0.0 && scale >= 0.0) {          sprintf(buf, "Range: npt=%.3f-/r/n", rangeStart);      } else {          sprintf(buf, "Range: npt=%.3f-%.3f/r/n", rangeStart, rangeEnd);      }      rangeHeader = strDup(buf);          // 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";      unsigned rtpInfoFmtSize = strlen(rtpInfoFmt);      char* rtpInfo = strDup("RTP-Info: ");      unsigned i, numRTPInfoItems = 0;          // Do any required seeking/scaling on each subsession, before starting streaming:      for (i = 0; i < fNumStreamStates; ++i) {          if (subsession == NULL /* means: aggregated Operation */          || subsession == fStreamStates[i].subsession) {              if (sawScaleHeader) {                  fStreamStates[i].subsession->setStreamScale(fOurSessionId,                          fStreamStates[i].streamToken, scale);              }              if (sawRangeHeader) {                  double streamDuration = 0.0; // by default; means: stream until the end of the media                  if (rangeEnd > 0.0 && (rangeEnd + 0.001) < duration) { // the 0.001 is because we limited the values to 3 decimal places                      // We want the stream to end early.  Set the duration we want:                      streamDuration = rangeEnd - rangeStart;                      if (streamDuration < 0.0)                          streamDuration = -streamDuration; // should happen only if scale < 0.0                  }                  u_int64_t numBytes;                  fStreamStates[i].subsession->seekStream(fOurSessionId,                          fStreamStates[i].streamToken, rangeStart,                          streamDuration, numBytes);              }          }      }          // Now, start streaming:      for (i = 0; i < fNumStreamStates; ++i) {          if (subsession == NULL /* means: aggregated operation */                  || subsession == fStreamStates[i].subsession) {              unsigned short rtpSeqNum = 0;              unsigned rtpTimestamp = 0;              //啟動流              fStreamStates[i].subsession->startStream(fOurSessionId,                      fStreamStates[i].streamToken,                      (TaskFunc*) noteClientLiveness, this, rtpSeqNum,                      rtpTimestamp, handleAlternativeRequestByte, this);              const char *urlSuffix = fStreamStates[i].subsession->trackId();              char* prevRTPInfo = rtpInfo;              unsigned rtpInfoSize = rtpInfoFmtSize + strlen(prevRTPInfo) + 1                      + rtspURLSize + strlen(urlSuffix) + 5 /*max unsigned short len*/              + 10 /*max unsigned (32-bit) len*/              + 2 /*allows for trailing /r/n at final end of string*/;              rtpInfo = new char[rtpInfoSize];              sprintf(rtpInfo, rtpInfoFmt, prevRTPInfo,                      numRTPInfoItems++ == 0 ? "" : ",", rtspURL, urlSuffix,                      rtpSeqNum, rtpTimestamp);              delete[] prevRTPInfo;          }      }      if (numRTPInfoItems == 0) {          rtpInfo[0] = '/0';      } else {          unsigned rtpInfoLen = strlen(rtpInfo);          rtpInfo[rtpInfoLen] = '/r';          rtpInfo[rtpInfoLen + 1] = '/n';          rtpInfo[rtpInfoLen + 2] = '/0';      }          // Fill in the response:      snprintf((char*) fResponseBuffer, sizeof fResponseBuffer,              "RTSP/1.0 200 OK/r/n"                      "CSeq: %s/r/n"                      "%s"                      "%s"                      "%s"                      "Session: %08X/r/n"                      "%s/r/n", cseq, dateHeader(), scaleHeader, rangeHeader,              fOurSessionId, rtpInfo);      delete[] rtpInfo;      delete[] rangeHeader;      delete[] scaleHeader;      delete[] rtspURL;  }  有個問題,如果這個streamToken使用的是已存在的(還記得ReuseFirstSource嗎),為它再次調(diào)用startStream()時,究竟會做什么呢?你猜啊!呵呵我猜吧:應(yīng)該是把這個客戶端的地址和rtp/rtcp端口傳給rtp server的groupSocket,rtp server自然就開始向這個客戶端發(fā)送數(shù)據(jù)了。是不是這樣尼?看代碼吧:[cpp] view plain copyvoid StreamState::startPlaying(          Destinations* dests,          TaskFunc* rtcpRRHandler,          void* rtcpRRHandlerClientData,          ServerRequestAlternativeByteHandler* serverRequestAlternativeByteHandler,          void* serverRequestAlternativeByteHandlerClientData)   {      //目標(biāo)ip address rtp && rtcp port      if (dests == NULL)          return;          //創(chuàng)建RTCPInstance對象,以計算和收發(fā)RTCP包      if (fRTCPInstance == NULL && fRTPSink != NULL) {          // Create (and start) a 'RTCP instance' for this RTP sink:          fRTCPInstance = RTCPInstance::createNew(fRTPSink->envir(), fRTCPgs,                  fTotalBW, (unsigned char*) fMaster.fCNAME, fRTPSink,                  NULL /* we're a server */);          // Note: This starts RTCP running automatically      }          if (dests->isTCP) {          //如果RTP over TCP          // Change RTP and RTCP to use the TCP socket instead of UDP:          if (fRTPSink != NULL) {              fRTPSink->addStreamSocket(dests->tcpSocketNum, dests->rtpChannelId);              fRTPSink->setServerRequestAlternativeByteHandler(                      dests->tcpSocketNum, serverRequestAlternativeByteHandler,                      serverRequestAlternativeByteHandlerClientData);          }          if (fRTCPInstance != NULL) {              fRTCPInstance->addStreamSocket(dests->tcpSocketNum,                      dests->rtcpChannelId);              fRTCPInstance->setSpecificRRHandler(dests->tcpSocketNum,                      dests->rtcpChannelId, rtcpRRHandler,                      rtcpRRHandlerClientData);          }      } else {          //向RTP和RTCP的groupsocket增加這個目標(biāo)          // Tell the RTP and RTCP 'groupsocks' about this destination          // (in case they don't already have it):          if (fRTPgs != NULL)              fRTPgs->addDestination(dests->addr, dests->rtpPort);          if (fRTCPgs != NULL)              fRTCPgs->addDestination(dests->addr, dests->rtcpPort);          if (fRTCPInstance != NULL) {              fRTCPInstance->setSpecificRRHandler(dests->addr.s_addr,                      dests->rtcpPort, rtcpRRHandler, rtcpRRHandlerClientData);          }      }          if (!fAreCurrentlyPlaying && fMediaSource != NULL) {          //如果還沒有啟動傳輸,現(xiàn)在啟動之。          if (fRTPSink != NULL) {              fRTPSink->startPlaying(*fMediaSource, afterPlayingStreamState,                      this);              fAreCurrentlyPlaying = True;          } else if (fUDPSink != NULL) {              fUDPSink->startPlaying(*fMediaSource, afterPlayingStreamState,this);              fAreCurrentlyPlaying = True;          }      }  }  嘿嘿,還真的這樣嘀!
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 海林市| 徐闻县| 时尚| 佛学| 卓尼县| 黎平县| 浮梁县| 安徽省| 河东区| 松溪县| 密山市| 平顶山市| 油尖旺区| 偏关县| 滦平县| 沙湾县| 山阳县| 孝感市| 额尔古纳市| 江城| 定州市| 武功县| 常山县| 沙雅县| 三原县| 屯留县| 龙江县| 京山县| 策勒县| 通道| 舒城县| 岚皋县| 三原县| 长阳| 宜兰市| 石渠县| 安乡县| 富源县| 长岭县| 寻乌县| 吴川市|