case 'desc':
{
//从消息msg里的"result"字段得到错误码的值
int32_t result;
CHECK(msg->findInt32("result", &result));
ALOGI("DESCRIBE completed with result %d (%s)",
result, strerror(-result));
if (result == OK) {
//如果result的值为OK,说明成功收到了服务端发送过来的应答消息
//从消息msg的"response"字段获取服务端发送过来的应答消息对象response
sp<RefBase> obj;
CHECK(msg->findObject("response", &obj));
sp<ARTSPResponse> response =
static_cast<ARTSPResponse *>(obj.get());
if (response->mStatusCode == 301 || response->mStatusCode == 302) {
//对从服务端发送过来的应答消息的状态码为301或者302的情况进行处理
//本文不分析对301,301状态码的处理流程
ssize_t i = response->mHeaders.indexOfKey("location");
CHECK_GE(i, 0);
mOriginalSessionURL = response->mHeaders.valueAt(i);
mSessionURL = mOriginalSessionURL;
// Strip any authentication info from the session url, we don't
// want to transmit user/pass in cleartext.
AString host, path, user, pass;
unsigned port;
if (ARTSPConnection::ParseURL(
mSessionURL.c_str(), &host, &port, &path, &user, &pass)
&& user.size() > 0) {
mSessionURL.clear();
mSessionURL.append("rtsp://");
mSessionURL.append(host);
mSessionURL.append(":");
mSessionURL.append(AStringPrintf("%u", port));
mSessionURL.append(path);
ALOGI("rewritten session url: '%s'", mSessionURL.c_str());
}
sp<AMessage> reply = new AMessage('conn', this);
mConn->connect(mOriginalSessionURL.c_str(), reply);
break;
}
//代码执行到这里说明该从服务端发送过来的应答消息的
//状态码不为301,302
if (response->mStatusCode != 200) {
//如果状态码不为200,将错误码UNKNOWN_ERROR赋值给result
result = UNKNOWN_ERROR;
} else if (response->mContent == NULL) {
//代码执行到这里说明。状态码为200,
//但是应答消息的内容为空,
//则将错误码ERROR_MALFORMED赋值给result
result = ERROR_MALFORMED;
ALOGE("The response has no content.");
} else {
//代码执行到这里说明状态码为200
//并且应答消息的内容也不为空
//创建一个会话描述对象
mSessionDesc = new ASessionDescription;
//将应答消息的内容的缓冲区赋值给该会话描述对象mSessionDesc
mSessionDesc->setTo(
response->mContent->data(),
response->mContent->size());
if (!mSessionDesc->isValid()) {
//如果mSessionDesc->isValid()的返回值是false
//则说明该会话描述对象是无效的
//将错误码ERROR_MALFORMED赋值给result
ALOGE("Failed to parse session description.");
result = ERROR_MALFORMED;
} else {
//代码执行到这里说明该会话描述对象是有效的
//从应答消息对象response的mHeaders
//成员变量获取key为"content-base"的值
ssize_t i = response->mHeaders.indexOfKey("content-base");
if (i >= 0) {
//将获取到key为"content-base"的值赋值给mBaseURL
mBaseURL = response->mHeaders.valueAt(i);
} else {
//代码执行到这里
//说明i的值小于0,即不存在key为"content-base"的头部
//则需要查询key为"content-location"的头部
i = response->mHeaders.indexOfKey("content-location");
if (i >= 0) {
//将key为"content-location"头部的
//内容赋值给mBaseURL
mBaseURL = response->mHeaders.valueAt(i);
} else {
//代码执行到这里
//说明在应答消息对象response里
//即不存在key为"content-base"
//也不存在key为"content-location"的头部
//则将mSessionURL的值赋值给mBaseURL
mBaseURL = mSessionURL;
}
}
//判断该媒体是否能被seek
//如果不为直播媒体流则可以被seek
mSeekable = !isLiveStream(mSessionDesc);
if (!mBaseURL.startsWith("rtsp://")) {
//mBaseURL.startsWith("rtsp://")的值为fasle
//说明服务端给出的是相对的url
//需要将该相对url与绝对url合并在一起来定位媒体的位置
// Some misbehaving servers specify a relative
// URL in one of the locations above, combine
// it with the absolute session URL to get
// something usable...
ALOGW("Server specified a non-absolute base URL"
", combining it with the session URL to "
"get something usable...");
AString tmp;
//合并相对url和绝对url
//相对url是mBaseURL.c_str()
//绝对url是mSessionURL.c_str()
//具体是怎样的合并规则后续再研究介绍给大家
CHECK(MakeURL(
mSessionURL.c_str(),
mBaseURL.c_str(),
&tmp));
mBaseURL = tmp;
}
//对于Control信息的处理
//详细的处理过程后续介绍
mControlURL = getControlURL();
if (mSessionDesc->countTracks() < 2) {
//如果会话描述的媒体的Tracks小于2
//则将错误码ERROR_UNSUPPORTED赋值给result
// There's no actual tracks in this session.
// The first "track" is merely session meta
// data.
ALOGW("Session doesn't contain any playable "
"tracks. Aborting.");
result = ERROR_UNSUPPORTED;
} else {
//创建索引为1的tarck
setupTrack(1);
}
}
}
}
if (result != OK) {
//如果在上面过程中result的值不为OK
//发送消息消息名为'disc'取消连接
sp<AMessage> reply = new AMessage('disc', this);
mConn->disconnect(reply);
}
break;
}
小结:MyHandler对’desc’消息的处理的主要工作就是创建一个会话对象。