精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
QTSS模块可以创建线程,使用互斥锁,并且可以完全自由地使用任何操作系统工具。
QuickTime流媒体服务器是完全多线程的,因此QTSS模块必须做好被别的线程抢入的准备。全局的数据结构以及代码中的关键部分应该用互斥锁进行保护。除非有特别的说明,否则我们只能假定线程的抢入是随时可能发生的。
服务器通常在很少的几个线程,或者可能是某个单一的线程上进行所有的活动,这就要求服务器尽可能使用异步I/O(服务器实际的行为取决于具体的平台和管理员配置服务器的方法)。
QTSS模块应该遵循下面的规则:
QuickTime流媒体服务器处理的是媒体的实时分发,因此QTSS模块编程接口的很多元素是时间值。
服务器的内部时钟计数从1970年1月1日0点以来经过的毫秒数。QTSS_TimeVal这个数据类型就是用于存储服务器内部时钟的值。为了使时间值更加容易使用,每个处理时间的属性,参数,和回调函数都显示指定时间单位。举例来说,qtssRTPStrBufferDelayInSecs属性指定的是客户端缓冲区大小对应的秒数。如果没有特别的说明,所有的时间值代表的是服务器内部时钟的毫秒数,都使用QTSS_TimeVal这个数据类型来表示。
如果要获得服务器时钟的当前值,可以调用QTSS_Milliseconds函数,或者获取服务器对象(QTSS_ServerObject)的qtssSvrCurrentTimeMilliseconds属性值。调用QTSS_MilliSecsTo1970Secs函数可以把从服务器时钟上得到的时间转换为当前时间。
QTSS编程接口中提供了一些QTSS流引用,作为一般化的流抽象。流可以用于读取或者写入很多类型的I/O资源,包括(但不限于)文件,错误日志,以及通过RTSP或者RTP进行通讯的套接口。举例来说,模块的所有RTSP角色都会接收到一个带有qtssRTSPReqStreamRef属性的QTSS_RTSPRequestObject对象类型。该属性值的类型为QTSS_StreamRef,可以用于将RTSP相应数据发送给客户。
如果没有特殊的说明,所有的流都是异步的。在使用异步的QTSS文件系统回调函数时,模块应该做好接收QTSS_WouldBlock结果码的准备,遵守本部分描述的各种类型的流的限制和规则。在需要阻塞当前线程才能完成被请求的操作时,流的回调函数就会返回QTSS_WouldBlock错误。举例来说,如果某个套接口当前受到流量控制的约束,则对该套接口进行操作的QTSS_Write函数就会返回QTSS_WouldBlock。
当模块接收到QTSS_WouldBlock返回码时,应该调用QTSS_RequestEvent回调函数,请求服务器在指定的流可以进行I/O的时候发出通知。调用QTSS_RequestEvent函数之后,模块应该马上将控制权返回给服务器。这样当指定的流可以进行I/O时,服务器将会以完全相同的状态再次调用模块的同一角色。
所有流引用的类型都是QTSS_StreamRef。QTSS编程接口使用下面这些流类型:
QTSS_ErrorLogStream
用于将二进制数据写入到服务器的错误日志中。服务器进程中只有一个这种流类型的实例,被作为参数传递给模块的初始化角色。在数据写入到这个流的时候,注册了Error Log角色的模块将会被调用。所有对于这种流类型的操作都是同步的。
QTSS_FileStream
代表一个文件,可以通过调用QTSS_OpenFileStream函数得到。如果打开文件流的时候使用了qtssFileStreamAsync标志,则调用者在调用QTSS_Read,QTSS_Write,和QTSS_WriteV函数时应该考虑处理QTSS_WouldBlock返回码。
QTSS_RTSPSessionStream
用来从RTSP客户端读取数据(QTSS_Read),或者将数据写入到RTSP客户端(QTSS_Write或者QTSS_WriteV)。服务器可能会处于流量控制状态,因此模块在读写这种流类型的时候应该做好处理QTSS_WouldBlock返回码的准备。调用QTSS_Read函数表示您要读取客户端发送给服务器端的请求体。这个流引用是QTSS_RTSPSessionObject对象的一个属性。
QTSS_RTSPRequestStream
用来从RTSP客户端读取数据(QTSS_Read),或者将数据写入到RTSP客户端(QTSS_Write或者QTSS_WriteV)。写入到这种流类型的数据会在内存中缓存,直到整个RTSP响应全部构造完成。除此之外,这种流和QTSS_RTSPSessionStream流是完全一样的。由于数据在内部进行缓存,在向这种流类型写入数据时,模块不会收到QTSS_WouldBlock错误。调用QTSS_Read函数对这种流进行操作表示您要读取客户端发送给服务器端的请求体。
模块在调用QTSS_Read函数读取这种类型的流时,应该做好处理QTSS_WouldBlock返回码的准备。这个流引用是QTSS_RTSPRequestObject对象的一个属性。
QTSS_RTPStreamStream
用于将数据写入到RTP客户端。在向这种类型的流写数据时,一个写调用对应一个完整的RTP数据包,包括报头。目前不可能用QTSS_RequestEvent回调函数来接收这种流的事件,因此如果QTSS_Write或者QTSS_WriteV函数返回QTSS_WouldBlock,则模块必须周期性地检测阻塞状态是否被消除。这种流引用是QTSS_RTPStreamObject对象的一个属性。
QTSS_SocketStream
表示一个套接口。这种流类型允许模块使用QTSS流事件机制(QTSS_RequestEvent)来进行raw套接口I/O(事实上,QTSS_RequestEvent回调是唯一一个可用于这种流类型的流回调函数)。模块应该异步地读取套接口,而且应该使用操作系统的套接口函数来读写套接口。当那些例程处于阻塞状态时,模块可以通过QTSS_RequestEvent函数来获得阻塞状态被清除的通知。
表1-24用“X”来概括与I/O相关的回调函数是否适用于各种类型的流。
流类型 | Read | Seek | Flush | Advise | Write | WriteV | RequestEvent | SignalStream |
---|---|---|---|---|---|---|---|---|
File Stream(文件流) | X | X | X | X | X | |||
Error Log(错误日志流) | X | |||||||
Socket Stream(套接口流) | X | |||||||
RTSP Session Stream会话流 | X | X | X | X | X | |||
RTSP Request Stream请求流 | X | X | X | X | X | |||
RTP Stream RTP流 | X | X | X | X |
QTSS服务是一些可以由模块访问的服务,可以是服务器提供的内建服务,或者其它模块提供的、并在后来添加的服务。服务的一个实例就是一个日志模块,允许其它模块将信息写入到错误日志中。
模块使用“服务回调例程”部分描述的回调例程来注册和调用服务。模块添加和寻找服务的方式和添加及寻找对象属性的方式类似。
每个服务都有一个名字。调用模块必须知道服务的名称,并将它转化为一个ID,才能调用服务。
每个服务都有自己特定的参数块格式。输出服务的模块应该将其输出的服务进行认真的文档说明。调用服务的模块则应该在服务不可用或者返回错误时优雅地进行错误处理。
实现某种服务的模块需要在Register角色中调用QTSS_AddService函数来将服务添加到服务器内部的服务数据库中,代码如下所示:
void MyAddService() |
这里的MyServiceFunction 对应于一个函数名称,必须在同一模块中加以实现。下面是MyServiceFunction函数的一个stub实现:
QTSS_Error MyServiceFunction(MyServiceArgs* inArgs) |
模块必须调用QTSS_IDForService函数,并在调用时提供服务名称作为参数,来获得服务的ID,才能使用服务。有了服务的ID,模块就可以调用QTSS_DoService函数来运行服务,如列表1-1所示。
Listing 1-1 Starting a service void MyInvokeService() |
QuickTime流媒体服务器提供一些内置的服务,模块可以通过服务例程来调用这些服务。在这个版本的QTSS编程接口中,有一个内置的服务:
#define QTSS_REREAD_PREFS_SERVICE "RereadPreferences" |
调用Reread Preferences服务可以使服务器重新读取其预置信息,并调用每个模块的Reread Preferences角色--如果该模块注册了这个角色的话。
调用内置服务时,首先调用QTSS_IDForService函数来获得服务的ID,然后调用QTSS_DoService 函数运行该服务。
QTSS编程接口使用一个命名规则来命名它所定义的数据类型。这个规则使用数据类型的尺寸作为名字的一部分。下面是QTSS编程接口使用的数据类型:
QTSS编程接口定义的回调函数的参数遵循下面这些命名规则: