概要
Darwin Streaming Server简称DSS。DSS是Apple公司提供的开源实时流媒体播放服务器程序(QuickTime Streaming Server开源版本)。整个程序使用C++编写,在设计上遵循高性能,简单,模块化等程序设计原则,务求做到程序高效,可扩充性好。并且DSS是一个开放源代码的,基于标准的流媒体服务器,可以运行在Windows NT和Windows 2000,以及几个UNIX实现上,包括Mac OS X,Linux,FreeBSD,和Solaris操作系统上的。
特性
支持MP4、3GPP等文件格式;
支持MPEG-4、H.264等视频编解码格式;
支持RTSP流控协议,支持HTTP协议;
支持RTP流媒体传输协议;
支持单播和组播;
支持基于Web的管理;
具有完备的日志功能。
此外,该服务器版本提供了一个基于模块的扩展方法。利用DSS提供的API就可以很方便地编写静态或动态的模块,对DSS进行扩展,使其支持其它文件格式、协议或者功能。
框架
核心服务器通过创建四种类型的线程来完成自己的工作,具体如下:
- 服务器自己拥有的主线程(Main Thread)。这个线程负责检查服务器是否需要关闭,记录状态信息,或者打印统计信息。
- 空闲任务线程(Idle Task Thread)。空闲任务线程管理一个周期性的任务队列。该任务队列有两种类型:超时任务和套接口任务。
- 事件线程(Event Thread)。事件线程负责侦听套接口事件,比如收到RTSP请求和RTP数据包,然后把事件传递给任务线程。
- 一个或者多个任务(Task)线程。任务线程从事件线程中接收RTSP和RTP请求,然后把请求传递到恰当的服务器模块进行处理,把数据包发送给客户端。缺省情况下,核心服务器为每一个处理器创建一个任务线程。
模块
媒体服务器使用模块来响应各种请求及完成任务。有三种类型的模块:
- 内容管理模块
内容管理模块负责管理与媒体源相关的RTSP请求和响应,比如一个文件或者一个广播。每个模块负责解释客户的请求,读取和解析它们的支持文件或者网络源,并且以RTSP和RTP的方式进行响应。在某些情况下,比如流化mp3的模块,使用的则是HTTP。
QTSSFileModule,QTSSReflectorModule,QTSSRelayModule,和QTSSMP3StreamingModule都是内容管理模块。
2.服务器支持模块
服务器支持模块执行服务器数据的收集和记录功能。服务器模块包括QTSSErrorLogModule, QTSSAccessLogModule,QTSSWebStatsModule,QTSSWebDebugModule, QTSSAdminModule,和QTSSPOSIXFileSystemModule。
3.访问控制模块
访问控制模块提供鉴权和授权功能,以及操作URL路径提供支持。
访问控制模块包括QTSSAccessModule,QTSSHomeDirectoryModule,QTSSHttpFileModule,和QTSSSpamDefenseModule。
数据
当一个模块需要访问客户请求的RTSP报头时,可以通过QTSS.h这个API头文件中定义的请求对象来访问相应的请求信息。举例来说,RTSPRequestInterface类实现了API字典元素,这些元素可以通过API来进行访问。名称是以“Interface”结尾的对象,比如RTSPRequestInterface,RTSPSessionInterface,和QTSServerInterface,则用于实现模块的API。
下面是重要的接口类:
- QTSServerInterface — 这是内部数据的存储对象,在API中标识为QTSS_ServerObject。在API中的每一个QTSS_ServerAttributes都在基类中声明和实现。
- RTSPSessionInterace — 这是内部数据的存储对象,在API中标识为qtssRTSPSessionObjectType。在API中的每一个QTSS_RTSPSessionAttributes都在基类中声明和实现。
- RTPSessionInterface — 这是内部数据的存储对象,在API中标识为QTSS_ClientSessionObject。在API中的每一个QTSS_ClientSessionAttributes都在基类中声明和实现。
- RTSPRequestInterface — 这是内部数据的存储对象,在API中标识为QTSS_RTSPRequestObject。在API中的每一个QTSS_RTSPRequestAttributes都在基类中声明和实现。
源代码的组织
Server.tproj
这个目录包含核心服务器(core server)的代码,可以分成三个子系统:
- 服务器内核。这个子系统中的类都有一个QTSS前缀。QTSServer负责处理服务器的启动和关闭。QTSServerInterface负责保存服务器全局变量,以及收集服务器的各种统计信息。QTSSPrefs是存储服务器偏好设定的地方。QTSSModule,QTSSModuleInterface,和QTSSCallbacks类的唯一目的就是支持QTSS的模块API。
- RTSP子系统。这些类负责解析和处理RTSP请求,以及实现QTSS模块API的RTSP部分。其中的几个类直接对应QTSS API的一些元素(比如,RTSPRequestInterface类就是对应于QTSS_RTSPRequestObject对象)。每个RTSP TCP连接都有一个RTSP会话对象与之相对应。RTSPSession对象是一个Task对象,负责处理与RTSP相关的事件。
- RTP子系统。这些类处理媒体数据的发送。RTPSession对象包含与所有RTSP会话ID相关联的数据。每个RTPSession都是一个Task对象,可以接受核心服务器的调度来进行RTP数据包的发送。RTPStream对象代表一个单独的RTP流,一个RTPSession对象可以和任何数目的RTPStream对象相关联。这两个对象实现了QTSS模块API中的针对RTP的部分。
CommonUtilitiesLib
这个目录含有一个工具箱,包括线程管理,数据结构,网络,和文本解析工具。Darwin流媒体服务器及其相关工具通过这些类对类似或者相同的任务进行抽象,以减少重复代码;这些类的封装简化了较高层次的代码;借助这些类还分离了专用于不同平台的代码。下面是对目录下的各个类的简短描述:
- OS类。这些类在时间,条件变量,互斥锁,和线程方面提供了专用于不同平台的代码抽象。这些类包括OS,OSCond,OSMutex,OSThread,和OSFileSource;数据结构则包括OSQueue,OSHashTable,OSHeap,和OSRef。
- 套接口类(Sockets)。这些类为TCP和UDP网络通讯方面提供了专用于不同平台的代码抽象。通常情况下,套接口类是异步的(或者说是非阻塞的),可以发送事件给Task对象。这些类有:EventContext,Socket,UDPSocket,UDPDemuxer,UDPSocketPool,TCPSocket,和TCPListenerSocket。
- 解析工具。这些类负责解析和格式化文本。包括StringParser,StringFormatter,StrPtrLen,和StringTranslator。
- Task(任务):这些类实现了服务器的异步事件机制。
QTFileLib
流媒体服务器的一个主要特性就是它能够将索引完成(hinted)的QuickTime电影文件通过RTSP和RTP协议提供给客户。这个目录包含QTFile库的源代码,包括负责解析索引完成的QuickTime文件的代码。服务器的RTPFileModule通过调用QTFile库来从索引过的QuickTime文件中取得数据包和元数据。QTFile库可以解析下面几种文件类型:.mov,.mp4(.mov的一种修改版本),和.3gpp(.mov的一种修改版本)。
APICommonCode
这个目录包含与API相关的类的源代码,比如moduletils,或者诸如记录文件的管理这样的公共模块函数。
APIModules
这个目录包含流媒体服务器模块目录,每个模块都有一个目录。
RTSPClientLib
这个目录包含实现RTSP客户端的源代码,这些代码可以用于连接服务器,只要该连接协议被支持。
RTCPUtilitiesLib
这个目录包含解析RTCP请求的源代码。
APIStubLib
这个目录包含API的定义和支持文件。
HTTPUtilitiesLib
这个目录包含解析HTTP请求的源代码。
二次开发模块添加的要求
每个DSS模块必须实现两个函数:一个是Main函数,服务器在启动时将调用这个函数进行必要的初始化。另一个是Dispatch函数,通过实现此函数,服务器可调用DSS模块并完成特定处理。对于编译到服务器里面的模块,其主函数的地址必须传递到服务器的模块Main函数中。
具体实现时,Main函数必须命名为MyModule_Main,其中MyModule是模块的文件名。此函数的实现通常如下所示:
QTSS_Error MyModule_Main(void* inPrivateArgs)
{
return _stublibrary_main(inPrivateArgs, MyModuleDispatch);
}
每个DSS模块都必须提供一个Dispatch函数。服务器为了特定的目的需要使用某个模块时,是通过调用该模块的Dispatch函数来实现的,调用时必须将任务的名称及相应的参数传递给该函数。在DSS中,使用角色(Role)这个术语来描述特定的任务。Dispatch函数的格式如下所示:
void MyModuleDispatch(QTSS_Role inRole,QTSS_RoleParamPtr inParams);
其中MyModuleDispatch是Dispatch函数的名称;MyModule是模块的文件名;inRole是角色的名称,只有注册了该角色的模块才会被调用;inParams则是一个结构体,可用于传递相应的参数。