字體:小 中 大 | |
|
|
2014/03/20 14:41:10瀏覽3003|回應0|推薦3 | |
之前提到 live555 的多工機制位於 BasicTaskScheduler0::doEventLoop() 函數其中利用 while 迴圈來遍詢所有的 File Descriptor 用 select 作為這些 File Descriptor I/O 逾時的控制。 所以使用 envir().taskScheduler().turnOnBackgroundReadHandling() 將一段工作函數塞入所謂的背景執行的時候,必須傳入是檔案或 socket 的 Descriptor。可這樣 一來造成一個問題,如果有多組客戶端連線上來的話?如果某一個客戶端速度較慢的話?則會拖累其他的客戶端。同時如果資料的來源端讀取速度與伺服器 RTP 的發送速度不匹配的話?也不容易去協調兩著的差異,造成客戶端播放上斷斷續續非常的不流暢。解決的方法就是將 live555 改成 Multi-Thread 的模式,這需要修改 RTSPServer 這個類。不過有人說不用改成 Multi-Thread 也能達成這個目的?但是看到BasicTaskScheduler::SingleStep() 的程式段落寫成那付德性,我就懶的研究下去 ....
首先將 socket 由原先的非組塞模式改成組塞模式。
將 RTSPServer::RTSPServer() 中
env.taskScheduler().turnOnBackgroundReadHandling(fRTSPServerSocket, (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandlerRTSP, this);
改成
incomingConnectionHandler(fRTSPServerSocket);
將 RTSPServer::setUpOurSocket() 中
ourSocket = setupStreamSocket(env, ourPort);
改成
ourSocket = setupStreamSocket(env, ourPort, False);
將 RTSPServer::incomingConnectionHandler() 中
makeSocketNonBlocking(clientSocket);
這行註釋掉
新增一個創建 ServerMediaSession 的方法
ServerMediaSession * createNewSMS(UsageEnvironment& env, char const* fileName, FILE* fid)
{
}
改寫一下 RTSPServer::lookupServerMediaSession() 方法
ServerMediaSession* RTSPServer::lookupServerMediaSession(char const* streamName)
{ ServerMediaSession *sms;
sms = (ServerMediaSession*)(fServerMediaSessions->Lookup(streamName));
if (sms == NULL) {
sms = createServerSession(envir(), streamName);
addServerMediaSession(sms);
}
return sms;
}
將 RTSPClientConnection::RTSPClientConnection() 中
envir().taskScheduler().setBackgroundHandling(fClientInputSocket, SOCKET_READABLE|SOCKET_EXCEPTION, (TaskScheduler::BackgroundHandlerProc*)&incomingRequestHandler, this);
改成
incomingRequestHandler1();
改寫一下 RTSPClientConnection::incomingRequestHandler1 方法
void RTSPClientConnection::incomingRequestHandler1()
{ struct sockaddr_in dummy; // 'from' address, meaningless in this case
int bytesRead;
while (fIsActive) {
if ((bytesRead = readSocket(envir(), fClientInputSocket, &fRequestBuffer[fRequestBytesAlreadySeen], fRequestBufferBytesLeft, dummy)) <= 0="" break="" div="">
handleRequestBytes(bytesRead);
}
}
將 RTSPClientConnection::handleRequestBytes() 中
} else if (strcmp(cmdName, "TEARDOWN") == 0 || strcmp(cmdName, "PLAY") == 0 || strcmp(cmdName, "PAUSE") == 0 ||
strcmp(cmdName, "GET_PARAMETER") == 0 || strcmp(cmdName, "SET_PARAMETER") == 0) {
if (clientSession != NULL) {
clientSession->handleCmd_withinSession(this, cmdName, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer);
if ((strcmp(cmdName, "GET_PARAMETER") == 0)) { <--- if="" div="">
fIsActive = False;
break;
}
} else {
handleCmd_sessionNotFound();
}
}
以下 if 敘述註釋掉
if (!fIsActive) {
if (fRecursionCount > 0) closeSockets();
else delete this;
}
編譯執行後,你會發現 VLC 可以順利播放,但 RTSP 交握卡在 GET_PARAMETER 命令。
接下來,怎麼改成 Multi-Thread? 你知道的,不用我再多說了。
|
|
( 知識學習|科學百科 ) |