網路城邦
上一篇 回創作列表 下一篇   字體:
粗解 live555 (續)
2014/03/20 14:41:10瀏覽2953|回應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? 你知道的,不用我再多說了。


( 知識學習科學百科 )
回應 推薦文章 列印 加入我的文摘
上一篇 回創作列表 下一篇

引用
引用網址:https://classic-blog.udn.com/article/trackback.jsp?uid=mhwu1&aid=11853764