[live555] 从testRTSPClient.cpp SETUP请求 三

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/engineer_james/article/details/82467832

前言

在DESCRIBE 请求流程,已经将 live555 处理机制走了一遍,所以在SETUP请求过程中也是适用的

SETUP

rtspClient->sendSetupCommand(*scs.subsession, continueAfterSETUP, False, REQUEST_STREAMING_OVER_TCP);

unsigned RTSPClient::sendSetupCommand(MediaSubsession& subsession
	, responseHandler* responseHandler
	,Boolean streamOutgoing
	, Boolean forceMulticastOnUnspecified
	, Authenticator* authenticator) {
 //...
  return sendRequest(new RequestRecord(++fCSeq, "SETUP", responseHandler
	  , NULL, &subsession, booleanFlags));
}

所以在sendRequest方法中因为已经打开了socket所以只是将 SETUP请求放入 fRequestsAwaitingConnection队列中

unsigned RTSPClient::sendRequest(RequestRecord* request) {
//....
    if (fTunnelOverHTTPPortNum == 0 
	    || strcmp(request->commandName(), "POST") != 0) {
      fRequestsAwaitingResponse.enqueue(request);
    } 
}

在事件轮询的时候,即 SingleStep 中处理
最后回调request 请求的回调函数 handlerProc ,SETUP请求的回调是continueAfterSETUP

continueAfterSETUP

  1. 创建sink 用来准备接收数据
  2. 准备接收
  3. 发起PLAY请求
void continueAfterSETUP(RTSPClient* rtspClient, int resultCode
											, char* resultString) {

  do {
    UsageEnvironment& env = rtspClient->envir(); // alias
    StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
	//创建sink 接收数据
    scs.subsession->sink = DummySink::createNew(env, *scs.subsession
		    , rtspClient->url());

    //开始播放
    scs.subsession->sink->startPlaying(*(scs.subsession->readSource()),
				       subsessionAfterPlaying, scs.subsession);
  } while (0);

  // Set up the next subsession, if any:
  setupNextSubsession(rtspClient);
}

startPlaying

主流程如下图:
startPlaying

最关键数据读取和处理在MultiFramedRTPSource::doGetNextFrame

  1. 将网络传输的RTP包读取放在事件轮询中处理,通过networkReadHandler 读取
  2. doGetNextFrame1 中判断读取buffer数据的情况,进行下一帧读取或者结束
void MultiFramedRTPSource::doGetNextFrame() {
  if (!fAreDoingNetworkReads) {
    // Turn on background read handling of incoming packets:
    fAreDoingNetworkReads = True;
    TaskScheduler::BackgroundHandlerProc* handler
      = (TaskScheduler::BackgroundHandlerProc*)&networkReadHandler;
    fRTPInterface.startNetworkReading(handler);
  }

  fSavedTo = fTo;
  fSavedMaxSize = fMaxSize;
  fFrameSize = 0; // for now
  fNeedDelivery = True;
  doGetNextFrame1();
}

通过了轮询不断读取服务器端读过来的数据,即使用networkReadHandler 不断轮询回调,而networkReadHandler具体操作

void MultiFramedRTPSource::networkReadHandler1() {
  BufferedPacket* bPacket = fPacketReadInProgress;
  if (bPacket == NULL) {
    bPacket = fReorderingBuffer->getFreePacket(this);
  }

  // Read the network packet, and perform sanity checks on the RTP header:
  Boolean readSuccess = False;
  do {
    if (!bPacket->fillInData(fRTPInterface, fromAddress, packetReadWasIncomplete)) {
      fPacketReadInProgress = NULL;
      break;
    }

	/××
	 × 对RTP包进行预处理,RTP Header 处理
	 ×/

 
    if (!fReorderingBuffer->storePacket(bPacket)) break;

    readSuccess = True;
  } while (0);

  doGetNextFrame1();
  // If we didn't get proper data this time, we'll get another chance
}

在bPacket中填充数据 fillInData

readSuccess = fGS->handleRead(buffer, bufferMaxSize, bytesRead, fromAddress);
Boolean Groupsock::handleRead(unsigned char* buffer, unsigned bufferMaxSize,
			      unsigned& bytesRead,
			      struct sockaddr_in& fromAddressAndPort) {
			      //... 从之前创建的socket 中读取数据通过numBytes判断成功还是失败
  int numBytes = readSocket(env(), socketNum(),
			    buffer, maxBytesToRead, fromAddressAndPort);
}

而doGetNextFrame1 如果继续下一帧读取,会继续回调DummySink::afterGettingFrame ,又是读取一帧的流程,因为在SETUP 步骤,还没有发送PLAY请求,所以服务器端不会有数据传过来,一直轮询等待
判断地方:

void MultiFramedRTPSource::doGetNextFrame1() {
    BufferedPacket* nextPacket
      = fReorderingBuffer->getNextCompletedPacket(packetLossPrecededThis);
    if (nextPacket == NULL) break;
	//.....
}

最后接收数据都会在 fReceiveBuffer,因为

Boolean DummySink::continuePlaying() {
  if (fSource == NULL) return False; // sanity check (should not happen)

  // Request the next frame of data from our input source.  "afterGettingFrame()" will get called later, when it arrives:
  fSource->getNextFrame(fReceiveBuffer, DUMMY_SINK_RECEIVE_BUFFER_SIZE,
                        afterGettingFrame, this,
                        onSourceClosure, this);
  return True;
}

因为DummySink 没有对接收的包处理,所以暂时只能抓数据但是没有解码出来

对SETUP请求response消息处理

在事件轮询中已经将 SETUP PLAY 等返回消息进行处理

void RTSPClient::handleResponseBytes(int newBytesRead) {

	if (responseCode == 200) {
	  // Do special-case response handling for some commands:
	  if (strcmp(foundRequest->commandName(), "SETUP") == 0) {
		if (!handleSETUPResponse(*foundRequest->subsession(), sessionParamsStr, transportParamsStr, foundRequest->booleanFlags()&0x1)) break;
	  } else if (strcmp(foundRequest->commandName(), "PLAY") == 0) {
		if (!handlePLAYResponse(foundRequest->session(), foundRequest->subsession(), scaleParamsStr, speedParamsStr, rangeParamsStr, rtpInfoParamsStr)) break;
	  } else if (strcmp(foundRequest->commandName(), "TEARDOWN") == 0) {
		if (!handleTEARDOWNResponse(*foundRequest->session(), *foundRequest->subsession())) break;
	  } else if (strcmp(foundRequest->commandName(), "GET_PARAMETER") == 0) {
		if (!handleGET_PARAMETERResponse(foundRequest->contentStr(), bodyStart, responseEnd)) break;
	  }
	} 

}

猜你喜欢

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