char* SDPSourceInfo::GetLocalSDP(UInt32* newSDPLen) { Assert(fSDPData.Ptr != NULL); bool appendCLine = true; UInt32 trackIndex = 0; char *localSDP = new char[fSDPData.Len * 2]; OSCharArrayDeleter charArrayPathDeleter(localSDP); StringFormatter localSDPFormatter(localSDP, fSDPData.Len * 2); StrPtrLen sdpLine; StringParser sdpParser(&fSDPData); char trackIndexBuffer[50]; // Only generate our own trackIDs if this file doesn't have 'em. // Our assumption here is that either the file has them, or it doesn't. // A file with some trackIDs, and some not, won't work. bool hasControlLine = false; while (sdpParser.GetDataRemaining() > 0) { //stop when we reach an empty line. sdpParser.GetThruEOL(&sdpLine); if (sdpLine.Len == 0) continue; switch (*sdpLine.Ptr) { case 'c': break;//ignore connection information case 'm': { //append new connection information right before the first 'm' if (appendCLine) { localSDPFormatter.Put(sCLine); localSDPFormatter.PutEOL(); if (!hasControlLine) { localSDPFormatter.Put(sControlLine); localSDPFormatter.PutEOL(); } appendCLine = false; } //the last "a=" for each m should be the control a= if ((trackIndex > 0) && (!hasControlLine)) { qtss_sprintf(trackIndexBuffer, "a=control:trackID=%" _S32BITARG_ "\r\n",trackIndex); localSDPFormatter.Put(trackIndexBuffer, ::strlen(trackIndexBuffer)); } //now write the 'm' line, but strip off the port information StringParser mParser(&sdpLine); StrPtrLen mPrefix; mParser.ConsumeUntil(&mPrefix, StringParser::sDigitMask); localSDPFormatter.Put(mPrefix); localSDPFormatter.Put("0", 1); (void)mParser.ConsumeInteger(NULL); localSDPFormatter.Put(mParser.GetCurrentPosition(), mParser.GetDataRemaining()); localSDPFormatter.PutEOL(); trackIndex++; break; } case 'a': { StringParser aParser(&sdpLine); aParser.ConsumeLength(NULL, 2);//go past 'a=' StrPtrLen aLineType; aParser.ConsumeWord(&aLineType); if (aLineType.Equal(sControlStr)) { aParser.ConsumeUntil(NULL, '='); aParser.ConsumeUntil(NULL, StringParser::sDigitMask); StrPtrLen aDigitType; (void)aParser.ConsumeInteger(&aDigitType); if (aDigitType.Len > 0) { localSDPFormatter.Put("a=control:trackID=", 18); localSDPFormatter.Put(aDigitType); localSDPFormatter.PutEOL(); hasControlLine = true; break; } } localSDPFormatter.Put(sdpLine); localSDPFormatter.PutEOL(); break; } default: { localSDPFormatter.Put(sdpLine); localSDPFormatter.PutEOL(); } } } if ((trackIndex > 0) && (!hasControlLine)) { qtss_sprintf(trackIndexBuffer, "a=control:trackID=%" _S32BITARG_ "\r\n",trackIndex); localSDPFormatter.Put(trackIndexBuffer, ::strlen(trackIndexBuffer)); } *newSDPLen = (UInt32)localSDPFormatter.GetCurrentOffset(); StrPtrLen theSDPStr(localSDP, *newSDPLen);//localSDP is not 0 terminated so initialize theSDPStr with the len. SDPContainer rawSDPContainer; (void) rawSDPContainer.SetSDPBuffer( &theSDPStr ); SDPLineSorter sortedSDP(&rawSDPContainer); return sortedSDP.GetSortedSDPCopy(); // return a new copy of the sorted SDP }
QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams) { char* theUriStr = NULL; QTSS_Error err = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileName, 0, &theUriStr); Assert(err == QTSS_NoErr); if(err != QTSS_NoErr) return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, 0); QTSSCharArrayDeleter theUriStrDeleter(theUriStr); //从接口获取信息结构体 //TODO: DeviceInfo* pDeviceInfo = parseDevice->GetDeviceInfoByIdName(theUriStr); if(pDeviceInfo == NULL) { qtss_printf("ID:%s Not Found\n",theUriStr); return QTSS_RequestFailed; } //信息存在rtsp://59.46.115.84:8554/h264/ch1/sub/av_stream RTSPRelaySession* clientSes = NULL; //首先查找Map里面是否已经有了对应的流 StrPtrLen streamName(theUriStr); OSRef* clientSesRef = sClientSessionMap->Resolve(&streamName); if(clientSesRef != NULL) { clientSes = (RTSPRelaySession*)clientSesRef->GetObject(); } else { clientSes = NEW RTSPRelaySession( SocketUtils::ConvertStringToAddr(pDeviceInfo->m_szIP), pDeviceInfo->m_nPort, pDeviceInfo->m_szSourceUrl, 1, rtcpInterval, 0, theReadInterval, sockRcvBuf, speed, packetPlayHeader, overbufferwindowInK, sendOptions, pDeviceInfo->m_szUser, pDeviceInfo->m_szPassword, theUriStr); OS_Error theErr = clientSes->SendDescribe(); if(theErr == QTSS_NoErr) { OS_Error theErr = sClientSessionMap->Register(clientSes->GetRef()); Assert(theErr == QTSS_NoErr); } else { clientSes->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0); } //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sClientSessionMap->Resolve(&streamName); Assert(debug == clientSes->GetRef()); } ReflectorSession* theSession = SetupProxySession(inParams, clientSes); if (theSession == NULL) { sClientSessionMap->Release(clientSes->GetRef()); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssServerNotImplemented, 0); } QTSS_Error Err = QTSS_SetValue(inParams->inRTSPSession, sRTSPBroadcastSessionAttr, 0, &theSession, sizeof(theSession)); Assert(Err == QTSS_NoErr); clientSes->SetReflectorSession(theSession); theSession->SetRTSPRelaySession((void*)clientSes); sClientSessionMap->Release(clientSes->GetRef()); iovec theDescribeVec[3] = { {0 }}; Assert(theSession->GetLocalSDP()->Ptr != NULL); StrPtrLen theFileData; QTSS_TimeVal outModDate = 0; QTSS_TimeVal inModDate = -1; theFileData.Ptr = theSession->GetLocalSDP()->Ptr; theFileData.Len = theSession->GetLocalSDP()->Len; // -------------- process SDP to remove connection info and add track IDs, port info, and default c= line StrPtrLen theSDPData; SDPSourceInfo tempSDPSourceInfo(theFileData.Ptr, theFileData.Len); // will make a copy and delete in destructor theSDPData.Ptr = tempSDPSourceInfo.GetLocalSDP(&theSDPData.Len); // returns a new buffer with processed sdp OSCharArrayDeleter sdpDeleter(theSDPData.Ptr); // delete the temp sdp source info buffer returned by GetLocalSDP if (theSDPData.Len <= 0) // can't find it on disk or it failed to parse just use the one in the session. { theSDPData.Ptr = theSession->GetLocalSDP()->Ptr; // this sdp isn't ours it must not be deleted theSDPData.Len = theSession->GetLocalSDP()->Len; } // ------------ Clean up missing required SDP lines ResizeableStringFormatter editedSDP(NULL,0); DoDescribeAddRequiredSDPLines2(inParams, theSession, outModDate, &editedSDP, &theSDPData); StrPtrLen editedSDPSPL(editedSDP.GetBufPtr(),editedSDP.GetBytesWritten()); // ------------ Check the headers SDPContainer checkedSDPContainer; checkedSDPContainer.SetSDPBuffer( &editedSDPSPL ); if (!checkedSDPContainer.IsSDPBufferValid()) { return QTSSModuleUtils::SendErrorResponseWithMessage(inParams->inRTSPRequest, qtssUnsupportedMediaType, &sSDPNotValidMessage); } // ------------ Put SDP header lines in correct order Float32 adjustMediaBandwidthPercent = 1.0; Bool16 adjustMediaBandwidth = false; SDPLineSorter sortedSDP(&checkedSDPContainer,adjustMediaBandwidthPercent); // ------------ Write the SDP UInt32 sessLen = sortedSDP.GetSessionHeaders()->Len; UInt32 mediaLen = sortedSDP.GetMediaHeaders()->Len; theDescribeVec[1].iov_base = sortedSDP.GetSessionHeaders()->Ptr; theDescribeVec[1].iov_len = sortedSDP.GetSessionHeaders()->Len; theDescribeVec[2].iov_base = sortedSDP.GetMediaHeaders()->Ptr; theDescribeVec[2].iov_len = sortedSDP.GetMediaHeaders()->Len; (void)QTSS_AppendRTSPHeader(inParams->inRTSPRequest, qtssCacheControlHeader, kCacheControlHeader.Ptr, kCacheControlHeader.Len); QTSSModuleUtils::SendDescribeResponse(inParams->inRTSPRequest, inParams->inClientSession, &theDescribeVec[0], 3, sessLen + mediaLen ); return QTSS_NoErr; }