1 // PHZ
2 // 2018-5-16
3 
4 #if defined(WIN32) || defined(_WIN32)
5 #ifndef _CRT_SECURE_NO_WARNINGS
6 #define _CRT_SECURE_NO_WARNINGS
7 #endif
8 #endif
9 
10 #include "RtspMessage.h"
11 #include "media.h"
12 
13 using namespace std;
14 using namespace xop;
15 
ParseRequest(BufferReader * buffer)16 bool RtspRequest::ParseRequest(BufferReader *buffer)
17 {
18 	if(buffer->Peek()[0] == '$') {
19 		method_ = RTCP;
20 		return true;
21 	}
22 
23 	bool ret = true;
24 	while(1) {
25 		if(state_ == kParseRequestLine) {
26 			const char* firstCrlf = buffer->FindFirstCrlf();
27 			if(firstCrlf != nullptr)
28 			{
29 				ret = ParseRequestLine(buffer->Peek(), firstCrlf);
30 				buffer->RetrieveUntil(firstCrlf + 2);
31 			}
32 
33 			if (state_ == kParseHeadersLine) {
34 				continue;
35 			}
36 			else {
37 				break;
38 			}
39 		}
40 		else if(state_ == kParseHeadersLine) {
41 			const char* lastCrlf = buffer->FindLastCrlf();
42 			if(lastCrlf != nullptr) {
43 				ret = ParseHeadersLine(buffer->Peek(), lastCrlf);
44 				buffer->RetrieveUntil(lastCrlf + 2);
45 			}
46 			break;
47 		}
48 		else if(state_ == kGotAll) {
49 			buffer->RetrieveAll();
50 			return true;
51 		}
52 	}
53 
54 	return ret;
55 }
56 
ParseRequestLine(const char * begin,const char * end)57 bool RtspRequest::ParseRequestLine(const char* begin, const char* end)
58 {
59 	string message(begin, end);
60 	char method[64] = {0};
61 	char url[512] = {0};
62 	char version[64] = {0};
63 
64 	if(sscanf(message.c_str(), "%s %s %s", method, url, version) != 3) {
65 		return true;
66 	}
67 
68 	string method_str(method);
69 	if(method_str == "OPTIONS") {
70 		method_ = OPTIONS;
71 	}
72 	else if(method_str == "DESCRIBE") {
73 		method_ = DESCRIBE;
74 	}
75 	else if(method_str == "SETUP") {
76 		method_ = SETUP;
77 	}
78 	else if(method_str == "PLAY") {
79 		method_ = PLAY;
80 	}
81 	else if(method_str == "TEARDOWN") {
82 		method_ = TEARDOWN;
83 	}
84 	else if(method_str == "GET_PARAMETER") {
85 		method_ = GET_PARAMETER;
86 	}
87 	else {
88 		method_ = NONE;
89 		return false;
90 	}
91 
92 	if(strncmp(url, "rtsp://", 7) != 0) {
93 		return false;
94 	}
95 
96 	// parse url
97 	uint16_t port = 0;
98 	char ip[64] = {0};
99 	char suffix[256] = {0};
100 
101 	if(sscanf(url+7, "%[^:]:%hu/%s", ip, &port, suffix) == 3) {
102 
103 	}
104 	else if(sscanf(url+7, "%[^/]/%s", ip, suffix) == 2) {
105 		port = 554;
106 	}
107 	else {
108 		return false;
109 	}
110 
111 	request_line_param_.emplace("url", make_pair(string(url), 0));
112 	request_line_param_.emplace("url_ip", make_pair(string(ip), 0));
113 	request_line_param_.emplace("url_port", make_pair("", (uint32_t)port));
114 	request_line_param_.emplace("url_suffix", make_pair(string(suffix), 0));
115 	request_line_param_.emplace("version", make_pair(string(version), 0));
116 	request_line_param_.emplace("method", make_pair(move(method_str), 0));
117 
118 	state_ = kParseHeadersLine;
119 	return true;
120 }
121 
ParseHeadersLine(const char * begin,const char * end)122 bool RtspRequest::ParseHeadersLine(const char* begin, const char* end)
123 {
124 	string message(begin, end);
125 	if(!ParseCSeq(message)) {
126 		if (header_line_param_.find("cseq") == header_line_param_.end()) {
127 			return false;
128 		}
129 	}
130 
131 	if (method_ == DESCRIBE || method_ == SETUP || method_ == PLAY) {
132 		ParseAuthorization(message);
133 	}
134 
135 	if(method_ == OPTIONS) {
136 		state_ = kGotAll;
137 		return true;
138 	}
139 
140 	if(method_ == DESCRIBE) {
141 		if(ParseAccept(message)) {
142 			state_ = kGotAll;
143 		}
144 		return true;
145 	}
146 
147 	if(method_ == SETUP) {
148 		if(ParseTransport(message)) {
149 			ParseMediaChannel(message);
150 			state_ = kGotAll;
151 		}
152 
153 		return true;
154 	}
155 
156 	if(method_ == PLAY) {
157 		if(ParseSessionId(message)) {
158 			state_ = kGotAll;
159 		}
160 		return true;
161 	}
162 
163 	if(method_ == TEARDOWN) {
164 		state_ = kGotAll;
165 		return true;
166 	}
167 
168 	if(method_ == GET_PARAMETER) {
169 		state_ = kGotAll;
170 		return true;
171 	}
172 
173 	return true;
174 }
175 
ParseCSeq(std::string & message)176 bool RtspRequest::ParseCSeq(std::string& message)
177 {
178 	std::size_t pos = message.find("CSeq");
179 	if (pos != std::string::npos) {
180 		uint32_t cseq = 0;
181 		sscanf(message.c_str()+pos, "%*[^:]: %u", &cseq);
182 		header_line_param_.emplace("cseq", make_pair("", cseq));
183 		return true;
184 	}
185 
186 	return false;
187 }
188 
ParseAccept(std::string & message)189 bool RtspRequest::ParseAccept(std::string& message)
190 {
191 	if ((message.rfind("Accept")==std::string::npos)
192 		|| (message.rfind("sdp")==std::string::npos)) {
193 		return false;
194 	}
195 
196 	return true;
197 }
198 
ParseTransport(std::string & message)199 bool RtspRequest::ParseTransport(std::string& message)
200 {
201 	std::size_t pos = message.find("Transport");
202 	if(pos != std::string::npos) {
203 		if((pos=message.find("RTP/AVP/TCP")) != std::string::npos) {
204 			transport_ = RTP_OVER_TCP;
205 			uint16_t rtpChannel = 0, rtcpChannel = 0;
206 			if (sscanf(message.c_str() + pos, "%*[^;];%*[^;];%*[^=]=%hu-%hu", &rtpChannel, &rtcpChannel) != 2) {
207 				return false;
208 			}
209 			header_line_param_.emplace("rtp_channel", make_pair("", rtpChannel));
210 			header_line_param_.emplace("rtcp_channel", make_pair("", rtcpChannel));
211 		}
212 		else if((pos=message.find("RTP/AVP")) != std::string::npos) {
213 			uint16_t rtp_port = 0, rtcpPort = 0;
214 			if(((message.find("unicast", pos)) != std::string::npos)) {
215 				transport_ = RTP_OVER_UDP;
216 				if(sscanf(message.c_str()+pos, "%*[^;];%*[^;];%*[^=]=%hu-%hu",
217 						&rtp_port, &rtcpPort) != 2)
218 				{
219 					return false;
220 				}
221 
222 			}
223 			else if((message.find("multicast", pos)) != std::string::npos) {
224 				transport_ = RTP_OVER_MULTICAST;
225 			}
226 			else {
227 				return false;
228 			}
229 
230 			header_line_param_.emplace("rtp_port", make_pair("", rtp_port));
231 			header_line_param_.emplace("rtcp_port", make_pair("", rtcpPort));
232 		}
233 		else {
234 			return false;
235 		}
236 
237 		return true;
238 	}
239 
240 	return false;
241 }
242 
ParseSessionId(std::string & message)243 bool RtspRequest::ParseSessionId(std::string& message)
244 {
245 	std::size_t pos = message.find("Session");
246 	if (pos != std::string::npos) {
247 		uint32_t session_id = 0;
248 		if (sscanf(message.c_str() + pos, "%*[^:]: %u", &session_id) != 1) {
249 			return false;
250 		}
251 		return true;
252 	}
253 
254 	return false;
255 }
256 
ParseMediaChannel(std::string & message)257 bool RtspRequest::ParseMediaChannel(std::string& message)
258 {
259 	channel_id_ = channel_0;
260 
261 	auto iter = request_line_param_.find("url");
262 	if(iter != request_line_param_.end()) {
263 		std::size_t pos = iter->second.first.find("track1");
264 		if (pos != std::string::npos) {
265 			channel_id_ = channel_1;
266 		}
267 	}
268 
269 	return true;
270 }
271 
ParseAuthorization(std::string & message)272 bool RtspRequest::ParseAuthorization(std::string& message)
273 {
274 	std::size_t pos = message.find("Authorization");
275 	if (pos != std::string::npos) {
276 		if ((pos = message.find("response=")) != std::string::npos) {
277 			auth_response_ = message.substr(pos + 10, 32);
278 			if (auth_response_.size() == 32) {
279 				return true;
280 			}
281 		}
282 	}
283 
284 	auth_response_.clear();
285 	return false;
286 }
287 
GetCSeq() const288 uint32_t RtspRequest::GetCSeq() const
289 {
290 	uint32_t cseq = 0;
291 	auto iter = header_line_param_.find("cseq");
292 	if(iter != header_line_param_.end()) {
293 		cseq = iter->second.second;
294 	}
295 
296 	return cseq;
297 }
298 
GetIp() const299 std::string RtspRequest::GetIp() const
300 {
301 	auto iter = request_line_param_.find("url_ip");
302 	if(iter != request_line_param_.end()) {
303 		return iter->second.first;
304 	}
305 
306 	return "";
307 }
308 
GetRtspUrl() const309 std::string RtspRequest::GetRtspUrl() const
310 {
311 	auto iter = request_line_param_.find("url");
312 	if(iter != request_line_param_.end()) {
313 		return iter->second.first;
314 	}
315 
316 	return "";
317 }
318 
GetRtspUrlSuffix() const319 std::string RtspRequest::GetRtspUrlSuffix() const
320 {
321 	auto iter = request_line_param_.find("url_suffix");
322 	if(iter != request_line_param_.end()) {
323 		return iter->second.first;
324 	}
325 
326 	return "";
327 }
328 
GetRtspUrlSession() const329 std::string RtspRequest::GetRtspUrlSession() const
330 {
331 	auto iter = request_line_param_.find("url_suffix");
332 	if(iter != request_line_param_.end()) {
333     int found = iter->second.first.find('?');
334     if (found != std::string::npos)
335       return iter->second.first.substr(0, found);
336 		return iter->second.first;
337 	}
338 
339 	return "";
340 }
341 
GetRtspUrlQueryString() const342 std::string RtspRequest::GetRtspUrlQueryString() const
343 {
344 	auto iter = request_line_param_.find("url_suffix");
345 	if(iter != request_line_param_.end()) {
346     int found = iter->second.first.find('?');
347     if (found != std::string::npos)
348       return iter->second.first.substr(found+1, std::string::npos);
349 	}
350 
351 	return "";
352 }
353 
GetAuthResponse() const354 std::string RtspRequest::GetAuthResponse() const
355 {
356 	return auth_response_;
357 }
358 
GetRtpChannel() const359 uint8_t RtspRequest::GetRtpChannel() const
360 {
361 	auto iter = header_line_param_.find("rtp_channel");
362 	if(iter != header_line_param_.end()) {
363 		return iter->second.second;
364 	}
365 
366 	return 0;
367 }
368 
GetRtcpChannel() const369 uint8_t RtspRequest::GetRtcpChannel() const
370 {
371 	auto iter = header_line_param_.find("rtcp_channel");
372 	if(iter != header_line_param_.end()) {
373 		return iter->second.second;
374 	}
375 
376 	return 0;
377 }
378 
GetRtpPort() const379 uint16_t RtspRequest::GetRtpPort() const
380 {
381 	auto iter = header_line_param_.find("rtp_port");
382 	if(iter != header_line_param_.end()) {
383 		return iter->second.second;
384 	}
385 
386 	return 0;
387 }
388 
GetRtcpPort() const389 uint16_t RtspRequest::GetRtcpPort() const
390 {
391 	auto iter = header_line_param_.find("rtcp_port");
392 	if(iter != header_line_param_.end()) {
393 		return iter->second.second;
394 	}
395 
396 	return 0;
397 }
398 
BuildOptionRes(const char * buf,int buf_size)399 int RtspRequest::BuildOptionRes(const char* buf, int buf_size)
400 {
401 	memset((void*)buf, 0, buf_size);
402 	snprintf((char*)buf, buf_size,
403 			"RTSP/1.0 200 OK\r\n"
404 			"CSeq: %u\r\n"
405 			"Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY\r\n"
406 			"\r\n",
407 			this->GetCSeq());
408 
409 	return (int)strlen(buf);
410 }
411 
BuildDescribeRes(const char * buf,int buf_size,const char * sdp)412 int RtspRequest::BuildDescribeRes(const char* buf, int buf_size, const char* sdp)
413 {
414 	memset((void*)buf, 0, buf_size);
415 	snprintf((char*)buf, buf_size,
416 			"RTSP/1.0 200 OK\r\n"
417 			"CSeq: %u\r\n"
418 			"Content-Length: %d\r\n"
419 			"Content-Type: application/sdp\r\n"
420 			"\r\n"
421 			"%s",
422 			this->GetCSeq(),
423 			(int)strlen(sdp),
424 			sdp);
425 
426 	return (int)strlen(buf);
427 }
428 
BuildSetupMulticastRes(const char * buf,int buf_size,const char * multicast_ip,uint16_t port,uint32_t session_id)429 int RtspRequest::BuildSetupMulticastRes(const char* buf, int buf_size, const char* multicast_ip, uint16_t port, uint32_t session_id)
430 {
431 	memset((void*)buf, 0, buf_size);
432 	snprintf((char*)buf, buf_size,
433 			"RTSP/1.0 200 OK\r\n"
434 			"CSeq: %u\r\n"
435 			"Transport: RTP/AVP;multicast;destination=%s;source=%s;port=%u-0;ttl=255\r\n"
436 			"Session: %u\r\n"
437 			"\r\n",
438 			this->GetCSeq(),
439 			multicast_ip,
440 			this->GetIp().c_str(),
441 			port,
442 			session_id);
443 
444 	return (int)strlen(buf);
445 }
446 
BuildSetupUdpRes(const char * buf,int buf_size,uint16_t rtp_chn,uint16_t rtcp_chn,uint32_t session_id)447 int RtspRequest::BuildSetupUdpRes(const char* buf, int buf_size, uint16_t rtp_chn, uint16_t rtcp_chn, uint32_t session_id)
448 {
449 	memset((void*)buf, 0, buf_size);
450 	snprintf((char*)buf, buf_size,
451 			"RTSP/1.0 200 OK\r\n"
452 			"CSeq: %u\r\n"
453 			"Transport: RTP/AVP;unicast;client_port=%hu-%hu;server_port=%hu-%hu\r\n"
454 			"Session: %u\r\n"
455 			"\r\n",
456 			this->GetCSeq(),
457 			this->GetRtpPort(),
458 			this->GetRtcpPort(),
459 			rtp_chn,
460 			rtcp_chn,
461 			session_id);
462 
463 	return (int)strlen(buf);
464 }
465 
BuildSetupTcpRes(const char * buf,int buf_size,uint16_t rtp_chn,uint16_t rtcp_chn,uint32_t session_id)466 int RtspRequest::BuildSetupTcpRes(const char* buf, int buf_size, uint16_t rtp_chn, uint16_t rtcp_chn, uint32_t session_id)
467 {
468 	memset((void*)buf, 0, buf_size);
469 	snprintf((char*)buf, buf_size,
470 			"RTSP/1.0 200 OK\r\n"
471 			"CSeq: %u\r\n"
472 			"Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n"
473 			"Session: %u\r\n"
474 			"\r\n",
475 			this->GetCSeq(),
476 			rtp_chn, rtcp_chn,
477 			session_id);
478 
479 	return (int)strlen(buf);
480 }
481 
BuildPlayRes(const char * buf,int buf_size,const char * rtpInfo,uint32_t session_id)482 int RtspRequest::BuildPlayRes(const char* buf, int buf_size, const char* rtpInfo, uint32_t session_id)
483 {
484 	memset((void*)buf, 0, buf_size);
485 	snprintf((char*)buf, buf_size,
486 			"RTSP/1.0 200 OK\r\n"
487 			"CSeq: %d\r\n"
488 			"Range: npt=0.000-\r\n"
489 			"Session: %u; timeout=60\r\n",
490 			this->GetCSeq(),
491 			session_id);
492 
493 	if (rtpInfo != nullptr) {
494 		snprintf((char*)buf + strlen(buf), buf_size - strlen(buf), "%s\r\n", rtpInfo);
495 	}
496 
497 	snprintf((char*)buf + strlen(buf), buf_size - strlen(buf), "\r\n");
498 	return (int)strlen(buf);
499 }
500 
BuildTeardownRes(const char * buf,int buf_size,uint32_t session_id)501 int RtspRequest::BuildTeardownRes(const char* buf, int buf_size, uint32_t session_id)
502 {
503 	memset((void*)buf, 0, buf_size);
504 	snprintf((char*)buf, buf_size,
505 			"RTSP/1.0 200 OK\r\n"
506 			"CSeq: %d\r\n"
507 			"Session: %u\r\n"
508 			"\r\n",
509 			this->GetCSeq(),
510 			session_id);
511 
512 	return (int)strlen(buf);
513 }
514 
BuildGetParamterRes(const char * buf,int buf_size,uint32_t session_id)515 int RtspRequest::BuildGetParamterRes(const char* buf, int buf_size, uint32_t session_id)
516 {
517 	memset((void*)buf, 0, buf_size);
518 	snprintf((char*)buf, buf_size,
519 			"RTSP/1.0 200 OK\r\n"
520 			"CSeq: %d\r\n"
521 			"Session: %u\r\n"
522 			"\r\n",
523 			this->GetCSeq(),
524 			session_id);
525 
526 	return (int)strlen(buf);
527 }
528 
BuildNotFoundRes(const char * buf,int buf_size)529 int RtspRequest::BuildNotFoundRes(const char* buf, int buf_size)
530 {
531 	memset((void*)buf, 0, buf_size);
532 	snprintf((char*)buf, buf_size,
533 			"RTSP/1.0 404 Stream Not Found\r\n"
534 			"CSeq: %u\r\n"
535 			"\r\n",
536 			this->GetCSeq());
537 
538 	return (int)strlen(buf);
539 }
540 
BuildServerErrorRes(const char * buf,int buf_size)541 int RtspRequest::BuildServerErrorRes(const char* buf, int buf_size)
542 {
543 	memset((void*)buf, 0, buf_size);
544 	snprintf((char*)buf, buf_size,
545 			"RTSP/1.0 500 Internal Server Error\r\n"
546 			"CSeq: %u\r\n"
547 			"\r\n",
548 			this->GetCSeq());
549 
550 	return (int)strlen(buf);
551 }
552 
BuildUnsupportedRes(const char * buf,int buf_size)553 int RtspRequest::BuildUnsupportedRes(const char* buf, int buf_size)
554 {
555 	memset((void*)buf, 0, buf_size);
556 	snprintf((char*)buf, buf_size,
557 			"RTSP/1.0 461 Unsupported transport\r\n"
558 			"CSeq: %d\r\n"
559 			"\r\n",
560 			this->GetCSeq());
561 
562 	return (int)strlen(buf);
563 }
564 
BuildUnauthorizedRes(const char * buf,size_t buf_size)565 size_t RtspRequest::BuildUnauthorizedRes(const char *buf, size_t buf_size)
566 {
567 	snprintf((char*)buf, buf_size,
568 			"RTSP/1.0 401 Unauthorized\r\n"
569 			"CSeq: %d\r\n"
570 			"\r\n",
571 			this->GetCSeq()
572 			);
573 
574 	return strlen(buf);
575 }
576 
BuildUnauthorizedRes(const char * buf,size_t buf_size,const char * realm,const char * nonce)577 size_t RtspRequest::BuildUnauthorizedRes(const char* buf, size_t buf_size, const char* realm, const char* nonce)
578 {
579 	memset((void*)buf, 0, buf_size);
580 	snprintf((char*)buf, buf_size,
581 			"RTSP/1.0 401 Unauthorized\r\n"
582 			"CSeq: %d\r\n"
583 			"WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n"
584 			"\r\n",
585 			this->GetCSeq(),
586 			realm,
587 			nonce);
588 
589 	return strlen(buf);
590 }
591 
ParseResponse(xop::BufferReader * buffer)592 bool RtspResponse::ParseResponse(xop::BufferReader *buffer)
593 {
594 	if (strstr(buffer->Peek(), "\r\n\r\n") != NULL) {
595 		if (strstr(buffer->Peek(), "OK") == NULL) {
596 			return false;
597 		}
598 
599 		char* ptr = strstr(buffer->Peek(), "Session");
600 		if (ptr != NULL) {
601 			char session_id[50] = {0};
602 			if (sscanf(ptr, "%*[^:]: %s", session_id) == 1)
603 				session_ = session_id;
604 		}
605 
606 		cseq_++;
607 		buffer->RetrieveUntil("\r\n\r\n");
608 	}
609 
610 	return true;
611 }
612 
BuildOptionReq(const char * buf,int buf_size)613 int RtspResponse::BuildOptionReq(const char* buf, int buf_size)
614 {
615 	memset((void*)buf, 0, buf_size);
616 	snprintf((char*)buf, buf_size,
617 			"OPTIONS %s RTSP/1.0\r\n"
618 			"CSeq: %u\r\n"
619 			"User-Agent: %s\r\n"
620 			"\r\n",
621 			rtsp_url_.c_str(),
622 			this->GetCSeq() + 1,
623 			user_agent_.c_str());
624 
625 	method_ = OPTIONS;
626 	return (int)strlen(buf);
627 }
628 
BuildAnnounceReq(const char * buf,int buf_size,const char * sdp)629 int RtspResponse::BuildAnnounceReq(const char* buf, int buf_size, const char *sdp)
630 {
631 	memset((void*)buf, 0, buf_size);
632 	snprintf((char*)buf, buf_size,
633 			"ANNOUNCE %s RTSP/1.0\r\n"
634 			"Content-Type: application/sdp\r\n"
635 			"CSeq: %u\r\n"
636 			"User-Agent: %s\r\n"
637 			"Session: %s\r\n"
638 			"Content-Length: %d\r\n"
639 			"\r\n"
640 			"%s",
641 			rtsp_url_.c_str(),
642 			this->GetCSeq() + 1,
643 			user_agent_.c_str(),
644 			this->GetSession().c_str(),
645 			(int)strlen(sdp),
646 			sdp);
647 
648 	method_ = ANNOUNCE;
649 	return (int)strlen(buf);
650 }
651 
BuildDescribeReq(const char * buf,int buf_size)652 int RtspResponse::BuildDescribeReq(const char* buf, int buf_size)
653 {
654 	memset((void*)buf, 0, buf_size);
655 	snprintf((char*)buf, buf_size,
656 			"DESCRIBE %s RTSP/1.0\r\n"
657 			"CSeq: %u\r\n"
658 			"Accept: application/sdp\r\n"
659 			"User-Agent: %s\r\n"
660 			"\r\n",
661 			rtsp_url_.c_str(),
662 			this->GetCSeq() + 1,
663 			user_agent_.c_str());
664 
665 	method_ = DESCRIBE;
666 	return (int)strlen(buf);
667 }
668 
BuildSetupTcpReq(const char * buf,int buf_size,int trackId)669 int RtspResponse::BuildSetupTcpReq(const char* buf, int buf_size, int trackId)
670 {
671 	int interleaved[2] = { 0, 1 };
672 	if (trackId == 1) {
673 		interleaved[0] = 2;
674 		interleaved[1] = 3;
675 	}
676 
677 	memset((void*)buf, 0, buf_size);
678 	snprintf((char*)buf, buf_size,
679 			"SETUP %s/track%d RTSP/1.0\r\n"
680 			"Transport: RTP/AVP/TCP;unicast;mode=record;interleaved=%d-%d\r\n"
681 			"CSeq: %u\r\n"
682 			"User-Agent: %s\r\n"
683 			"Session: %s\r\n"
684 			"\r\n",
685 			rtsp_url_.c_str(),
686 			trackId,
687 			interleaved[0],
688 			interleaved[1],
689 			this->GetCSeq() + 1,
690 			user_agent_.c_str(),
691 			this->GetSession().c_str());
692 
693 	method_ = SETUP;
694 	return (int)strlen(buf);
695 }
696 
BuildRecordReq(const char * buf,int buf_size)697 int RtspResponse::BuildRecordReq(const char* buf, int buf_size)
698 {
699 	memset((void*)buf, 0, buf_size);
700 	snprintf((char*)buf, buf_size,
701 			"RECORD %s RTSP/1.0\r\n"
702 			"Range: npt=0.000-\r\n"
703 			"CSeq: %u\r\n"
704 			"User-Agent: %s\r\n"
705 			"Session: %s\r\n"
706 			"\r\n",
707 			rtsp_url_.c_str(),
708 			this->GetCSeq() + 1,
709 			user_agent_.c_str(),
710 			this->GetSession().c_str());
711 
712 	method_ = RECORD;
713 	return (int)strlen(buf);
714 }
715