用Darwin开发RTSP级联服务器

 

 

#转发模块设计

      拉模式转发中,转发服务器一方面作为RTSP客户端的角色,向源端摄像机获取音视频数据,另一方面作为服务器的角色,将拉取到的音视频数据,重新作为数据源,分发给正在请求的客户端。这样,我们在设计中需要考虑到以下几点:

 

  • 源端数据流到服务器的数据流能够复用,也就是一路进多路出。
  • 服务器端维护所有正在分发的摄像机源列表。
  • 服务器与源端在空闲状态下无连接,只有在有需要的情况下才发起连接过程。
  • 当所有客户端结束对某个源端请求时,服务器停止从源端获取数据,断开连接。

      Darwin系统已经具有了我们所需的一定条件:RTSPClient客户端实现、RTP分发流程(ReflectorSession),我们需要实现:Darwin拉模式转发模块,我们定义此模块名称为QTSSOnDemandRelayModule,意为只有在有需要的时候,才会转发;Darwin与源端用于交互、保存信息、接收数据的ClientSession,为了不影响Darwin原有的架构,我们没有直接在RTSPClient类中修改,而是自定义类:RTSPClientSession,实例化RTSPClient对象为其成员变量:

 

用Darwin开发RTSP级联服务器

 

      在RTSPClientSession中,所有RTSP流程都由fClient(RTSPClient对象)完成,RTSPClientSession负责进行变量存储(如服务器地址fAddr、端口fPort、用户名fName、密码fPassword)、收到数据包统计(fStates、fNumPacketReceived)、RTSPClient控制(SETUP发送fNumSetups、RTSP断开fTeardownImmediately)、以及在非客户端断开情况下,服务器与摄像机间的重连

 

#转发模块实现

 

我们命名拉模式转发模块名称为:QTSSOnDemandRelayModule,需要分别实现对RTSP和RTP的转发和处理,如此,我们会分别处理QTSS_RTSPPreProcessor_Role(RTSP消息处理)、QTSS_RTSPRelayingData_Role(拉取的RTP数据处理)、QTSS_ClientSessionClosing_Role(客户端或RTSPClientSession断开处理)。

 

用Darwin开发RTSP级联服务器

 

*QTSS_RTSPPreProcessor_Role(RTSP消息处理)

 

我们设计的拉模式转发为名称与地址映射的方式,映射列表配置在xml文件中,在QTSSOnDemandRelayModule初始化时,我们就会将配置映射表加载到模块中,当然!我们也可以修改为读取数据库的方式:

 

用Darwin开发RTSP级联服务器

 

例如,RTSP摄像机地址为:rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwcfbqjoo80j.sdp,RTSP转发服务器地址为:8.8.8.8,端口为:554,那么客户端请求:rtsp://8.8.8.8:554/ipC1,转发服务器就会向rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwcfbqjoo80j.sdp 请求摄像机数据,获取后转发给客户端列表。映射查找我们在DoDescribe中进行:

 

 
  1. QTSS_Error DoDescribe(QTSS_StandardRTSP_Params* inParams)

  2. {

  3. char* theUriStr = NULL;

  4. QTSS_Error err = QTSS_GetValueAsString(inParams->inRTSPRequest, qtssRTSPReqFileName, 0, &theUriStr);

  5. Assert(err == QTSS_NoErr);

  6. if(err != QTSS_NoErr)

  7. return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientBadRequest, 0);

  8. QTSSCharArrayDeleter theUriStrDeleter(theUriStr);

  9.  
  10. // 查找配置表,获取摄像机信息结构体

  11. DeviceInfo* pDeviceInfo = parseDevice->GetDeviceInfoByIdName(theUriStr);

  12.  
  13. if(pDeviceInfo == NULL)

  14. {

  15. // 映射表中没有查到相关信息,返回,RTSP请求交给其他模块处理

  16. return QTSS_RequestFailed;

  17. }

  18.  
  19. // 映射信息存在rtsp://218.204.223.237:554/live/1/66251FC11353191F/e7ooqwcfbqjoo80j.sdp

  20. RTSPClientSession* clientSes = NULL;

  21. // 首先查找RTSPClientSession Hash表是否已经建立了对应摄像机的RTSPClientSession

  22. StrPtrLen streamName(theUriStr);

  23. OSRef* clientSesRef = sClientSessionMap->Resolve(&streamName);

  24. if(clientSesRef != NULL)

  25. {

  26. clientSes = (RTSPClientSession*)clientSesRef->GetObject();

  27. }

  28. else

  29. {

  30. // 初次建立服务器与摄像机间的交互RTSPClientSession

  31. clientSes = NEW RTSPClientSession(

  32. SocketUtils::ConvertStringToAddr(pDeviceInfo->m_szIP),

  33. pDeviceInfo->m_nPort,

  34. pDeviceInfo->m_szSourceUrl,

  35. 1,

  36. rtcpInterval,

  37. 0,

  38. theReadInterval,

  39. sockRcvBuf,

  40. speed,

  41. packetPlayHeader,

  42. overbufferwindowInK,

  43. sendOptions,

  44. pDeviceInfo->m_szUser,

  45. pDeviceInfo->m_szPassword,

  46. theUriStr);

  47.  
  48. // 向摄像机源端发送Describe请求

  49. OS_Error theErr = clientSes->SendDescribe();

  50.  
  51. if(theErr == QTSS_NoErr){

  52. // 将成功建立的RTSPClientSession注册到sClientSessionMap表中

  53. OS_Error theErr = sClientSessionMap->Register(clientSes->GetRef());

  54. Assert(theErr == QTSS_NoErr);

  55. }

  56. else{

  57. clientSes->Signal(Task::kKillEvent);

  58. return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssClientNotFound, 0);

  59. }

  60.  
  61. //增加一次对RTSPClientSession的无效引用,后面会统一释放

  62. OSRef* debug = sClientSessionMap->Resolve(&streamName);

  63. Assert(debug == clientSes->GetRef());

  64. }

  65.  
  66. // 建立转发所用的ReflectorSession,后续流程与QTSSReflectorModule类似

  67. ReflectorSession* theSession = SetupProxySession(inParams, clientSes);

  68.  
  69. if (theSession == NULL)

  70. {

  71. sClientSessionMap->Release(clientSes->GetRef());

  72. return QTSSModuleUtils::SendErrorResponse(inParams->inRTSPRequest, qtssServerNotImplemented, 0);

  73. }

  74. }


      这里我们用到了两个Hash Map,一个是存储RTSPClientSession的sClientSessionMap、一个存储ReflectorSession的sSessionMap。

 

 

*QTSS_RTSPRelayingData_Role(拉取的RTP数据处理)

 

当RTSPClientSession获取到一个RTP包时,我们就会调用QTSS_RTSPRelayingData_Role,将RTP包Push给ReflectorSession进行分发,分发过程与QTSSReflectorModule处理方式是一样的,调用方法也同理:

 

用Darwin开发RTSP级联服务器

 

*QTSS_ClientSessionClosing_Role(客户端和RTSPClientSession断开处理)

 

ReflectorSession客户端引用数统计、客户端端断开流程、RTSPClientSession断开流程,基本与RTSPSession(客户端与设备推送)方法一样:

void RemoveOutput(ReflectorOutput* inOutput, ReflectorSession* inSession, Bool16 killClients)
{
    // 从ReflectorSession中移除RTSPSession
    Assert(inSession);
    if (inSession != NULL)
    {
        if (inOutput != NULL)
            inSession->RemoveOutput(inOutput,true);
 
        OSMutexLocker locker (sSessionMap->GetMutex());
        
        OSRef* theSessionRef = inSession->GetRef();
        if (theSessionRef != NULL) 
        {               
            if (theSessionRef->GetRefCount() == 0)
            { 
                // 当引用客户端数量为0的时候,通知RTSPClientSession断开与摄像机的连接
                RTSPClientSession* proxySession = (RTSPClientSession*)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",(UInt32)inSession,theSessionRef->GetRefCount());
                sSessionMap->Release(theSessionRef);
            }
        }
    }
    delete inOutput;
}

 

 

相关文章:

  • 2021-04-21
  • 2021-04-25
  • 2022-01-16
  • 2021-08-28
  • 2021-11-24
  • 2021-11-13
  • 2021-10-02
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-05-30
  • 2021-12-11
  • 2021-05-23
  • 2022-01-26
相关资源
相似解决方案