基于 QPlay 的智能无线流媒体传输音箱的设计
系统总体架构
QPlay音箱设备主要工作流程如图所示。由于采用libupnp作为UPnP SDK进行开发,所以程序开始时需要初始化UPnP SDK。
程序主要分为设备初始化,事件循环,设备结束三个阶段。其中事件循环是程序的核心。
设备初始化阶段
设备初始化阶段需要完成:
- 初始化UPnP SDK
调用库函数UpnpInit()初始化UPnP协议栈。
◆ UpnpInit()方法:
/**
* 初始化UPnP SDK。确定IP地址和端口号,用于监听UPnP和HTTP请求
* @param HostIP
* 主机IP地址。如果为NULL,将自动获取一个IP地址
* @param DestPort
* 目的端口号。如果为0,将使用一个随机的端口号。
* @return 成功返回0(UPNP_E_SUCCESS),失败返回错误码
*/
int UpnpInit(const char *HostIP, unsigned short DestPort);
如果IP地址为NULL,端口号为0。SDK将会自动去获取一个可用的IP地址和端口号。可以使用库函数UpnpGetServerIpAddress()获得该IP地址(失败返回NULL),使用库函数UpnpGetServerPort()获取目的端口号。
- 设置WEB服务器的根目录
调用库函数UpnpSetWebServerRootDir()把一个本地目录设置为WEB服务器的根目录,为HTTP请求描述文件时提供准确路径。
◆ UpnpSetWebServerRootDir()方法:
/**
* 设置WEB服务器根目录。以构建描述文件正确路径
* @param rootDir
* 根目录路径。如果为NULL,以程序所在的目录为根目录
* @return 成功返回0(UPNP_E_SUCCESS),失败返回错误码
*/
int UpnpSetWebServerRootDir(const char *rootDir);
- 注册根设备
注册根设备需要设置描述文件和异步事件回调函数,该回调函数负责处理控制点发送的订阅请求、控制请求等。
调用库函数UpnpRegisterRootDevice()来完成根设备注册。
◆ UpnpRegisterRootDevice()方法:
/**
* 注册根设备
* @param DescUrl
* 描述文档URL
* @param Callback
* 收到异步事件请求后执行的回调函数
* @param Cookie
* 回调发生时传给回调函数的参数。可以为NULL
* @param Hnd
* 设备的句柄。通过该句柄可以访问设备
* @return 成功返回0(UPNP_E_SUCCESS),失败返回错误码
*/
int UpnpRegisterRootDevice(const char * DescUrl, Upnp_FunPtr Fun, const void * Cookie, UpnpDevice_Handle * Hnd);
- 其它相关初始化
设备相关信息初始化,如打开DSP文件(用于播放音频)、初始化播放列表容器(用于存储歌曲信息)、注册信号处理函数(绑定结束函数,程序退出时进行资源回收)以及相关服务的状态变量初始化等。
- 广播设备存在公告
设备初始化结束后,将广播设备存在信息,等待控制点的请求。
程序调用库函数UpnpSendAdvertisement()广播设备存在公告,之后设备必须进入循环,等待事件的到来(或等待程序结束信息)。
◆ UpnpSendAdvertisement()方法:
/**
* 广播设备存在公告
* @param Hnd
* 设备句柄
* @param Exp
* 公告生存时间。在设备生命周期中,SDK会自动在超时前重新广播设备存在公告
* @return 成功返回0(UPNP_E_SUCCESS),失败返回错误码
*/
int UpnpSendAdvertisement(UpnpDevice_Handle Hnd, int Exp);
事件循环阶段
设备广播存在公告后,将进入事件循环阶段。该阶段主要接收控制点发送过来的各种异步请求:订阅请求、动作请求、获取状态变量请求(QPlay框架并未提供该请求)。
UPnP SDK会将各种请求进行处理,创建线程,调用注册根设备时注册的回调函数(称为event_handler)进行处理。
该回调函数原型是:
◆ event_handler()方法:
/**