QTSS_Error DoPlay(QTSS_StandardRTSP_Params* inParams, ReflectorSession* inSession) { QTSS_Error theErr = QTSS_NoErr; UInt32 flags = 0; UInt32 theLen = 0; if (inSession == NULL) // it is a broadcast session so store the broadcast session. return QTSS_RequestFailed; else { UInt32 bitsPerSecond = inSession->GetBitRate(); (void)QTSS_SetValue(inParams->inClientSession, qtssCliSesMovieAverageBitRate, 0, &bitsPerSecond, sizeof(bitsPerSecond)); QTSS_Error theErr = QTSS_Play(inParams->inClientSession, inParams->inRTSPRequest, qtssPlayFlagsAppendServerInfo); if (theErr != QTSS_NoErr) return theErr; } OSRef* theRelaySessionRef = sClientSessionMap->Resolve(inSession->GetRef()->GetString()); if(theRelaySessionRef != NULL) { RTSPRelaySession* relaySes = (RTSPRelaySession*)theRelaySessionRef->GetObject(); QTSS_Error err = relaySes->Start(); sClientSessionMap->Release(theRelaySessionRef); } else { return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssServerInternal, 0); } (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, inParams->inClientSession, flags); 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 DoPlay(QTSS_StandardRTSP_Params* inParamBlock) { FileSession** theFile = NULL; UInt32 theLen = 0; QTSS_Error theErr = QTSS_GetValuePtr(inParamBlock->inClientSession, sFileSessionAttr, 0, (void**)&theFile, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*))) return QTSS_RequestFailed; Float64* theStartTime = 0; theErr = QTSS_GetValuePtr(inParamBlock->inRTSPRequest, qtssRTSPReqStartTime, 0, (void**)&theStartTime, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(Float64))) return QTSSModuleUtils::SendErrorResponse( inParamBlock->inRTSPRequest, qtssClientBadRequest, sSeekToNonexistentTimeErr); RTPFileSession::ErrorCode qtFileErr = (*theFile)->fFile.Seek(*theStartTime); if (qtFileErr != RTPFileSession::errNoError) return QTSSModuleUtils::SendErrorResponse( inParamBlock->inRTSPRequest, qtssClientBadRequest, sSeekToNonexistentTimeErr); //make sure to clear the next packet the server would have sent! (*theFile)->fPacketStruct.packetData = NULL; // Set the movie duration and size parameters Float64 movieDuration = (*theFile)->fFile.GetMovieDuration(); (void)QTSS_SetValue(inParamBlock->inClientSession, qtssCliSesMovieDurationInSecs, 0, &movieDuration, sizeof(movieDuration)); UInt64 movieSize = (*theFile)->fFile.GetAddedTracksRTPBytes(); (void)QTSS_SetValue(inParamBlock->inClientSession, qtssCliSesMovieSizeInBytes, 0, &movieSize, sizeof(movieSize)); //UInt32 bitsPerSecond = (*theFile)->fFile.GetBytesPerSecond() * 8; //(void)QTSS_SetValue(inParamBlock->inClientSession, qtssCliSesMovieAverageBitRate, 0, &bitsPerSecond, sizeof(bitsPerSecond)); // // For the purposes of the speed header, check to make sure all tracks are // over a reliable transport Bool16 allTracksReliable = true; // Set the timestamp & sequence number parameters for each track. QTSS_RTPStreamObject* theRef = NULL; for ( UInt32 theStreamIndex = 0; QTSS_GetValuePtr(inParamBlock->inClientSession, qtssCliSesStreamObjects, theStreamIndex, (void**)&theRef, &theLen) == QTSS_NoErr; theStreamIndex++) { UInt32* theTrackID = NULL; theErr = QTSS_GetValuePtr(*theRef, qtssRTPStrTrackID, 0, (void**)&theTrackID, &theLen); Assert(theErr == QTSS_NoErr); Assert(theTrackID != NULL); Assert(theLen == sizeof(UInt32)); SInt16 theSeqNum = (*theFile)->fFile.GetNextTrackSequenceNumber(*theTrackID); SInt32 theTimestamp = (*theFile)->fFile.GetSeekTimestamp(*theTrackID); Assert(theRef != NULL); Assert(theLen == sizeof(QTSS_RTPStreamObject)); theErr = QTSS_SetValue(*theRef, qtssRTPStrFirstSeqNumber, 0, &theSeqNum, sizeof(theSeqNum)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(*theRef, qtssRTPStrFirstTimestamp, 0, &theTimestamp, sizeof(theTimestamp)); Assert(theErr == QTSS_NoErr); if (allTracksReliable) { QTSS_RTPTransportType theTransportType = qtssRTPTransportTypeUDP; theLen = sizeof(theTransportType); theErr = QTSS_GetValue(*theRef, qtssRTPStrTransportType, 0, &theTransportType, &theLen); Assert(theErr == QTSS_NoErr); if (theTransportType == qtssRTPTransportTypeUDP) allTracksReliable = false; } } //Tell the server to start playing this movie. We do want it to send RTCP SRs, but //we DON'T want it to write the RTP header theErr = QTSS_Play(inParamBlock->inClientSession, inParamBlock->inRTSPRequest, qtssPlayFlagsSendRTCP); if (theErr != QTSS_NoErr) return theErr; // qtssRTPSesAdjustedPlayTimeInMsec is valid only after calling QTSS_Play // theAdjustedPlayTime is a way to delay the sending of data until a time after the // the Play response should have been received. SInt64* theAdjustedPlayTime = 0; theErr = QTSS_GetValuePtr(inParamBlock->inClientSession, qtssCliSesAdjustedPlayTimeInMsec, 0, (void**)&theAdjustedPlayTime, &theLen); Assert(theErr == QTSS_NoErr); Assert(theAdjustedPlayTime != NULL); Assert(theLen == sizeof(SInt64)); (*theFile)->fAdjustedPlayTime = *theAdjustedPlayTime; // // This module supports the Speed header if the client wants the stream faster than normal. Float32 theSpeed = 1; theLen = sizeof(theSpeed); theErr = QTSS_GetValue(inParamBlock->inRTSPRequest, qtssRTSPReqSpeed, 0, &theSpeed, &theLen); Assert(theErr != QTSS_BadArgument); Assert(theErr != QTSS_NotEnoughSpace); if (theErr == QTSS_NoErr) { if (theSpeed > sMaxAllowedSpeed) theSpeed = sMaxAllowedSpeed; if ((theSpeed <= 0) || (!allTracksReliable)) theSpeed = 1; } (*theFile)->fSpeed = theSpeed; if (theSpeed != 1) { // // If our speed is not 1, append the RTSP speed header in the response char speedBuf[32]; qtss_sprintf(speedBuf, "%10.5f", theSpeed); StrPtrLen speedBufPtr(speedBuf); (void)QTSS_AppendRTSPHeader(inParamBlock->inRTSPRequest, qtssSpeedHeader, speedBufPtr.Ptr, speedBufPtr.Len); } // // Record the requested start and stop time. (*theFile)->fStopTime = -1; theLen = sizeof((*theFile)->fStopTime); theErr = QTSS_GetValue(inParamBlock->inRTSPRequest, qtssRTSPReqStopTime, 0, &(*theFile)->fStopTime, &theLen); Assert(theErr == QTSS_NoErr); (*theFile)->fStartTime = 0; theLen = sizeof((*theFile)->fStopTime); theErr = QTSS_GetValue(inParamBlock->inRTSPRequest, qtssRTSPReqStartTime, 0, &(*theFile)->fStartTime, &theLen); Assert(theErr == QTSS_NoErr); //the client doesn't necessarily specify this information in a play, //if it doesn't, fall back on some defaults. if ((*theFile)->fStartTime == -1) (*theFile)->fStartTime = 0; (void)QTSS_SendStandardRTSPResponse(inParamBlock->inRTSPRequest, inParamBlock->inClientSession, qtssPlayRespWriteTrackInfo); return QTSS_NoErr; }