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::kWhatConnected:
{
mState = CONNECTED; //设置状态为已连接
if (!mSetupURI.empty()) {
status_t err =
sendDescribe(mSessionID, mSetupURI.c_str());
}
break;
}
... ...
}
... ...
}
至此Sink端(Client端)和Source端(Server端)建立了Socket连接,或者说两个设备的WFD进程建立了连接。可以开始RTSP协议的交互了。
2.RTSP协议交互
省略UIBC和HDCP交互,RTSP协议交互也分为以下三个阶段
- WFD capability negotiation
- WFD session establishment
- AV streaming and control
下表简单列出M1-M7消息的简述
Message | Method | Direct | 简述 |
---|---|---|---|
M1 | OPTIONS | Source -> Sink | 打招呼 |
M2 | OPTIONS | Source <- Sink | 打招呼 |
M3 | GET_PARAMETER | Source -> Sink | 你支持什么音视频格式 |
M4 | SET_PARAMETER | Source -> Sink | 我们使用这个格式吧 |
M5 | SETUP | Source -> Sink | 建立连接吧 |
M6 | SETUP | Source <- Sink | 建立连接吧 |
M7 | PLAY | Source <- Sink | 开始发送数据吧 |
注:每个Message发送后,都会收到到对方发送的一个表明状态的Response
2.1 WFD capability negotiation阶段(M1-M4)
当接收到Source端发送的M1 Request以后
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onMessageReceived(const sp<AMessage> &msg) {
... ...
case kWhatRTSPNotify:
{
... ...
switch (reason) {
case ANetworkSession::kWhatData: //判断接收到的是数据
{
onReceiveClientData(msg); //调用进行处理
break;
}
... ...
}
... ...
}
调用WifiDisplaySink::onReceiveClientData进行处理
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onReceiveClientData(const sp<AMessage> &msg) {
int32_t sessionID;
CHECK(msg->findInt32("sessionID", &sessionID)); //获取sessionID
sp<RefBase> obj;
CHECK(msg->findObject("data", &obj)); //获取数据
sp<ParsedMessage> data =
static_cast<ParsedMessage *>(obj.get()); //解析数据
AString method;
AString uri;
data->getRequestField(0, &method);
int32_t cseq;
if (!data->findInt32("cseq", &cseq)) { //如果没有cseq字段则错误
sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
return;
}
if (method.startsWith("RTSP/")) { //如果是"RTSP"开头,则是Response,检查是否OK
// This is a response.
ResponseID id;
id.mSessionID = sessionID;
id.mCSeq = cseq;
ssize_t index = mResponseHandlers.indexOfKey(id);
if (index < 0) {
ALOGW("Received unsolicited server response, cseq %d", cseq);
return;
}
HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
mResponseHandlers.removeItemsAt(index);
status_t err = (this->*func)(sessionID, data);
CHECK_EQ(err, (status_t)OK);
} else { //否则的话收到的是Request
AString version;
data->getRequestField(2, &version);
if (!(version == AString("RTSP/1.0"))) { //检查RTSP版本
sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
return;
}
if (method == "OPTIONS") { //M1 Request的method字段是"OPTIONS",所以进入这个分支
onOptionsRequest(sessionID, cseq, data);
} else if (method == "GET_PARAMETER") {
onGetParameterRequest(sessionID, cseq, data);
} else if (method == "SET_PARAMETER") {
onSetParameterRequest(sessionID, cseq, data);
} else {
sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
}
}
}
接着会调用onOptionsRequest这个方法构建并发送M1 Response,紧接着发送M2 Request
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onOptionsRequest(
int32_t sessionID,
int32_t cseq,
const sp<ParsedMessage> &data) {
... ...
//构建M1 Response
AString response = "RTSP/1.0 200 OK\r\n";
AppendCommonResponse(&response, cseq);
response.append("Public: org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER\r\n");
response.append("\r\n");
//发送M1 Response
status_t err = mNetSession->sendRequest(sessionID, response.c_str()); //调用ANetworkSession进行发送
CHECK_EQ(err, (status_t)OK);
//发送M2 Request
err = sendM2(sessionID);
CHECK_EQ(err, (status_t)OK);
}
接着看M2 Request的发送函数sendM2
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::sendM2(int32_t sessionID) {
//构建request消息
AString request = "OPTIONS * RTSP/1.0\r\n";
AppendCommonResponse(&request, mNextCSeq);
request.append(
"Require: org.wfa.wfd1.0\r\n"
"\r\n");
status_t err =
mNetSession->sendRequest(sessionID, request.c_str(), request.size()); //调用ANetworkSession进行发送
if (err != OK) {
return err;
}
registerResponseHandler(
sessionID, mNextCSeq, &WifiDisplaySink::onReceiveM2Response); //注册M2 Response接收函数
++mNextCSeq;
return OK;
}
上面在发送M2 Request的时候已经注册了接收函数,此时当ANetworkSession接收到M2 Response后会通过ALooper转给WifiDisplaySink::onReceiveM2Response进行处理,处理也很简单,就是看是否OK
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::onReceiveM2Response(
int32_t sessionID, const sp<ParsedMessage> &msg) {
int32_t statusCode;
if (!msg->getStatusCode(&statusCode)) {
return ERROR_MALFORMED;
}
if (statusCode != 200) {
return ERROR_UNSUPPORTED;
}
return OK;
}
接下来等待Source端发送过来M3 Request,和接收M1 Request的过程一样,先到达WifiDisplaySink::onMessageReceived,然后到WifiDisplaySink::onReceiveClientData进行辨识,判断是M3 Request,也就是GET_PARAMETER。
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onReceiveClientData(const sp<AMessage> &msg) {
... ...
if (method == "OPTIONS") {
onOptionsRequest(sessionID, cseq, data);
} else if (method == "GET_PARAMETER") { //接收到M3 Request消息
onGetParameterRequest(sessionID, cseq, data);
} else if (method == "SET_PARAMETER") {
onSetParameterRequest(sessionID, cseq, data);
} else {
sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
}
... ...
}
接着看处理函数WifiDisplaySink::onGetParameterRequest,这里会构造并发送M3 Response
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onGetParameterRequest(
int32_t sessionID,
int32_t cseq,
const sp<ParsedMessage> &data) {
int32_t statusCode;
//这里申明Sink端支持的音视频格式等,具体请参阅《Wi-Fi_Display_Technical_Specification_v2.1_0.pdf》 第6.1小节 RTSP data structures
AString body =
"wfd_video_formats: xxx\r\n"
"wfd_audio_codecs: xxx\r\n"
"wfd_client_rtp_ports: RTP/AVP/UDP;unicast xxx 0 mode=play\r\n";
//构造M3 Response
AString response = "RTSP/1.0 200 OK\r\n";
AppendCommonResponse(&response, cseq);
response.append("Content-Type: text/parameters\r\n");
response.append(AStringPrintf("Content-Length: %d\r\n", body.size()));
response.append("\r\n");
response.append(body);
status_t err = mNetSession->sendRequest(sessionID, response.c_str()); //调用ANetworkSession进行发送
CHECK_EQ(err, (status_t)OK);
}
特别注意主要上面的body字符串,wfd_video_formats(视频格式)和wfd_audio_codecs(音频格式)后面的xxx需要结合自己平台支持的音视频格式按照《Wi-Fi_Display_Technical_Specification_v2.1_0.pdf》 协议 第6.1小节中的格式顺序自己组装成类似以下的字符串
"wfd_video_formats: 40 00 02 04 0001DEFF 053C7FFF 00000FFF 00 0000 0000 11 none none\r\n"
"wfd_audio_codecs: AAC 00000001 00\r\n"
Source端所有支持的WFD功能都在这里标明,包括是否支持HDCP、UIBC等,格式也是按照《Wi-Fi_Display_Technical_Specification_v2.1_0.pdf》 协议 第6.1小节中的格式顺序。
接下来等待Source端发送过来M4 Request,和接收M1 Request的过程一样,先到达WifiDisplaySink::onMessageReceived,然后到WifiDisplaySink::onReceiveClientData进行辨识,判断是M4 Request,也就是SET_PARAMETER。
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onReceiveClientData(const sp<AMessage> &msg) {
... ...
if (method == "OPTIONS") {
onOptionsRequest(sessionID, cseq, data);
} else if (method == "GET_PARAMETER") {
onGetParameterRequest(sessionID, cseq, data);
} else if (method == "SET_PARAMETER") { //接收到M4 Request消息
onSetParameterRequest(sessionID, cseq, data);
} else {
sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
}
... ...
}
接着看onSetParameterRequest方法,这个方法会检查M4发送过来的Request参数本地(Sink端)是否支持,如果支持的话回复M4 Response
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onSetParameterRequest(
int32_t sessionID,
int32_t cseq,
const sp<ParsedMessage> &data) {
const char *content = data->getContent();
onSetParameterRequest_CheckM4Parameter(content); //M4的话会检查M4 Request的参数本端是否支持
... ...
//构造答复
AString response = "RTSP/1.0 200 OK\r\n";
AppendCommonResponse(&response, cseq);
response.append("\r\n");
status_t err = mNetSession->sendRequest(sessionID, response.c_str()); //调用ANetworkSession进行发送
CHECK_EQ(err, (status_t)OK);
}
至此M1-M4交互完毕,WFD capability negotiation完毕,进入WFD session establishment阶段
2.2 WFD session establishment阶段 (M5-M6)
接下来等待Source端发送过来M5 Request,和接收M1 Request的过程一样,先到达WifiDisplaySink::onMessageReceived,然后到WifiDisplaySink::onReceiveClientData进行辨识,判断是M5 Request,也就是SET_PARAMETER。
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onReceiveClientData(const sp<AMessage> &msg) {
... ...
if (method == "OPTIONS") {
onOptionsRequest(sessionID, cseq, data);
} else if (method == "GET_PARAMETER") {
onGetParameterRequest(sessionID, cseq, data);
} else if (method == "SET_PARAMETER") { //接收到M5 Request消息
onSetParameterRequest(sessionID, cseq, data);
} else {
sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
}
... ...
}
接着看onSetParameterRequest方法,首先判断是有方法"SETUP"的话,直接启动M6 Request发送,紧接着发送M5 Response
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
void WifiDisplaySink::onSetParameterRequest(
int32_t sessionID,
int32_t cseq,
const sp<ParsedMessage> &data) {
const char *content = data->getContent();
//发送M6 Request
if (strstr(content, "wfd_trigger_method: SETUP\r\n") != NULL) {
AString uri = AStringPrintf("rtsp://%s/wfd1.0/streamid=0", mPresentation_URL.c_str());
status_t err =
sendSetup(
sessionID,
uri.c_str());
CHECK_EQ(err, (status_t)OK);
}
... ...
//回复M5 Response
AString response = "RTSP/1.0 200 OK\r\n";
AppendCommonResponse(&response, cseq);
response.append("\r\n");
status_t err = mNetSession->sendRequest(sessionID, response.c_str()); //调用ANetworkSession进行发送
CHECK_EQ(err, (status_t)OK);
}
接着看M6 Request的发送函数WifiDisplaySink::sendSetup()
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::sendSetup(int32_t sessionID, const char *uri) {
//创建RTPSink类用于处理RTP/RTCP协议
mRTPSink = new RTPSink(mNetSession, mSurfaceTex);
mRTPSink->setHDCP(mHDCP);
looper()->registerHandler(mRTPSink); //RTPSink注册到消息循环
status_t err = mRTPSink->init(sUseTCPInterleaving); //初始化RTPSink,这里传入的sUseTCPInterleaving在头文件里面默认为false
if (err != OK) {
looper()->unregisterHandler(mRTPSink->id());
mRTPSink.clear();
return err;
}
AString request = AStringPrintf("SETUP %s RTSP/1.0\r\n", uri);
AppendCommonResponse(&request, mNextCSeq);
if (sUseTCPInterleaving) {
request.append("Transport: RTP/AVP/TCP;interleaved=0-1\r\n");
} else {
int32_t rtpPort = mRTPSink->getRTPPort();
request.append(
AStringPrintf(
"Transport: RTP/AVP/UDP;unicast;client_port=%d-%d\r\n",
rtpPort, rtpPort + 1));
}
request.append("\r\n");
err = mNetSession->sendRequest(sessionID, request.c_str(), request.size()); //调用ANetworkSession进行发送
if (err != OK) {
return err;
}
registerResponseHandler(
sessionID, mNextCSeq, &WifiDisplaySink::onReceiveSetupResponse); //注册M6 Response接收函数
++mNextCSeq;
return OK;
}
上面的RTPSink创建和初始化以及下面的configureTransport用于创建传输RTP数据流的连接,我们先顺着主线看RTSP交互,后面分析这条线
接着看WifiDisplaySink::onReceiveSetupResponse,这里接收M6 Response
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::onReceiveSetupResponse(
int32_t sessionID, const sp<ParsedMessage> &msg) {
int32_t statusCode;
//检查是否错误
if (!msg->getStatusCode(&statusCode)) {
return ERROR_MALFORMED;
}
if (statusCode != 200) {
return ERROR_UNSUPPORTED;
}
if (!msg->findString("session", &mPlaybackSessionID)) {
return ERROR_MALFORMED;
}
//获取超时
if (!ParsedMessage::GetInt32Attribute(
mPlaybackSessionID.c_str(),
"timeout",
&mPlaybackSessionTimeoutSecs)) {
mPlaybackSessionTimeoutSecs = -1;
}
ssize_t colonPos = mPlaybackSessionID.find(";");
if (colonPos >= 0) {
// Strip any options from the returned session id.
mPlaybackSessionID.erase(
colonPos, mPlaybackSessionID.size() - colonPos);
}
status_t err = configureTransport(msg); //配置Server端RTP和RTCP传送端口
... ...
mState = PAUSED; //设置状态为暂停
return sendPlay(
sessionID,
!mSetupURI.empty()
? mSetupURI.c_str() : playCommand.c_str()); //发送M7 Request
}
2.3 AV streaming and control阶段 (M7)
发送M7 Request
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::sendPlay(int32_t sessionID, const char *uri) {
AString request = AStringPrintf("PLAY %s RTSP/1.0\r\n", uri);
AppendCommonResponse(&request, mNextCSeq);
request.append(AStringPrintf("Session: %s\r\n", mPlaybackSessionID.c_str()));
request.append("\r\n");
status_t err =
mNetSession->sendRequest(sessionID, request.c_str(), request.size()); //调用ANetworkSession进行发送
if (err != OK) {
return err;
}
registerResponseHandler(
sessionID, mNextCSeq, &WifiDisplaySink::onReceivePlayResponse); //注册M7 Response接收函数
++mNextCSeq;
return OK;
}
接收M7 Response
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::onReceivePlayResponse(
int32_t sessionID, const sp<ParsedMessage> &msg) {
int32_t statusCode;
if (!msg->getStatusCode(&statusCode)) {
return ERROR_MALFORMED;
}
if (statusCode != 200) {
return ERROR_UNSUPPORTED;
}
mState = PLAYING; //设置状态为播放中
return OK;
}
至此RTSP交互完毕,我们接着上面的RTPSink创建继续分析
3.RTP/RTCP交互
这里会在端口15550和15551分别创建RTP socket和RTCP socket。用于接收数据流
//frameworks/av/media/libstagefright/wifi-display/sink/RTPSink.cpp
status_t RTPSink::init(bool useTCPInterleaving) {
if (useTCPInterleaving) { //sUseTCPInterleaving传过来为false
return OK;
}
int clientRtp;
sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, this); //创建RTP通知消息
sp<AMessage> rtcpNotify = new AMessage(kWhatRTCPNotify, this); //创建RTCP通知消息
//创建RTP socket
for (clientRtp = 15550;; clientRtp += 2) {
int32_t rtpSession;
status_t err = mNetSession->createUDPSession(
clientRtp, rtpNotify, &rtpSession);
if (err != OK) {
ALOGI("failed to create RTP socket on port %d", clientRtp);
continue;
}
//创建RTCP socket
int32_t rtcpSession;
err = mNetSession->createUDPSession(
clientRtp + 1, rtcpNotify, &rtcpSession);
if (err == OK) {
mRTPPort = clientRtp;
mRTPSessionID = rtpSession;
mRTCPSessionID = rtcpSession;
break;
}
mNetSession->destroySession(rtpSession);
}
if (mRTPPort == 0) {
return UNKNOWN_ERROR;
}
return OK;
}
配置M6 Response传送过来的server端RTP和RTCP端口
//frameworks/av/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
status_t WifiDisplaySink::configureTransport(const sp<ParsedMessage> &msg) {
ALOGD("WifiDisplaySink configureTransport");
if (sUseTCPInterleaving) {
return OK;
}
AString transport;
if (!msg->findString("transport", &transport)) {
ALOGE("Missing 'transport' field in SETUP response.");
return ERROR_MALFORMED;
}
AString sourceHost;
if (!ParsedMessage::GetAttribute(
transport.c_str(), "source", &sourceHost)) {
sourceHost = mRTSPHost;
}
int rtpPort, rtcpPort;
AString serverPortStr;
if (ParsedMessage::GetAttribute(
transport.c_str(), "server_port", &serverPortStr)) {
if (sscanf(serverPortStr.c_str(), "%d-%d", &rtpPort, &rtcpPort) == 2) {
if (rtpPort <= 0 || rtpPort > 65535
|| rtcpPort <=0 || rtcpPort > 65535
|| rtcpPort != rtpPort + 1) {
ALOGE("Invalid server_port description '%s'.",
serverPortStr.c_str());
return ERROR_MALFORMED;
}
if (rtpPort & 1) {
ALOGW("Server picked an odd numbered RTP port.");
}
} else if (sscanf(serverPortStr.c_str(), "%d", &rtpPort) == 1) {
rtcpPort = rtpPort + 1;
} else {
ALOGE("Invalid server_port description '%s'.",
serverPortStr.c_str());
return ERROR_MALFORMED;
}
} else {
// ALOGI("Missing 'server_port' in Transport field. using default port");
// rtpPort = 33633;
// rtcpPort = 33634;
ALOGI("Missing 'server_port' in Transport field. so not link to source.(RTP)");
return OK;
}
return OK; // Now, we not care the "server_port" parameter.
// return mRTPSink->connect(sourceHost.c_str(), rtpPort, rtcpPort);
}
等待Source发送数据流过来
//frameworks/av/media/libstagefright/wifi-display/sink/RTPSink.cpp
void RTPSink::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatRTPNotify:
case kWhatRTCPNotify:
{
int32_t reason;
CHECK(msg->findInt32("reason", &reason));
switch (reason) {
... ...
case ANetworkSession::kWhatDatagram: //是数据流的话
{
int32_t sessionID;
CHECK(msg->findInt32("sessionID", &sessionID));
sp<ABuffer> data;
CHECK(msg->findBuffer("data", &data));
status_t err;
if (msg->what() == kWhatRTPNotify) {
err = parseRTP(data); //解析RTP数据
} else {
err = parseRTCP(data); //解析RTCP数据
}
break;
}
default:
TRESPASS();
}
... ...
}
}
在这里解析RTP数据包,然后发送给TunnelRenderer呈现
//frameworks/av/media/libstagefright/wifi-display/sink/RTPSink.cpp
status_t RTPSink::parseRTP(const sp<ABuffer> &buffer) {
... ...
ssize_t index = mSources.indexOfKey(srcId);
if (index < 0) {
if (mRenderer == NULL) {
sp<AMessage> notifyLost = new AMessage(kWhatPacketLost, this);
notifyLost->setInt32("ssrc", srcId);
mRenderer = new TunnelRenderer(notifyLost, mSurfaceTex); //创建TunnelRenderer
mRenderer->setHDCP(mHDCP);
looper()->registerHandler(mRenderer);
}
sp<AMessage> queueBufferMsg =
new AMessage(TunnelRenderer::kWhatQueueBuffer, mRenderer); //创建queueBufferMsg消息
sp<Source> source = new Source(seqNo, buffer, queueBufferMsg);
mSources.add(srcId, source);
} else {
mSources.valueAt(index)->updateSeq(seqNo, buffer);
}
return OK;
}
TunnelRenderer收到数据后调用initPlayer创建播放器
//frameworks/av/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
void TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatQueueBuffer:
{
sp<ABuffer> buffer;
CHECK(msg->findBuffer("buffer", &buffer));
queueBuffer(buffer); //数据入列
if (mStreamSource == NULL) {
if (mTotalBytesQueued > 0ll) {
initPlayer(); //初始化播放设备
} else {
ALOGI("Have %lld bytes queued...", (long long)mTotalBytesQueued);
}
} else {
mStreamSource->doSomeWork();
}
break;
}
default:
TRESPASS();
}
}
TunnelRenderer::initPlayer这里是创建播放器的地方,这里直接调用了Android原生的播放器
//frameworks/av/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
void TunnelRenderer::initPlayer() {
if (mSurfaceTex == NULL) {
mComposerClient = new SurfaceComposerClient;
CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
DisplayInfo info;
SurfaceComposerClient::getDisplayInfo(0, &info);
ssize_t displayWidth = info.w;
ssize_t displayHeight = info.h;
mSurfaceControl =
mComposerClient->createSurface(
String8("A Surface"),
displayWidth,
displayHeight,
PIXEL_FORMAT_RGB_565,
0);
CHECK(mSurfaceControl != NULL);
CHECK(mSurfaceControl->isValid());
//SurfaceComposerClient::openGlobalTransaction();
//CHECK_EQ(mSurfaceControl->getClient()->setLayer(INT_MAX), (status_t)OK);
//CHECK_EQ(mSurfaceControl->getClient()->show(), (status_t)OK);
SurfaceComposerClient::Transaction{}
.setLayer(mSurfaceControl, INT_MAX-1)
.show(mSurfaceControl)
.apply();
//SurfaceComposerClient::closeGlobalTransaction();
mSurface = mSurfaceControl->getSurface();
CHECK(mSurface != NULL);
}
sp<IServiceManager> sm = defaultServiceManager();//获取ServiceManager
sp<IBinder> binder = sm->getService(String16("media.player"));//通过binder拿到了名为media.player服务
sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);//获得MediaPlayerService服务
CHECK(service.get() != NULL);
mStreamSource = new StreamSource(this); //数据流
mStreamSource->setHDCP(mHDCP);
mPlayerClient = new PlayerClient; //创建播放器客户端
mPlayer = service->create(mPlayerClient, (audio_session_t)0);//来创建一个player
CHECK(mPlayer != NULL);
//CHECK_EQ(mPlayer->setDataSource(mStreamSource), (status_t)OK);
CHECK_EQ(mPlayer->setDataSource((sp<IStreamSource>)mStreamSource), (status_t)OK);//设置数据流
mPlayer->setVideoSurfaceTexture(
mSurfaceTex != NULL ? mSurfaceTex : mSurface->getIGraphicBufferProducer());
mPlayer->start(); //开始播放
}
这里是调到了Android的MediaPlayer进行实际的播放。