代码改变世界

一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——实现篇:(三)用户接口层之RTSP命令

2017-07-10 23:32  Ansersion  阅读(1311)  评论(0编辑  收藏  举报

截至版本1.2.3,myRtspClient函数库共支持以下6个RTSP命令(RFC 2326):

(1)OPTIONS

(2)DESCRIBE

(3)SETUP

(4)PLAY

(5)PAUSE

(6)TEARDOWN

对应的接口函数都以“Do”开头,如“DoOPTIONS”。各个接口函数写法相似,大同小异,差异部分会在后续章节做说明,现以DoOPTIONS()和DoPLAY()举例。

 

一、ErrorType RtspClient::DoOPTIONS(string uri)

 1 ErrorType RtspClient::DoOPTIONS(string uri)
 2 {   
 3     string RtspUri("");
 4     int Sockfd = -1;
 5     
 6     if(uri.length() != 0) {
 7         RtspUri.assign(uri);
 8         RtspURI.assign(uri);
 9     }
10     else if(RtspURI.length() != 0) RtspUri.assign(RtspURI);
11     else return RTSP_INVALID_URI;
12 
13     Sockfd = CreateTcpSockfd(RtspUri);
14     if(Sockfd < 0) return RTSP_INVALID_URI;
15         
16     string Cmd("OPTIONS");
17     stringstream Msg("");
18     Msg << Cmd << " " << RtspUri << " " << "RTSP/" << VERSION_RTSP << "\r\n";
19     Msg << "CSeq: " << ++RtspCSeq << "\r\n";
20     Msg << "\r\n";
21 
22     if(!SendRTSP(Sockfd, Msg.str())) {
23         Close(Sockfd);
24         return RTSP_SEND_ERROR;
25     }
26     if(!RecvRTSP(Sockfd, &RtspResponse)) {
27         Close(Sockfd);
28         return RTSP_RECV_ERROR;
29     }
30     return RTSP_NO_ERROR;
31 }

第6-11行,获取RTSP的URI(如rtsp://127.0.0.1/ansersion)。先检查DoOPTIONS参数传入的URI,如果不存在就使用类成员变量RtspURI(更多说明见“实现篇(二)二、RtspClient::RtspClient(string uri)”),若RtspURI也不存在则返回失败。如果参数传入URI,该URI同时会保存至类成员变量RtspURI从而记忆住该URI,以便后续调用“DoXXX”RTSP命令函数时,不必再重复传入URI。

第13-14行,根据URI创建socket,用于和RTSP服务端通信(注:CreateTcpSockfd会根据URI中的IP创建socket,如果以前创建过socket且未关闭,则继续沿用旧有socket。截至版本1.2.3,仅支持使用IPv4的URI)。

第16-20行,组建OPTIONS报文(参见RFC2326 10.1)。

第22-25行,向服务端发送OPTIONS报文。

第26-29行,接收服务端返回报文,并将报文赋值给类成员变量RtspResponse(可以通过GetResponse()获取该值)。

第30行,返回成功。

 

二、ErrorType RtspClient::DoPLAY(MediaSession * media_session)

 1 ErrorType RtspClient::DoPLAY(MediaSession * media_session)
 2 {
 3     if(!media_session) {
 4         return RTSP_INVALID_MEDIA_SESSION;
 5     }
 6 
 7     ErrorType Err = RTSP_NO_ERROR;
 8     int Sockfd = -1;
 9     Sockfd = CreateTcpSockfd();
10     if(Sockfd < 0) return RTSP_INVALID_URI;
11 
12     string Cmd("PLAY");
13     stringstream Msg("");
14     Msg << Cmd << " " << RtspURI << " " << "RTSP/" << VERSION_RTSP << "\r\n";
15     Msg << "CSeq: " << ++RtspCSeq << "\r\n";
16     Msg << "Session: " << media_session->SessionID << "\r\n";
17     if(Realm.length() > 0 && Nonce.length() > 0) {
18         string RealmTmp = Realm;
19         string NonceTmp = Nonce;
20         string Md5Response  = MakeMd5DigestResp(RealmTmp, Cmd, RtspURI,  NonceTmp);
21         if(Md5Response.length() != MD5_SIZE) {
22             cout << "Make MD5 digest response error" << endl;
23             return RTSP_RESPONSE_401;
24         }
25         Msg << "Authorization: Digest username=\"" << Username << "\", realm=\""
26             << RealmTmp << "\", nonce=\"" << NonceTmp << "\", uri=\"" << RtspURI
27             << "\", response=\"" << Md5Response << "\"\r\n";
28     }
29     Msg << "\r\n";
30 
31     if(RTSP_NO_ERROR == Err && !SendRTSP(Sockfd, Msg.str())) {
32         Close(Sockfd);
33         Sockfd = -1;
34         Err = RTSP_SEND_ERROR;
35     }
36     if(RTSP_NO_ERROR == Err && !RecvRTSP(Sockfd, &RtspResponse)) {
37         Close(Sockfd);
38         Sockfd = -1;
39         Err = RTSP_RECV_ERROR;
40     }
41     return RTSP_NO_ERROR;
42 }

第3-5行,判断media_session是否有效(MediaSession类存有音频或视频相关信息,后续章节将做说明)。

第9-10行,创建socket。

第12-29行,组建PLAY报文(参见RFC2326 10.5),其中第17-28行在报文中加入鉴权信息(参见RFC2069),如果不需要鉴权则可略去。

第31-35行,向服务端发送PLAY报文。

第36-40行,接收服务端返回报文。

example代码中使用的是ErrorType RtspClient::DoPLAY(string media_type),是该函数的封装,参数media_type取“video”或“audio”。

 

 

上一篇                       回目录                      下一篇