主要介绍了有关WifiDisplay设备连接和建立数据流的流程,这一回将接着向底层前进。由于涉及的内容较多,这里仅仅理清一个大概的头绪,细节的部分将不再展开,如果有什么错误的地方我会及时更正。
当Source端通过RemoteDisplay.cpp的构造函数注册了Wifidisplay处理线程,并且ANetworkSession初始化 了通信所用的数据管道并且开始监听数据流变化后,Source端将通过函数mSource->start(iface)开始建立RTSP连接并且向 Sink端传递数据流。接下来,将具体分析其流程。mSource->start(iface)的具体实现在以下文件,
frameworks/av/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
- status_t WifiDisplaySource::start(const char *iface) {
- CHECK_EQ(mState, INITIALIZED);
- sp<AMessage> msg = new AMessage(kWhatStart, id());
- msg->setString("iface", iface);
- sp<AMessage> response;
- status_t err = msg->postAndAwaitResponse(&response);
- if (err != OK) {
- return err;
- }
- if (!response->findInt32("err", &err)) {
- err = OK;
- }
- return err;
- }
该函数首先通过CHECK_EQ来判断当前Source端状态是否为 INITIALIZED,如果是将通过 AMessage创建 标识为kWhatStart的消息,用于在onMessageReceived处理分支中进行匹 配,msg->setString(“iface”,iface)用于在传递消息过程中携带网络地址端口信息, msg->postAndAwaitResponse用于返回相应结果。这种方式在Android的流媒体类中相当常见,是一种异步消息处理框架。 与该框架相关的类主要有ALooper、AHandler、ALooperRoster等,具体请见这里。
接下来,我们来看看当Source端接收到kWhatStart的消息后做何种处理,
- void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatStart:
- {
- uint32_t replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- AString iface;
- CHECK(msg->findString("iface", &iface));
- status_t err = OK;
- ssize_t colonPos = iface.find(":"); //寻找“:”所在位置
- unsigned long port;
- if (colonPos >= 0) {
- const char *s = iface.c_str() + colonPos + 1;
- char *end;
- port = strtoul(s, &end, 10); //得到port号
- if (end == s || *end != '\0' || port > 65535) {
- err = -EINVAL;
- } else {
- iface.erase(colonPos, iface.size() - colonPos);
- }
- } else {
- port = kWifiDisplayDefaultPort;
- }
- if (err == OK) {
- if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) { //将IP地址转化为32位的网络序列IP地址
- sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());//建立标识为 kWhatRTSPNotify的消息作为参数传递
- err = mNetSession->createRTSPServer(
- mInterfaceAddr, port, notify, &mSessionID);
- } else {
- err = -EINVAL;
- }
- }
- if (err == OK) {
- mState = AWAITING_CLIENT_CONNECTION;
- }
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
- break;
- }
- ...
- }
- }
首先,可以看到当Source端接收到消息标识为 kWhatStart的消息后,消息指针msg会通过函数msg->senderAwaitsResponse(&replyID)获取对 应于postAndAwaitResponse函数的响应标识,并把处理中的错误信息作为消息载体通过 response->postReply(replyID)传递回start(iface)函数。然后,该处理函数将接收到的网络地址端口信息 iface拆分为IP地址和端口两个部分,并且利用 createRTSPServer创建RTSP服务端,函数会返回相应的Session编号。如果RTSP服务端创建成功,则将Source端状态更改为 AWAITING_CLIENT_CONNECTION,表示等待客户端连接。
接着看创建RTSP服务端具体做了哪些动作,
frameworks/av/media/libstagefright/wifi-display/ANetworkSession.cpp
- status_t ANetworkSession::createRTSPServer(
- const struct in_addr &addr, unsigned port,
- const sp<AMessage> notify, int32_t *sessionID) {
- return createClientOrServer(
- kModeCreateRTSPServer,
- &addr,
- port,
- NULL /* remoteHost */,
- 0 /* remotePort */,
- notify,
- sessionID);
- }
可以看到函数createRTSPServer具体又调用了 cre