WFD连接过程代码分析(Sink端)

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> &notify,
        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> &notify,
        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
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值