QTSS_Error ProcessRTSPRequest(QTSS_StandardRTSP_Params* inParams) { QTSS_RTSPMethod* theMethod = NULL; UInt32 theMethodLen = 0; if ((QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqMethod, 0, (void**)&theMethod, &theMethodLen) != QTSS_NoErr) || (theMethodLen != sizeof(QTSS_RTSPMethod))) { Assert(0); return QTSS_RequestFailed; } switch (*theMethod) { case qtssDescribeMethod: return DoDescribe(inParams); case qtssSetupMethod: return DoSetup(inParams); case qtssPlayMethod: return DoPlay(inParams); case qtssTeardownMethod: // Tell the server that this session should be killed, and send a TEARDOWN response (void)QTSS_Teardown(inParams->inClientSession); (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0); break; case qtssPauseMethod: (void)QTSS_Pause(inParams->inClientSession); (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0); break; default: break; } return QTSS_NoErr; }
QTSS_Error ProcessRTSPRequest(QTSS_StandardRTSP_Params* inParams) { QTSS_RTSPMethod* theMethod = NULL; UInt32 theLen = 0; if ((QTSS_GetValuePtr(inParams->inRTSPRequest, qtssRTSPReqMethod, 0, (void**)&theMethod, &theLen) != QTSS_NoErr) || (theLen != sizeof(QTSS_RTSPMethod))) { Assert(0); return QTSS_RequestFailed; } if (*theMethod == qtssDescribeMethod) return DoDescribe(inParams); if (*theMethod == qtssSetupMethod) return DoSetup(inParams); RTPSessionOutput** theOutput = NULL; QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sOutputAttr, 0, (void**)&theOutput, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(RTPSessionOutput*))) // a broadcaster push session { if (*theMethod == qtssPlayMethod || *theMethod == qtssRecordMethod) return DoPlay(inParams, NULL); else return QTSS_RequestFailed; } switch (*theMethod) { case qtssPlayMethod: return DoPlay(inParams, (*theOutput)->GetReflectorSession()); case qtssTeardownMethod: // Tell the server that this session should be killed, and send a TEARDOWN response (void)QTSS_Teardown(inParams->inClientSession); (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0); break; case qtssPauseMethod: (void)QTSS_Pause(inParams->inClientSession); (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, 0); break; default: break; } return QTSS_NoErr; }
QTSS_Error DoRequestPostProcessing(ProxyClientInfo* inProxyClientInfo, QTSS_RTSPRequestObject inRequest, QTSS_ClientSessionObject inClientSession) { QTSS_RTSPMethod* theMethod = NULL; UInt32 theLen = 0; QTSS_Error theErr = QTSS_GetValuePtr(inRequest, qtssRTSPReqMethod, 0, (void**)&theMethod, &theLen); Assert(theErr == QTSS_NoErr); char theTransportHeaderBuf[128]; StrPtrLen theTransportHeader(theTransportHeaderBuf, 0); StrPtrLen theSessionID; theErr = QTSS_GetValuePtr(inClientSession, qtssCliSesRTSPSessionID, 0, (void**)&theSessionID.Ptr, &theSessionID.Len); Assert(theErr == QTSS_NoErr); StrPtrLen theResponse(inProxyClientInfo->GetRTSPClient()->GetResponse(), inProxyClientInfo->GetRTSPClient()->GetResponseLen()); if ((*theMethod == qtssSetupMethod) && (inProxyClientInfo->GetRTSPClient()->GetStatus() == 200)) { ProxyDemuxerTask* thisStreamsDemuxer = inProxyClientInfo->GetLastDemuxerTask(); thisStreamsDemuxer->SetOriginServerPort(inProxyClientInfo->GetRTSPClient()->GetServerPort()); // // Build a new Transport header. This should basically be exactly what the // server would be sending back if the proxy module wasn't generating the response UInt16 theSvrRTPPort = 0; UInt16 theCliRTPPort = 0; UInt32 theLen = sizeof(theSvrRTPPort); theErr = QTSS_GetValue(thisStreamsDemuxer->GetStream(), qtssRTPStrSvrRTPPort, 0, &theSvrRTPPort, &theLen); Assert(theErr == QTSS_NoErr); theErr = QTSS_GetValue(thisStreamsDemuxer->GetStream(), qtssRTPStrClientRTPPort, 0, &theCliRTPPort, &theLen); Assert(theErr == QTSS_NoErr); char theIPAddrStr[20]; theLen = 20; theErr = QTSS_GetValue(inClientSession, qtssCliRTSPSessLocalAddrStr, 0, &theIPAddrStr[0], &theLen); Assert(theErr == QTSS_NoErr); theIPAddrStr[theLen] = '\0'; qtss_sprintf(theTransportHeader.Ptr, "Transport: RTP/AVP;unicast;client_port=%d-%d;server_port=%d-%d;source=%s\r\n", theCliRTPPort, theCliRTPPort + 1, theSvrRTPPort, theSvrRTPPort + 1, theIPAddrStr); theTransportHeader.Len = ::strlen(theTransportHeader.Ptr); } else if ((*theMethod == qtssPlayMethod) && (inProxyClientInfo->GetRTSPClient()->GetStatus() == 200)) { // // The client session needs to know that we are entering the playing state. // Otherwise, when we write RTP packet data to the QTSS_RTPStreamObjects, // the server won't really be able to figure out what to do with the packets. theErr = QTSS_Play(inClientSession, inRequest, 0); if (theErr != QTSS_NoErr) { Assert(theErr == QTSS_RequestFailed); return theErr; } } else if ((*theMethod == qtssPauseMethod) && (inProxyClientInfo->GetRTSPClient()->GetStatus() == 200)) { // // Same thing as above, just let the server know that we are no longer playing theErr = QTSS_Pause(inClientSession); Assert(theErr == QTSS_NoErr); } // // Build our ioVec with the new response // When building the iovec used for the response, we need to leave the first // iovec in the array empty, per QTSS API conventions. iovec theNewResponse[7]; theNewResponse[0].iov_len = 0; UInt32 totalResponseLen = 0; // // Internally, the server keeps an RTSP Session ID for this QTSS_ClientSessionObject. // We need to replace the one the upstream server has given us with this server's // RTSP Session ID. Otherwise, when the server receives the next RTSP request, // this server will not be able to map the RTSP session ID properly. UInt32 theNumVecs = ReplaceSessionAndTransportHeaders(&theResponse, &theNewResponse[1], &theSessionID, &theTransportHeader, &totalResponseLen); theNumVecs++; // Take into account that the first one is empty // // Also add in the content body of the response if there is one theNewResponse[theNumVecs].iov_base = inProxyClientInfo->GetRTSPClient()->GetContentBody(); theNewResponse[theNumVecs].iov_len = inProxyClientInfo->GetRTSPClient()->GetContentLength(); totalResponseLen += theNewResponse[theNumVecs].iov_len; theNumVecs++; UInt32 lenWritten = 0; theErr = QTSS_WriteV(inRequest, theNewResponse, theNumVecs, totalResponseLen, &lenWritten); Assert(lenWritten == totalResponseLen); Assert(theErr == QTSS_NoErr); return QTSS_NoErr; }
QTSS_Error SendPackets(QTSS_RTPSendPackets_Params* inParams) { FileSession** theFile = NULL; UInt32 theLen = 0; QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sFileSessionAttr, 0, (void**)&theFile, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*))) { Assert( 0 ); return QTSS_RequestFailed; } while (true) { if ((*theFile)->fPacketStruct.packetData == NULL) { void* theCookie = NULL; Float64 theTransmitTime = (*theFile)->fFile.GetNextPacket((UInt8**)&(*theFile)->fPacketStruct.packetData, &(*theFile)->fNextPacketLen, &theCookie); // // Check to see if we should stop playing based on a client specified stop time if (((*theFile)->fStopTime != -1) && (theTransmitTime > (*theFile)->fStopTime)) { // We should indeed stop playing (void)QTSS_Pause(inParams->inClientSession); inParams->outNextPacketTime = qtssDontCallSendPacketsAgain; return QTSS_NoErr; } // // Adjust transmit time based on speed Float64 theOffsetFromStartTime = theTransmitTime - (*theFile)->fStartTime; theTransmitTime = (*theFile)->fStartTime + (theOffsetFromStartTime / (*theFile)->fSpeed); (*theFile)->fStream = (QTSS_RTPStreamObject)theCookie; (*theFile)->fPacketStruct.packetTransmitTime = (*theFile)->fAdjustedPlayTime + ((SInt64)(theTransmitTime * 1000)); #if RTP_FILE_MODULE_DEBUGGING >= 8 UInt16* theSeqNumPtr = (UInt16*)(*theFile)->fNextPacket; UInt32* theTimestampP = (UInt32*)(*theFile)->fNextPacket; UInt32* theTrackID = NULL; (void)QTSS_GetValuePtr((*theFile)->fStream, qtssRTPStrTrackID, 0, (void**)&theTrackID, &theLen); qtss_printf("Got packet. Seq num: %d. Timestamp: %d. TrackID: %d. Transmittime: %f\n",theSeqNumPtr[1], theTimestampP[1], *theTrackID, theTransmitTime); #endif } //We are done playing all streams! if ((*theFile)->fPacketStruct.packetData == NULL) { #if RTP_FILE_MODULE_DEBUGGING >= 8 qtss_printf("done w all packets\n"); #endif inParams->outNextPacketTime = qtssDontCallSendPacketsAgain; return QTSS_NoErr; } //we have a packet that needs to be sent now Assert((*theFile)->fStream != NULL); // Send the packet! theErr = QTSS_Write((*theFile)->fStream, &(*theFile)->fPacketStruct, (*theFile)->fNextPacketLen, NULL, qtssWriteFlagsIsRTP); if ( theErr == QTSS_WouldBlock ) { if ((*theFile)->fPacketStruct.packetTransmitTime == -1) inParams->outNextPacketTime = sFlowControlProbeInterval; // for buffering, try me again in # MSec else { Assert((*theFile)->fPacketStruct.packetTransmitTime > inParams->inCurrentTime); inParams->outNextPacketTime = (*theFile)->fPacketStruct.packetTransmitTime - inParams->inCurrentTime; } return QTSS_NoErr; } (*theFile)->fPacketStruct.packetData = NULL; } Assert(0); return QTSS_NoErr; }