void setupTrack(size_t index) {
//由会话描述对象mSessionDesc和参数index创建一个APacketSource类型对象
sp<APacketSource> source =
new APacketSource(mSessionDesc, index);
if (source->initCheck() != OK) {
ALOGW("Unsupported format. Ignoring track #%zu.", index);
//对APacketSource类型对象source未能成功初始化的情况进行处理
//创建一个回应消息reply,消息名为'setu',消息的处理者为this,也即MyHandler
//将参数index设置到"index"字段
//将错误码ERROR_UNSUPPORTED设置到"result"字段
//发送该异步处理消息并返回
sp<AMessage> reply = new AMessage('setu', this);
reply->setSize("index", index);
reply->setInt32("result", ERROR_UNSUPPORTED);
reply->post();
return;
}
//代码执行到这里说明该APacketSource类型对象source成功完成了初始化
//从会话描述对象mSessionDesc里获取索引为index,key为"a=control"的value
AString url;
CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
//合并mBaseURL和url得到最终表述的媒体的位置
AString trackURL;
CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
//向容器mTracks里添加一个TrackInfo对象
//并完成一些初始化工作
mTracks.push(TrackInfo());
TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
//设置媒体的位置info->mURL
info->mURL = trackURL;
//设置媒体源对象info->mPacketSource
info->mPacketSource = source;
//设置是否使用InterleavedTCP
info->mUsingInterleavedTCP = false;
info->mFirstSeqNumInSegment = 0;
info->mNewSegment = true;
info->mAllowedStaleAccessUnits = kMaxAllowedStaleAccessUnits;
//初始化RTP和RTCP的套接字描述符
info->mRTPSocket = -1;
info->mRTCPSocket = -1;
info->mRTPAnchor = 0;
info->mNTPAnchorUs = -1;
//初始化NTP
info->mNormalPlayTimeRTP = 0;
info->mNormalPlayTimeUs = 0ll;
//由会话描述对象mSessionDesc的到索引为index的变量PT,formatDesc,formatParams的值
unsigned long PT;
AString formatDesc;
AString formatParams;
mSessionDesc->getFormatType(index, &PT, &formatDesc, &formatParams);
//由formatDesc.c_str()得到变量timescale和numChannels的值
//如何获取在后续的文章介绍
int32_t timescale;
int32_t numChannels;
ASessionDescription::ParseFormatDesc(
formatDesc.c_str(), ×cale, &numChannels);
info->mTimeScale = timescale;
info->mEOSReceived = false;
ALOGV("track #%zu URL=%s", mTracks.size(), trackURL.c_str());
//构建请求消息request 方法名为SETUP
AString request = "SETUP ";
request.append(trackURL);
request.append(" RTSP/1.0\r\n");
if (mTryTCPInterleaving) {
//mTryTCPInterleaving成员变量的值在MyHandler的构造函数中被初始化为false
size_t interleaveIndex = 2 * (mTracks.size() - 1);
info->mUsingInterleavedTCP = true;
info->mRTPSocket = interleaveIndex;
info->mRTCPSocket = interleaveIndex + 1;
request.append("Transport: RTP/AVP/TCP;interleaved=");
request.append(interleaveIndex);
request.append("-");
request.append(interleaveIndex + 1);
} else {
//调用AVMediaServiceUtils::get()->makePortPair函数构建RTP套接字描述符和RTCP套接字描述符以及rtp端口号
unsigned rtpPort;
AVMediaServiceUtils::get()->makePortPair(
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort,
mConn->isIPV6());
if (mUIDValid) {
HTTPBase::RegisterSocketUserTag(info->mRTPSocket, mUID,
(uint32_t)*(uint32_t*) "RTP_");
HTTPBase::RegisterSocketUserTag(info->mRTCPSocket, mUID,
(uint32_t)*(uint32_t*) "RTP_");
HTTPBase::RegisterSocketUserMark(info->mRTPSocket, mUID);
HTTPBase::RegisterSocketUserMark(info->mRTCPSocket, mUID);
}
//添加Transport消息头
//即将rtp端口号添加进去,以及加1作为rtcp端口号
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
request.append(rtpPort);
request.append("-");
request.append(rtpPort + 1);
}
request.append("\r\n");
if (index > 1) {
//如果index大于1,添加Session消息头部
request.append("Session: ");
request.append(mSessionID);
request.append("\r\n");
}
//添加消息头部和消息体的分隔符
request.append("\r\n");
//新建回应消息reply,消息名为'setu',消息处理者为this,即为MyHandler
//将index添加到reply的"index"字段
//将mTracks.size() - 1添加到reply的"track-index"字段
sp<AMessage> reply = new AMessage('setu', this);
reply->setSize("index", index);
reply->setSize("track-index", mTracks.size() - 1);
//调用mConn->sendRequest发用请求消息request.c_str()
//回应消息reply被暂存在mConn(sp<ARTSPConnection>)对象的mPendingRequests容器里
//直到服务端发送来对应的应答消息,该异步处理reply消息被发送出去
mConn->sendRequest(request.c_str(), reply);
}
给出一个SETUP方法的会话例子:
C->S: SETUP rtsp://example.com/foo/bar/baz.rm RTSP/1.0
CSeq: 302
Transport: RTP/AVP;unicast;client_port=4588-4589
S->C: RTSP/1.0 200 OK
CSeq: 302
Date: 23 Jan 1997 15:35:06 GMT
Session: 47112344
Transport: RTP/AVP;unicast;
client_port=4588-4589;server_port=6256-6257