QTSS_Error DoSetup(QTSS_StandardRTSP_Params* inParams) { ReflectorSession* theSession = NULL; UInt32 len = sizeof(theSession); QTSS_GetValue(inParams->inRTSPSession, sRTSPBroadcastSessionAttr, 0, &theSession, &len); if(theSession == NULL) return QTSS_RequestFailed; Bool16 foundSession = false; UInt32 theLen = 0; RTPSessionOutput** theOutput = NULL; QTSS_Error theErr = QTSS_GetValuePtr(inParams->inClientSession, sOutputAttr, 0, (void**)&theOutput, &theLen); if (theLen != sizeof(RTPSessionOutput*)) { if (theErr != QTSS_NoErr) { RTPSessionOutput* theNewOutput = NEW RTPSessionOutput(inParams->inClientSession, theSession, sServerPrefs, sStreamCookieAttr ); theSession->AddOutput(theNewOutput,true); (void)QTSS_SetValue(inParams->inClientSession, sOutputAttr, 0, &theNewOutput, sizeof(theNewOutput)); } } //unless there is a digit at the end of this path (representing trackID), don't //even bother with the request char* theDigitStr = NULL; (void)QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileDigit, 0, &theDigitStr); QTSSCharArrayDeleter theDigitStrDeleter(theDigitStr); if (theDigitStr == NULL) { return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest,sExpectedDigitFilenameErr); } UInt32 theTrackID = ::strtol(theDigitStr, NULL, 10); // Get info about this trackID SourceInfo::StreamInfo* theStreamInfo = theSession->GetSourceInfo()->GetStreamInfoByTrackID(theTrackID); // If theStreamInfo is NULL, we don't have a legit track, so return an error if (theStreamInfo == NULL) return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, sReflectorBadTrackIDErr); StrPtrLen* thePayloadName = &theStreamInfo->fPayloadName; QTSS_RTPPayloadType thePayloadType = theStreamInfo->fPayloadType; StringParser parser(thePayloadName); parser.GetThru(NULL, '/'); theStreamInfo->fTimeScale = parser.ConsumeInteger(NULL); if (theStreamInfo->fTimeScale == 0) theStreamInfo->fTimeScale = 90000; QTSS_RTPStreamObject newStream = NULL; { // Ok, this is completely crazy but I can't think of a better way to do this that's // safe so we'll do it this way for now. Because the ReflectorStreams use this session's // stream queue, we need to make sure that each ReflectorStream is not reflecting to this // session while we call QTSS_AddRTPStream. One brutal way to do this is to grab each // ReflectorStream's mutex, which will stop every reflector stream from running. for (UInt32 x = 0; x < theSession->GetNumStreams(); x++) theSession->GetStreamByIndex(x)->GetMutex()->Lock(); theErr = QTSS_AddRTPStream(inParams->inClientSession, inParams->inRTSPRequest, &newStream, 0); for (UInt32 y = 0; y < theSession->GetNumStreams(); y++) theSession->GetStreamByIndex(y)->GetMutex()->Unlock(); if (theErr != QTSS_NoErr) return theErr; } // Set up dictionary items for this stream theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadName, 0, thePayloadName->Ptr, thePayloadName->Len); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadType, 0, &thePayloadType, sizeof(thePayloadType)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTrackID, 0, &theTrackID, sizeof(theTrackID)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTimescale, 0, &theStreamInfo->fTimeScale, sizeof(theStreamInfo->fTimeScale)); Assert(theErr == QTSS_NoErr); // We only want to allow over buffering to dynamic rate clients SInt32 canDynamicRate = -1; theLen = sizeof(canDynamicRate); (void) QTSS_GetValue(inParams->inRTSPRequest, qtssRTSPReqDynamicRateState, 0, (void*) &canDynamicRate, &theLen); if (canDynamicRate < 1) // -1 no rate field, 0 off (void)QTSS_SetValue(inParams->inClientSession, qtssCliSesOverBufferEnabled, 0, &sFalse, sizeof(sFalse)); // Place the stream cookie in this stream for future reference void* theStreamCookie = theSession->GetStreamCookie(theTrackID); Assert(theStreamCookie != NULL); theErr = QTSS_SetValue(newStream, sStreamCookieAttr, 0, &theStreamCookie, sizeof(theStreamCookie)); Assert(theErr == QTSS_NoErr); // Set the number of quality levels. static UInt32 sNumQualityLevels = ReflectorSession::kNumQualityLevels; theErr = QTSS_SetValue(newStream, qtssRTPStrNumQualityLevels, 0, &sNumQualityLevels, sizeof(sNumQualityLevels)); Assert(theErr == QTSS_NoErr); //send the setup response (void)QTSS_AppendRTSPHeader(inParams->inRTSPRequest, qtssCacheControlHeader, kCacheControlHeader.Ptr, kCacheControlHeader.Len); (void)QTSS_SendStandardRTSPResponse(inParams->inRTSPRequest, newStream, qtssSetupRespDontWriteSSRC); return QTSS_NoErr; }
QTSS_Error DoSetup(QTSS_StandardRTSP_Params* inParamBlock) { //setup this track in the file object FileSession* theFile = NULL; UInt32 theLen = sizeof(FileSession*); QTSS_Error theErr = QTSS_GetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, (void*)&theFile, &theLen); if ((theErr != QTSS_NoErr) || (theLen != sizeof(FileSession*))) { // This is possible, as clients are not required to send a DESCRIBE. If we haven't set // anything up yet, set everything up char* theFullPathStr = NULL; theErr = QTSS_GetValueAsString(inParamBlock->inRTSPRequest, qtssRTSPReqLocalPath, 0, &theFullPathStr); Assert(theErr == QTSS_NoErr); QTSSCharArrayDeleter theFullPathDeleter(theFullPathStr); StrPtrLen theFullPath(theFullPathStr); if ((theFullPath.Len <= sRTPSuffix.Len) || (!sRTPSuffix.NumEqualIgnoreCase(&theFullPath.Ptr[theFullPath.Len - sRTPSuffix.Len], sRTPSuffix.Len))) return QTSS_RequestFailed; theErr = CreateRTPFileSession(inParamBlock, theFullPath, &theFile); if (theErr != QTSS_NoErr) return theErr; // Store this newly created file object in the RTP session. theErr = QTSS_SetValue(inParamBlock->inClientSession, sFileSessionAttr, 0, &theFile, sizeof(theFile)); } //unless there is a digit at the end of this path (representing trackID), don't //even bother with the request char* theDigitStr = NULL; (void)QTSS_GetValueAsString(inParamBlock->inRTSPRequest, qtssRTSPReqFileDigit, 0, &theDigitStr); QTSSCharArrayDeleter theDigitStrDeleter(theDigitStr); if (theDigitStr == NULL) return QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest, qtssClientBadRequest, sExpectedDigitFilenameErr); UInt32 theTrackID = ::strtol(theDigitStr, NULL, 10); RTPFileSession::ErrorCode qtfileErr = theFile->fFile.AddTrack(theTrackID); //if we get an error back, forward that error to the client if (qtfileErr == RTPFileSession::errTrackDoesntExist) return QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest, qtssClientNotFound, sTrackDoesntExistErr); else if (qtfileErr != RTPFileSession::errNoError) return QTSSModuleUtils::SendErrorResponse(inParamBlock->inRTSPRequest, qtssUnsupportedMediaType, sBadQTFileErr); //find the payload for this track ID (if applicable) StrPtrLen* thePayload = NULL; UInt32 thePayloadType = qtssUnknownPayloadType; Float32 bufferDelay = (Float32) 3.0; // FIXME need a constant defined for 3.0 value. It is used multiple places for (UInt32 x = 0; x < theFile->fFile.GetSourceInfo()->GetNumStreams(); x++) { SourceInfo::StreamInfo* theStreamInfo = theFile->fFile.GetSourceInfo()->GetStreamInfo(x); if (theStreamInfo->fTrackID == theTrackID) { thePayload = &theStreamInfo->fPayloadName; thePayloadType = theStreamInfo->fPayloadType; bufferDelay = theStreamInfo->fBufferDelay; break; } } //Create a new RTP stream QTSS_RTPStreamObject newStream = NULL; theErr = QTSS_AddRTPStream(inParamBlock->inClientSession, inParamBlock->inRTSPRequest, &newStream, 0); if (theErr != QTSS_NoErr) return theErr; // Set the payload type, payload name & timescale of this track SInt32 theTimescale = theFile->fFile.GetTrackTimeScale(theTrackID); theErr = QTSS_SetValue(newStream, qtssRTPStrBufferDelayInSecs, 0, &bufferDelay, sizeof(bufferDelay)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadName, 0, thePayload->Ptr, thePayload->Len); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrPayloadType, 0, &thePayloadType, sizeof(thePayloadType)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTimescale, 0, &theTimescale, sizeof(theTimescale)); Assert(theErr == QTSS_NoErr); theErr = QTSS_SetValue(newStream, qtssRTPStrTrackID, 0, &theTrackID, sizeof(theTrackID)); Assert(theErr == QTSS_NoErr); // Set the number of quality levels. Allow up to 6 static UInt32 sNumQualityLevels = 0; theErr = QTSS_SetValue(newStream, qtssRTPStrNumQualityLevels, 0, &sNumQualityLevels, sizeof(sNumQualityLevels)); Assert(theErr == QTSS_NoErr); // Get the SSRC of this track UInt32* theTrackSSRC = NULL; UInt32 theTrackSSRCSize = 0; (void)QTSS_GetValuePtr(newStream, qtssRTPStrSSRC, 0, (void**)&theTrackSSRC, &theTrackSSRCSize); // The RTP stream should ALWAYS have an SSRC assuming QTSS_AddStream succeeded. Assert((theTrackSSRC != NULL) && (theTrackSSRCSize == sizeof(UInt32))); //give the file some info it needs. theFile->fFile.SetTrackSSRC(theTrackID, *theTrackSSRC); theFile->fFile.SetTrackCookie(theTrackID, newStream); // // Our array has now been updated to reflect the fields requested by the client. //send the setup response //(void)QTSS_AppendRTSPHeader(inParamBlock->inRTSPRequest, qtssLastModifiedHeader, // theFile->fFile.GetQTFile()->GetModDateStr(), DateBuffer::kDateBufferLen); (void)QTSS_AppendRTSPHeader(inParamBlock->inRTSPRequest, qtssCacheControlHeader, kCacheControlHeader.Ptr, kCacheControlHeader.Len); //send the setup response (void)QTSS_SendStandardRTSPResponse(inParamBlock->inRTSPRequest, newStream, 0); return QTSS_NoErr; }