WFD连接过程代码分析(Sink端)
WFD建立连接首先必需建立P2P连接,随后WFD使用P2P连接的IP和端口号建立RTSP连接。本文着重分析P2P连接建立后的RTSP连接建立过程,且为一个Source端对Primary Sink端连接,涉及两个Sink端耦合的过程请参阅其他博客,P2P的连接过程不在本文分析范围,请读者自行查阅相关博客。
目录
1.建立Session连接
在main函数会创建创建三个重要的类,一个是消息循环ALooper类,实现各个类之间的异步消息处理,因为代码中WifiDisplaySink,RTPSink,TunnelRenderer等类都继承于AHandler,并且都实现了onMessageReceived函数,所以相应的消息得以在对应的AHandler派生类处理,例如当收到Source端的RTSP Request后,会在WifiDisplaySink的onMessageReceived中做相应的处理;一个是网络通信部分的ANetworkSession类,用于处理Source端发送的网络数据;最后一个是WifiDisplaySink,RTSP协议的实现类。 wfd::main方法主要完成以下任务
- 创建ALooper异步消息处理机制
- 创建ANetworkSession网络通信线程
- 创建WifiDisplaySink用于实现RTSP交互
//frameworks/avmedialibstagefright/wifi-display/wfd.cpp
int main(int argc, char **argv) {
using namespace android;
ProcessState::self()->startThreadPool();
DataSource::RegisterDefaultSniffers();
... ...
sp<ANetworkSession> session = new ANetworkSession; //网络通信
session->start();//开启网络消息监听循环
sp<ALooper> looper = new ALooper; //网络通信
sp<WifiDisplaySink> sink = new WifiDisplaySink(session); //RTSP协议交互显示类WifiDisplaySink
looper->registerHandler(sink); //注册消息处理类WifiDisplaySink
if (connectToPort >= 0) {
sink->start(connectToHost.c_str(), connectToPort);//传递IP和端口,开启RTSP交互
} else {
sink->start(uri.c_str());
}
looper->start(true /* runOnCallingThread */);//启动消息循环
return 0;
}
注:ALooper消息循环机制请参阅博客AHandler AMessage ALooper消息机制
接着看WifiDisplaySink的start方法,由于采用了AHandler消息机制,所以start里面并没有什么实际操作,而是创建一条消息发送出去,转给它的onMessageReceived方法进行处理。
WifiDisplaySink::start方法主要完成以下任务
- 创建一条消息"kWhatStart"并发送
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::start(const char *sourceHost, int32_t sourcePort) {
sp<AMessage> msg = new AMessage(kWhatStart, this); //创建消息
msg->setString("sourceHost", sourceHost);
msg->setInt32("sourcePort", sourcePort);
msg->post(); //发送消息
}
在onMessageReceived()的"case kWhatStart:"里面,将创建任务交给了ANetworkSession类
WifiDisplaySink::onMessageReceived的case kWhatStart方法主要完成以下任务
- 调用ANetworkSession创建RTSP客户端
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatStart:
{
int32_t sourcePort;
... ...
sp<AMessage> notify = new AMessage(kWhatRTSPNotify, this); //创建一条notify消息,用于建立会话后回调
status_t err = mNetSession->createRTSPClient(
mRTSPHost.c_str(), sourcePort, notify, &mSessionID); //调用ANetworkSession::createRTSPClient创建RTSP客户端
mState = CONNECTING; //设置当前状态为连接中
break;
}
... ...
default:
TRESPASS();
}
ANetworkSession::createRTSPClient方法只是一个方法的封装,也没有实际操作,而是将任务交给了createClientOrServer集中进行处理。
ANetworkSession::createRTSPClient的方法主要完成以下任务
- 调用createClientOrServer方法
//frameworks/av/media/libstagefright/foundation/ANetworkSession.cpp
status_t ANetworkSession::createRTSPClient(
const char *host, unsigned port, const sp<AMessage> ¬ify,
int32_t *sessionID) {
return createClientOrServer( //实际调用createClientOrServer方法
kModeCreateRTSPClient,
NULL /* addr */,
0 /* port */,
host,
port,
notify,
sessionID);
}
ANetworkSession::createClientOrServer是一个复杂的方法,用于创建Socket和会话等
ANetworkSession::createClientOrServer方法主要完成以下任务
- 和对端Server端(Source端)建立socket连接
- 创建会话
//frameworks/av/media/libstagefright/foundation/ANetworkSession.cpp
status_t ANetworkSession::createClientOrServer(
Mode mode,
const struct in_addr *localAddr,
unsigned port,
const char *remoteHost,
unsigned remotePort,
const sp<AMessage> ¬ify,
int32_t *sessionID) {
Mutex::Autolock autoLock(mLock);
*sessionID = 0;
status_t err = OK;
int s, res;
sp<Session> session;
//创建套接字描述符
s = socket(
AF_INET,
(mode == kModeCreateUDPSession) ? SOCK_DGRAM : SOCK_STREAM,
0);
... ...
err = MakeSocketNonBlocking(s);
//构建服务器地址
struct sockaddr_in addr;
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
addr.sin_family = AF_INET;
//将上面传送过来的IP和端口号设置为服务器设备地址
if (mode == kModeCreateRTSPClient
|| mode == kModeCreateTCPDatagramSessionActive) {
struct hostent *ent= gethostbyname(remoteHost);
... ...
addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
addr.sin_port = htons(remotePort);
}else if (localAddr != NULL) {
... ...
}
//connect函数阻塞直到连接成功或发送错误
if (mode == kModeCreateRTSPClient
|| mode == kModeCreateTCPDatagramSessionActive) {
in_addr_t x = ntohl(addr.sin_addr.s_addr);
res = connect(s, (const struct sockaddr *)&addr, sizeof(addr));
} else {
... ...
}
//设置会话状态为连接中
Session::State state;
switch (mode) {
case kModeCreateRTSPClient:
state = Session::CONNECTING;
break;
... ...
}
//创建会话
session = new Session(
mNextSessionID++,
state,
s,
notify);
if (mode == kModeCreateTCPDatagramSessionActive) {
session->setMode(Session::MODE_DATAGRAM);
} else if (mode == kModeCreateRTSPClient) {
session->setMode(Session::MODE_RTSP); //设置会话模型为RTSP
}
mSessions.add(session->sessionID(), session);
interrupt();
*sessionID = session->sessionID(); //设置会话ID
... ...
}
当Session成功建立后接收到来自服务端(Source端)的消息后会回调WifiDisplaySink::onMessageReceived的"case kWhatRTSPNotify"
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onMessageReceived(const sp<AMessage> &msg) {
... ...
case kWhatRTSPNotify:
{
... ...
switch (reason) {
case ANetworkSession::kWh