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;
}
예제 #2
0
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
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #8
0
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;
}
예제 #10
0
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;
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
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;
}
예제 #14
0
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);
}
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;
}