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::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消息的简述

MessageMethodDirect简述
M1OPTIONSSource -> Sink打招呼
M2OPTIONSSource <- Sink打招呼
M3GET_PARAMETERSource -> Sink你支持什么音视频格式
M4SET_PARAMETERSource -> Sink我们使用这个格式吧
M5SETUPSource -> Sink建立连接吧
M6SETUPSource <- Sink建立连接吧
M7PLAYSource <- 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进行实际的播放。

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值