ARTSPConnection::receiveRTSPReponse

bool ARTSPConnection::receiveRTSPReponse() {
    AString statusLine;

    //調用函數receiveLine從套接口獲取服務端消息的第一行,在下文被稱爲狀態行statusLine
    if (!receiveLine(&statusLine)) {
        return false;
    }

    if (statusLine == "$") {
        //如果狀態行statusLine爲字符"$",則需要接收二進制數據
        //這裏不具體討論如何接收二進制數據
        sp<ABuffer> buffer = receiveBinaryData();

        if (buffer == NULL) {
            return false;
        }

        if (mObserveBinaryMessage != NULL) {
            sp<AMessage> notify = mObserveBinaryMessage->dup();
            notify->setBuffer("buffer", buffer);
            notify->post();
        } else {
            ALOGW("received binary data, but no one cares.");
        }

        return true;
    }

    //創建一個ARTSPResponse類對象來表述一個服務端的消息
    //將狀態行賦給該對象的成員變量mStatusLine
    sp<ARTSPResponse> response = new ARTSPResponse;
    response->mStatusLine = statusLine;

    ALOGI("status: %s", response->mStatusLine.c_str());

    ssize_t space1 = response->mStatusLine.find(" ");
    if (space1 < 0) {
        return false;
    }
    ssize_t space2 = response->mStatusLine.find(" ", space1 + 1);
    if (space2 < 0) {
        return false;
    }

    //布爾變量isRequest 是用來表示該RTSP消息是請求消息還是應答消息
    //即用來判斷該消息是服務端發送過來的請求消息還是服務端發送來的應答消息
    //具體的判別方法是根據版本號"RTSP/1.0"在狀態行statusLine存放的位置
    //對於請求消息的第一行:方法 URI RTSP版本 CR LF 
    //對於迴應消息的第一行:RTSP版本 狀態碼 解釋 CR LF
    bool isRequest = false;

    if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) {
        //如果IsRTSPVersion(AString(response->mStatusLine, 0, space1)的返回值不爲真說明mStatusLine[0,space1]存放的不是版本號"RTSP/1.0"
        //如果IsRTSPVersion(
        //            AString(
        //                response->mStatusLine,
        //                space2 + 1,
        //                response->mStatusLine.size() - space2 - 1))
        //的調用值爲真說明mStatusLine[space2 + 1,response->mStatusLine.size() - space2 - 1]存放的是版本號"RTSP/1.0"
        //則該消息爲服務端發送過來的請求消息,將isRequest 設置爲 true
        //將response對象的成員變量mStatusCode狀態碼設置爲0,因爲只有迴應消息纔有狀態碼
        CHECK(IsRTSPVersion(
                    AString(
                        response->mStatusLine,
                        space2 + 1,
                        response->mStatusLine.size() - space2 - 1)));

        isRequest = true;

        response->mStatusCode = 0;
    } else {
        //代碼執行到else分支說明IsRTSPVersion(AString(response->mStatusLine, 0, space1)返回值爲真
        //說明mStatusLine[0,space1]存放的是版本號"RTSP/1.0",由於isRequest初始值爲false,所以在這裏不需要再賦值爲false了
        //從mStatusLine[space1 + 1,space2 - space1 - 1]獲取到狀態碼的字符表示
        AString statusCodeStr(
                response->mStatusLine, space1 + 1, space2 - space1 - 1);

        //調用ParseSingleUnsignedLong函數將字符表示的狀態碼轉換成整數表示的狀態碼,並賦值爲response的成員變量mStatusCode
        //狀態碼有效的整數值範圍爲100~999(包括100和999)
        if (!ParseSingleUnsignedLong(
                    statusCodeStr.c_str(), &response->mStatusCode)
                || response->mStatusCode < 100 || response->mStatusCode > 999) {
            return false;
        }
    }

    //代碼執行到這裏成功判斷了該消息是服務端發送來的迴應消息還是請求消息,由布爾變量isRequest表示
    //接下來要獲取消息後續的行,緊接着是消息頭headers,會有多個消息頭
    //一個消息頭佔據一到多個行,若佔據多個行,後續的行開頭用空格' '或者製表符'\t'來標識
    AString line;
    //lastDictIndex變量用來標識上一個消息頭在對象response的成員變量mHeaders容器裏存放的位置
    ssize_t lastDictIndex = -1;

    //採用一個無限循環來獲取剩餘的所有的行
    for (;;) {
        //調用函數receiveLine來獲取一行
        if (!receiveLine(&line)) {
            break;
        }

        //如果該行爲空,則停止獲取,終止循環
        if (line.empty()) {
            break;
        }

        ALOGV("line: '%s'", line.c_str());

        //如果獲取的該行首字符爲' '或者'\t'則,說明該回去的一行是上一行攜帶的參數值
        //將該行和上一行合併在一起
        if (line.c_str()[0] == ' ' || line.c_str()[0] == '\t') {
            // Support for folded header values.

            if (lastDictIndex < 0) {
                //lastDictIndex變的值爲負,說明沒有任何行添加到了對象response的成員變量mHeaders容器裏
                //既然該獲取的行又被表示爲上一行攜帶的參數,顯然是發生了錯誤
                // First line cannot be a continuation of the previous one.
                return false;
            }

            //根據lastDictIndex變量得到上一行在response的成員變量mHeaders容器裏存放的引用
            AString &value = response->mHeaders.editValueAt(lastDictIndex);
            //將該被表示爲上一行引用的一行和上一行進行合併
            //continue跳出本次循環繼續獲取下一行
            value.append(line);

            continue;
        }

        //代碼執行到這裏說明該行的首字符不是' '或者'\t',說明該行是一個header
        //給一個header的例子,Accept: application/rtsl, application/sdp;level=2
        //冒號前的字符是該header的key
        //查找冒號在改行的位置colonPos
        ssize_t colonPos = line.find(":");
        if (colonPos < 0) {
            //如果colonPos的值小於0,則說明該行是一個錯誤的header line
            // Malformed header line.
            return false;
        }

        //從該行獲取該行的header line的key
        AString key(line, 0, colonPos);
        key.trim();
        key.tolower();

        //將該行的header line的key從該行刪除
        line.erase(0, colonPos + 1);

        //用key,value的方式將該header line的key與其內容保存在response->mHeaders容器裏
        //並將其保存的位置索引保存在變量lastDictIndex中
        lastDictIndex = response->mHeaders.add(key, line);
    }

    //代碼執行到這裏,已經跳出了for循環
    for (size_t i = 0; i < response->mHeaders.size(); ++i) {

        response->mHeaders.editValueAt(i).trim();
    }

    //開始分析key爲content-length的header line
    unsigned long contentLength = 0;

    ssize_t i = response->mHeaders.indexOfKey("content-length");

    if (i >= 0) {
        //根據content-length這一個header line存放的位置索引i得到該header line 的value
        AString value = response->mHeaders.valueAt(i);
        //調用ParseSingleUnsignedLong將該content-length的值的字符表示轉換成整數表示
        if (!ParseSingleUnsignedLong(value.c_str(), &contentLength)) {
            return false;
        }
    }

    if (contentLength > 0) {
        //如果contentLength的值大於0,則需要創建一個buffer並調用receive函數從創建的套接口獲取內容
        //並將緩衝區的引用賦值給response->mContent
        response->mContent = new ABuffer(contentLength);

        if (receive(response->mContent->data(), contentLength) != OK) {
            return false;
        }
    }

    if (response->mStatusCode == 401) {
        //對狀態碼爲401的迴應消息做特別的處理
        if (mAuthType == NONE && mUser.size() > 0
                && parseAuthMethod(response)) {
            ssize_t i;
            CHECK_EQ((status_t)OK, findPendingRequest(response, &i));
            CHECK_GE(i, 0);

            sp<AMessage> reply = mPendingRequests.valueAt(i);
            mPendingRequests.removeItemsAt(i);

            AString request;
            CHECK(reply->findString("original-request", &request));

            sp<AMessage> msg = new AMessage(kWhatSendRequest, this);
            msg->setMessage("reply", reply);
            msg->setString("request", request.c_str(), request.size());

            ALOGI("re-sending request with authentication headers...");
            onSendRequest(msg);

            return true;
        }
    }


    //對RTSP消息進行處理
    //如果isRequest爲真,說明response是服務端發送過來的請求消息則調用handleServerRequest(response)處理服務端發送來的請求消息
    //如果isRequest不爲真說明response是服務端發送過來的迴應消息,調用notifyResponseListener(response)函數處理服務端發送過來的消息
    return isRequest
        ? handleServerRequest(response)
        : notifyResponseListener(response);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章