QTSS_Error EasyHLSClose(Easy_HLSClose_Params* inParams) { OSRefTable* sHLSSessionMap = QTSServerInterface::GetServer()->GetHLSSessionMap(); OSMutexLocker locker (sHLSSessionMap->GetMutex()); //首先查找Map里面是否已经有了对应的流 StrPtrLen streamName(inParams->inStreamName); OSRef* clientSesRef = sHLSSessionMap->Resolve(&streamName); if(NULL == clientSesRef) return QTSS_RequestFailed; EasyHLSSession* session = (EasyHLSSession*)clientSesRef->GetObject(); session->HLSSessionRelease(); sHLSSessionMap->Release(session->GetRef()); if (session->GetRef()->GetRefCount() == 0) { qtss_printf("EasyHLSModule.cpp:EasyHLSClose UnRegister and delete session =%p refcount=%"_U32BITARG_"\n", session->GetRef(), session->GetRef()->GetRefCount() ) ; sHLSSessionMap->UnRegister(session->GetRef()); delete session; } return QTSS_NoErr; }
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; }
SInt64 ReflectorSessionCheckTask::Run() { OSRefTable* reflectorSessionMap = QTSServerInterface::GetServer()->GetReflectorSessionMap(); OSMutexLocker locker(reflectorSessionMap->GetMutex()); SInt64 sNowTime = OS::Milliseconds(); for (OSRefHashTableIter theIter(reflectorSessionMap->GetHashTable()); !theIter.IsDone(); theIter.Next()) { OSRef* theRef = theIter.GetCurrent(); ReflectorSession* theSession = (ReflectorSession*)theRef->GetObject(); SInt64 sCreateTime = theSession->GetInitTimeMS(); if( (theSession->GetNumOutputs() == 0) && (sNowTime-sCreateTime >= 20*1000) ) { QTSS_RoleParams theParams; theParams.easyFreeStreamParams.inStreamName = theSession->GetStreamName(); UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kEasyCMSFreeStreamRole); for ( UInt32 currentModule=0;currentModule < numModules; currentModule++) { qtss_printf("没有客户端观看当前转发媒体\n"); QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kEasyCMSFreeStreamRole, currentModule); (void)theModule->CallDispatch(Easy_CMSFreeStream_Role, &theParams); } } } return 30*1000;//30s }
QTSS_Error EasyHLSOpen(Easy_RecordOpen_Params* inParams) { OSRefTable* sHLSSessionMap = QTSServerInterface::GetServer()->GetRecordSessionMap(); OSMutexLocker locker (sHLSSessionMap->GetMutex()); EasyRecordSession* session = NULL; //首先查找MAP里面是否已经有了对应的流 StrPtrLen streamName(inParams->inStreamName); OSRef* clientSesRef = sHLSSessionMap->Resolve(&streamName); if(clientSesRef != NULL) { session = (EasyRecordSession*)clientSesRef->GetObject(); } else { session = NEW EasyRecordSession(&streamName); OS_Error theErr = sHLSSessionMap->Register(session->GetRef()); Assert(theErr == QTSS_NoErr); //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sHLSSessionMap->Resolve(&streamName); Assert(debug == session->GetRef()); } //到这里,肯定是有一个EasyRecordSession可用的 session->HLSSessionStart(inParams->inRTSPUrl, inParams->inTimeout); sHLSSessionMap->Release(session->GetRef()); return QTSS_NoErr; }
void QTSServerInterface::KillAllRTPSessions() { OSMutexLocker locker(fRTPMap->GetMutex()); for (OSRefHashTableIter theIter(fRTPMap->GetHashTable()); !theIter.IsDone(); theIter.Next()) { OSRef* theRef = theIter.GetCurrent(); RTPSessionInterface* theSession = (RTPSessionInterface*)theRef->GetObject(); theSession->Signal(Task::kKillEvent); } }
ReflectorSession* FindOrCreateProxySession(StrPtrLen* inPath, QTSS_StandardRTSP_Params* inParams, StrPtrLen* inData, Bool16 *foundSessionPtr) { OSMutexLocker locker(sSessionMap->GetMutex()); OSRef* theSessionRef = sSessionMap->Resolve(inPath); ReflectorSession* theSession = NULL; if( inData == NULL ) return NULL; if (theSessionRef == NULL) { StrPtrLen theFileData; StrPtrLen theFileDeleteData; theFileData = *inData; OSCharArrayDeleter fileDataDeleter(theFileDeleteData.Ptr); if (theFileData.Len <= 0) return NULL; SDPSourceInfo* theInfo = NEW SDPSourceInfo(theFileData.Ptr, theFileData.Len); // will make a copy //if (!theInfo->IsReflectable()) //{ delete theInfo; // return NULL; //} UInt32 theSetupFlag = ReflectorSession::kMarkSetup; theSession = NEW ReflectorSession(inPath); if (theSession == NULL) return NULL; theSession->SetHasBufferedStreams(true); QTSS_Error theErr = theSession->SetupReflectorSession(theInfo, inParams, theSetupFlag); if (theErr != QTSS_NoErr) { delete theSession; return NULL; } theErr = sSessionMap->Register(theSession->GetRef()); Assert(theErr == QTSS_NoErr); } else { theSession = (ReflectorSession*)theSessionRef->GetObject(); } Assert(theSession != NULL); return theSession; }
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); //从接口获取信息结构体 //信息存在rtsp://59.46.115.84:8554/h264/ch1/sub/av_stream RTSPRelaySession* clientSes = NULL; //首先查找Map里面是否已经有了对应的流 StrPtrLen streamName(theUriStr); OSRef* clientSesRef = sRelaySessionMap->Resolve(&streamName); if(clientSesRef != NULL) { clientSes = (RTSPRelaySession*)clientSesRef->GetObject(); } else { clientSes = NEW RTSPRelaySession("rtsp://*****:*****@192.168.66.189/", RTSPRelaySession::kRTSPTCPClientType, theUriStr); QTSS_Error theErr = clientSes->SendDescribe(); if(theErr == QTSS_NoErr) { OS_Error theErr = sRelaySessionMap->Register(clientSes->GetRef()); Assert(theErr == QTSS_NoErr); } else { clientSes->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0); } //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sRelaySessionMap->Resolve(&streamName); Assert(debug == clientSes->GetRef()); } return QTSS_NoErr; }
void* QTSSCallbacks::Easy_GetRTSPPushSessions() { OSRefTable* reflectorSessionMap = QTSServerInterface::GetServer()->GetReflectorSessionMap(); EasyMsgSCRTSPPushSessionListACK ack; ack.SetHeaderValue(EASY_TAG_VERSION, "1.0"); ack.SetHeaderValue(EASY_TAG_CSEQ, "1"); UInt32 uIndex= 0; OSMutexLocker locker(reflectorSessionMap->GetMutex()); for (OSRefHashTableIter theIter(reflectorSessionMap->GetHashTable()); !theIter.IsDone(); theIter.Next()) { OSRef* theRef = theIter.GetCurrent(); ReflectorSession* theSession = (ReflectorSession*)theRef->GetObject(); EasyDarwinRTSPSession session; session.index = uIndex; char* fullRequestURL = NULL; RTPSession* clientSession = (RTPSession*) theSession->GetBroadcasterSession(); if(clientSession == NULL) continue; clientSession->GetValueAsString(qtssCliSesFullURL,0,&fullRequestURL); session.Url = fullRequestURL; session.Name = theSession->GetSessionName(); session.numOutputs = theSession->GetNumOutputs(); ack.AddSession(session); uIndex++; } char count[16] = { 0 }; sprintf(count,"%d", uIndex); ack.SetBodyValue(EASY_TAG_SESSION_COUNT, count); string msg = ack.GetMsg(); UInt32 theMsgLen = strlen(msg.c_str()); char* retMsg = new char[theMsgLen+1]; retMsg[theMsgLen] = '\0'; strncpy(retMsg, msg.c_str(), strlen(msg.c_str())); return (void*)retMsg; }
RTPSessionInterface* RTPStatsUpdaterTask::GetNewestSession(OSRefTable* inRTPSessionMap) { //Caller must lock down the RTP session map SInt64 theNewestPlayTime = 0; RTPSessionInterface* theNewestSession = NULL; //use the session map to iterate through all the sessions, finding the most //recently connected client for (OSRefHashTableIter theIter(inRTPSessionMap->GetHashTable()); !theIter.IsDone(); theIter.Next()) { OSRef* theRef = theIter.GetCurrent(); RTPSessionInterface* theSession = (RTPSessionInterface*)theRef->GetObject(); Assert(theSession->GetSessionCreateTime() > 0); if (theSession->GetSessionCreateTime() > theNewestPlayTime) { theNewestPlayTime = theSession->GetSessionCreateTime(); theNewestSession = theSession; } } return theNewestSession; }
char* GetHLSUrl(char* inSessionName) { OSRefTable* sHLSSessionMap = QTSServerInterface::GetServer()->GetHLSSessionMap(); OSMutexLocker locker (sHLSSessionMap->GetMutex()); char* hlsURL = NULL; //首先查找Map里面是否已经有了对应的流 StrPtrLen streamName(inSessionName); OSRef* clientSesRef = sHLSSessionMap->Resolve(&streamName); if(NULL == clientSesRef) return NULL; EasyHLSSession* session = (EasyHLSSession*)clientSesRef->GetObject(); hlsURL = session->GetHLSURL(); sHLSSessionMap->Release(session->GetRef()); return hlsURL; }
void* QTSSCallbacks::Easy_GetHLSessions() { OSRefTable* hlsMap = QTSServerInterface::GetServer()->GetHLSSessionMap(); EasyMsgSCHLSessionListACK ack; ack.SetHeaderValue(EASY_TAG_VERSION, "1.0"); ack.SetHeaderValue(EASY_TAG_CSEQ, "1"); char count[16] = { 0 }; sprintf(count,"%d", hlsMap->GetNumRefsInTable()); ack.SetBodyValue(EASY_TAG_SESSION_COUNT, count ); OSRef* theSesRef = NULL; UInt32 uIndex= 0; OSMutexLocker locker(hlsMap->GetMutex()); for (OSRefHashTableIter theIter(hlsMap->GetHashTable()); !theIter.IsDone(); theIter.Next()) { OSRef* theRef = theIter.GetCurrent(); EasyHLSSession* theSession = (EasyHLSSession*)theRef->GetObject(); EasyDarwinHLSession session; session.index = uIndex; session.SessionName = string(theSession->GetSessionID()->Ptr); session.HlsUrl = string(theSession->GetHLSURL()); session.sourceUrl = string(theSession->GetSourceURL()); session.bitrate = theSession->GetLastStatBitrate(); ack.AddSession(session); uIndex++; } string msg = ack.GetMsg(); UInt32 theMsgLen = strlen(msg.c_str()); char* retMsg = new char[theMsgLen+1]; retMsg[theMsgLen] = '\0'; strncpy(retMsg, msg.c_str(), strlen(msg.c_str())); return (void*)retMsg; }
RTPFileSession::ErrorCode RTPFileSession::Initialize(StrPtrLen& inFilePath, Float32 inBufferSeconds) { Assert(fFile == NULL); // Check to see if this file is already open OSMutexLocker locker(sOpenFileMap.GetMutex()); OSRef* theFileRef = sOpenFileMap.Resolve((StrPtrLen*)&inFilePath); if (theFileRef == NULL) { //qtss_printf("Didn't find file in map. Creating new one\n"); fFile = NEW RTPFile(); ErrorCode theErr = fFile->Initialize(inFilePath); if (theErr != errNoError) { delete fFile; fFile = NULL; return theErr; } OS_Error osErr = sOpenFileMap.Register(fFile->GetRef()); Assert(osErr == OS_NoErr); //unless we do this, the refcount won't increment (and we'll delete the session prematurely OSRef* debug = sOpenFileMap.Resolve((StrPtrLen*)&inFilePath); Assert(debug == fFile->GetRef()); } else { //qtss_printf("Found file. Refcounting.\n"); fFile = (RTPFile*)theFileRef->GetObject(); } //Open the file no matter what //fFileSource.Set(inFilePath.Ptr); //Assert(fFileSource.GetLength() > 0); QTSS_Error theErr = QTSS_OpenFileObject(inFilePath.Ptr, 0, &fFileSource); Assert(theErr == QTSS_NoErr); // // Get the file length UInt32 theLen = sizeof(fFileLength); theErr = QTSS_GetValue(fFileSource, qtssFlObjLength, 0, &fFileLength, &theLen); Assert(theErr == QTSS_NoErr); Assert(theLen == sizeof(fFileLength)); // Allocate our data buffer fDataBufferSize = this->PowerOf2Floor((UInt32)(inBufferSeconds * fFile->GetBytesPerSecond())); // Check to see if the size is out of range. If so, adjust it if (fDataBufferSize > kMaxDataBufferSize) fDataBufferSize = kMaxDataBufferSize; if (fDataBufferSize < kBlockSize) fDataBufferSize = kBlockSize; fReadBuffer = fDataBuffer = NEW UInt8[fDataBufferSize]; // Allocate a buffer of TrackInfos fTrackInfo = NEW RTPFileSessionTrackInfo[fFile->GetMaxTrackNumber() + 1]; ::memset(fTrackInfo, 0, fFile->GetMaxTrackNumber() * sizeof(RTPFileSessionTrackInfo)); return errNoError; }
QTSS_Error RedisInit()//only called by RedisConnect after connect redis sucess { //每一次与redis连接后,都应该清除上一次的数据存储,使用覆盖或者直接清除的方式,串行命令使用管线更加高效 char chTemp[128] = { 0 }; do { //1,redis密码认证 sprintf(chTemp, "auth %s", sRedisPassword); sRedisClient->AppendCommand(chTemp); //2,EasyDarwin唯一信息存储(覆盖上一次的存储) sprintf(chTemp, "sadd EasyDarwinName %s:%d", sRTSPWanIP, sRTSPWanPort); sRedisClient->AppendCommand(chTemp); //3,EasyDarwin属性存储,设置多个filed使用hmset,单个使用hset(覆盖上一次的存储) sprintf(chTemp, "hmset %s:%d_Info IP %s PORT %d RTP %d", sRTSPWanIP, sRTSPWanPort, sRTSPWanIP, sRTSPWanPort, QTSServerInterface::GetServer()->GetNumRTPSessions()); sRedisClient->AppendCommand(chTemp); //4,清除推流名称存储 sprintf(chTemp, "del %s:%d_PushName", sRTSPWanIP, sRTSPWanPort); sRedisClient->AppendCommand(chTemp); char* strAllPushName; OSRefTable * reflectorTable = QTSServerInterface::GetServer()->GetReflectorSessionMap(); OSMutex *mutexMap = reflectorTable->GetMutex(); int iPos = 0, iLen = 0; mutexMap->Lock(); strAllPushName = new char[reflectorTable->GetNumRefsInTable() * 128 + 1];//为每一个推流名称分配128字节的内存 memset(strAllPushName, 0, reflectorTable->GetNumRefsInTable() * 128 + 1);//内存初始化为0 for (OSRefHashTableIter theIter(reflectorTable->GetHashTable()); !theIter.IsDone(); theIter.Next()) { OSRef* theRef = theIter.GetCurrent(); ReflectorSession * theSession = (ReflectorSession *)theRef->GetObject(); char * chPushName = theSession->GetSessionName(); if (chPushName) { strAllPushName[iPos++] = ' '; memcpy(strAllPushName + iPos, chPushName, strlen(chPushName)); iPos = iPos + strlen(chPushName); } } mutexMap->Unlock(); char *chNewTemp = new char[strlen(strAllPushName) + 128];//注意,这里不能再使用chTemp,因为长度不确定,可能导致缓冲区溢出 //5,推流名称存储 sprintf(chNewTemp, "sadd %s:%d_PushName%s", sRTSPWanIP, sRTSPWanPort, strAllPushName); sRedisClient->AppendCommand(chTemp); delete[] chNewTemp; delete[] strAllPushName; //6,保活,设置15秒,这之后当前EasyDarwin已经开始提供服务了 sprintf(chTemp, "setex %s:%d_Live 15 1", sRTSPWanIP, sRTSPWanPort); sRedisClient->AppendCommand(chTemp); bool bBreak = false; easyRedisReply* reply = NULL; for (int i = 0; i < 6; i++) { if (EASY_REDIS_OK != sRedisClient->GetReply((void**)&reply)) { bBreak = true; if (reply) EasyFreeReplyObject(reply); break; } EasyFreeReplyObject(reply); } if (bBreak)//说明redisGetReply出现了错误 break; return QTSS_NoErr; } while (0); //走到这说明出现了错误,需要进行重连,重连操作再下一次执行命令时进行,在这仅仅是置标志位 sRedisClient->Free(); sIfConSucess = false; return (QTSS_Error)false; }
void RemoveOutput(ReflectorOutput* inOutput, ReflectorSession* inSession, Bool16 killClients) { //This function removes the output from the ReflectorSession, then Assert(inSession); if (inSession != NULL) { if (inOutput != NULL) { inSession->RemoveOutput(inOutput,true); //qtss_printf("QTSSReflectorModule.cpp:RemoveOutput it is a client session\n"); } else { // it is a Broadcaster session //qtss_printf("QTSSReflectorModule.cpp:RemoveOutput it is a broadcaster session\n"); //SourceInfo* theInfo = inSession->GetSourceInfo(); //Assert(theInfo); // //if (theInfo->IsRTSPControlled()) //{ // FileDeleter(inSession->GetSourcePath()); //} // //if (killClients || 1) //{ inSession->TearDownAllOutputs(); //} } //qtss_printf("QTSSReflectorModule.cpp:RemoveOutput refcount =%lu\n", inSession->GetRef()->GetRefCount()); //check if the ReflectorSession should be deleted //(it should if its ref count has dropped to 0) OSMutexLocker locker (sSessionMap->GetMutex()); OSRef* theSessionRef = inSession->GetRef(); if (theSessionRef != NULL) { if (theSessionRef->GetRefCount() == 0) { RTSPRelaySession* proxySession = (RTSPRelaySession*)inSession->GetRTSPRelaySession(); if(proxySession != NULL) { proxySession->SetReflectorSession(NULL); sClientSessionMap->UnRegister(proxySession->GetRef()); proxySession->Signal(Task::kKillEvent); } inSession->SetRTSPRelaySession(NULL); sSessionMap->UnRegister(theSessionRef); delete inSession; } //else if (theSessionRef->GetRefCount() == 1) //{ // //qtss_printf("QTSSReflector.cpp:RemoveOutput Delete SESSION=%lu\n",(UInt32)inSession); // RTSPRelaySession* proxySession = (RTSPRelaySession*)inSession->GetRelaySession(); // if(proxySession != NULL) // { // proxySession->SetReflectorSession(NULL); // sClientSessionMap->UnRegister(proxySession->GetRef()); // proxySession->Signal(Task::kKillEvent); // } // inSession->SetRelaySession(NULL); // sSessionMap->UnRegister(theSessionRef); // delete inSession; //} else { qtss_printf("QTSSReflector.cpp:RemoveOutput Release SESSION=%lu RefCount=%d\n",(UInt64)inSession,theSessionRef->GetRefCount()); sSessionMap->Release(theSessionRef); // one of the sessions on the ref is ending just decrement the count } } } delete inOutput; }
void EventThread::Entry() { struct eventreq theCurrentEvent; ::memset( &theCurrentEvent, '\0', sizeof(theCurrentEvent) ); while (!IsStopRequested()) { int theErrno = EINTR; while (theErrno == EINTR) { #if MACOSXEVENTQUEUE int theReturnValue = waitevent(&theCurrentEvent, NULL); #else int theReturnValue = select_waitevent(&theCurrentEvent, NULL); #endif //Sort of a hack. In the POSIX version of the server, waitevent can return //an actual POSIX errorcode. if (theReturnValue >= 0) theErrno = theReturnValue; else theErrno = OSThread::GetErrno(); if(IsStopRequested()) break; } if (IsStopRequested()) break; AssertV(theErrno == 0, theErrno); //ok, there's data waiting on this socket. Send a wakeup. if (theCurrentEvent.er_data != NULL) { //The cookie in this event is an ObjectID. Resolve that objectID into //a pointer. StrPtrLen idStr((char*)&theCurrentEvent.er_data, sizeof(theCurrentEvent.er_data)); OSRef* ref = fRefTable.Resolve(&idStr); if (ref != NULL) { EventContext* theContext = (EventContext*)ref->GetObject(); #if DEBUG theContext->fModwatched = false; #endif theContext->ProcessEvent(theCurrentEvent.er_eventbits); fRefTable.Release(ref); } } #if EVENT_CONTEXT_DEBUG SInt64 yieldStart = OS::Milliseconds(); #endif this->ThreadYield(); #if EVENT_CONTEXT_DEBUG SInt64 yieldDur = OS::Milliseconds() - yieldStart; static SInt64 numZeroYields; if ( yieldDur > 1 ) { qtss_printf( "EventThread time in OSTHread::Yield %i, numZeroYields %i\n", (SInt32)yieldDur, (SInt32)numZeroYields ); numZeroYields = 0; } else numZeroYields++; #endif } }
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; }
QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams) { //解析命令 char* theFullPathStr = NULL; QTSS_Error theErr = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileName, 0, &theFullPathStr); Assert(theErr == QTSS_NoErr); QTSSCharArrayDeleter theFullPathStrDeleter(theFullPathStr); if (theErr != QTSS_NoErr) return NULL; StrPtrLen theFullPath(theFullPathStr); if (theFullPath.Len != sRelaySuffix.Len ) return NULL; StrPtrLen endOfPath2(&theFullPath.Ptr[theFullPath.Len - sRelaySuffix.Len], sRelaySuffix.Len); if (!endOfPath2.Equal(sRelaySuffix)) { return NULL; } //解析查询字符串 char* theQueryStr = NULL; theErr = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqQueryString, 0, &theQueryStr); Assert(theErr == QTSS_NoErr); QTSSCharArrayDeleter theQueryStringDeleter(theQueryStr); if (theErr != QTSS_NoErr) return NULL; StrPtrLen theQueryString(theQueryStr); QueryParamList parList(theQueryStr); const char* sName = parList.DoFindCGIValueForParam(QUERY_STREAM_NAME); const char* sChannel = parList.DoFindCGIValueForParam(QUERY_STREAM_CHANNEL); if(sName == NULL && sChannel == NULL) { return NULL; } char szChannelURL[256] = {0,}; char szUsername[32] = {0,}; char szPassword[32] = {0,}; const char* sURL = NULL; char sPushServerAddr[256] = {0,}; if (NULL != sChannel) { //find channel info GetChannelInfoById( (char*)sChannel, szChannelURL, sizeof(szChannelURL), szUsername, sizeof(szUsername), szPassword, sizeof(szPassword), sPushServerAddr, sizeof(sPushServerAddr)); if ( (int)strlen(szChannelURL) < 1 ) return NULL; //not found the channel //sURL = "rtsp://192.168.1.186:8557"; sURL = szChannelURL; } else { sURL = parList.DoFindCGIValueForParam(QUERY_STREAM_URL); } //if(sURL == NULL) return NULL; const char* sCMD = parList.DoFindCGIValueForParam(QUERY_STREAM_CMD); bool bStop = false; if(sCMD) { if(::strcmp(sCMD,QUERY_STREAM_CMD_STOP) == 0) bStop = true; } StrPtrLen streamName(NULL!=sName?(char*)sName:(char*)sChannel); //从接口获取信息结构体 EasyRelaySession* session = NULL; //首先查找Map里面是否已经有了对应的流 OSRef* sessionRef = sRelaySessionMap->Resolve(&streamName); if(sessionRef != NULL) { session = (EasyRelaySession*)sessionRef->GetObject(); } else { if(bStop) return NULL; if(sURL == NULL) return NULL; session = NEW EasyRelaySession((char*)sURL, EasyRelaySession::kRTSPTCPClientType, NULL!=sName?(char*)sName:(char*)sChannel, sPushServerAddr); QTSS_Error theErr = session->RelaySessionStart(); if(theErr == QTSS_NoErr) { OS_Error theErr = sRelaySessionMap->Register(session->GetRef()); Assert(theErr == QTSS_NoErr); } else { session->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0); } //增加一次对RelaySession的无效引用,后面会统一释放 OSRef* debug = sRelaySessionMap->Resolve(&streamName); Assert(debug == session->GetRef()); } sRelaySessionMap->Release(session->GetRef()); if(bStop) { sRelaySessionMap->UnRegister(session->GetRef()); session->Signal(Task::kKillEvent); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssSuccessOK, 0); } QTSS_RTSPStatusCode statusCode = qtssRedirectPermMoved; QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqStatusCode, 0, &statusCode, sizeof(statusCode)); // Get the ip addr out of the prefs dictionary UInt16 thePort = 554; UInt32 theLen = sizeof(UInt16); theErr = QTSServerInterface::GetServer()->GetPrefs()->GetValue(qtssPrefsRTSPPorts, 0, &thePort, &theLen); Assert(theErr == QTSS_NoErr); //构造本地URL char url[QTSS_MAX_URL_LENGTH] = { 0 }; qtss_sprintf(url,"rtsp://%s:%d/%s.sdp", sLocal_IP_Addr, thePort, NULL!=sName?(char*)sName:(char*)sChannel); StrPtrLen locationRedirect(url); Bool16 sFalse = false; (void)QTSS_SetValue(inParams->inRTSPRequest, qtssRTSPReqRespKeepAlive, 0, &sFalse, sizeof(sFalse)); QTSS_AppendRTSPHeader(inParams->inRTSPRequest, qtssLocationHeader, locationRedirect.Ptr, locationRedirect.Len); return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssRedirectPermMoved, 0); }