You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.5KB

  1. // RFC-2326 14.6 Recording (p71)
  2. /*
  3. C->M:
  4. SETUP rtsp://server.example.com/meeting/videotrack RTSP/1.0
  5. CSeq: 92
  6. Session: 50887676
  7. Transport: RTP/AVP;multicast;destination=224.0.1.12;port=61010-61011;mode=record;ttl=127
  8. M->C:
  9. RTSP/1.0 200 OK
  10. CSeq: 92
  11. Transport: RTP/AVP;multicast;destination=224.0.1.12;port=61010-61011;mode=record;ttl=127
  12. C->M:
  13. RECORD rtsp://server.example.com/meeting RTSP/1.0
  14. CSeq: 93
  15. Session: 50887676
  16. Range: clock=19961110T1925-19961110T2015
  17. M->C:
  18. RTSP/1.0 200 OK
  19. CSeq: 93
  20. */
  21. #include "rtsp-client.h"
  22. #include "rtsp-client-internal.h"
  23. #include "rtsp-header-range.h"
  24. #include "rtsp-header-rtp-info.h"
  25. #include <assert.h>
  26. static const char* sc_format =
  27. "RECORD %s RTSP/1.0\r\n"
  28. "CSeq: %u\r\n"
  29. "Session: %s\r\n"
  30. "%s" // Range
  31. "%s" // Scale
  32. "%s" // Authorization: Digest xxx
  33. "User-Agent: %s\r\n"
  34. "\r\n";
  35. static int rtsp_client_media_record(struct rtsp_client_t *rtsp, int i)
  36. {
  37. int r;
  38. assert(0 == rtsp->aggregate);
  39. assert(i < rtsp->media_count);
  40. assert(RTSP_RECORD == rtsp->state);
  41. if (i >= rtsp->media_count) return -1;
  42. assert(rtsp->media[i].uri[0] && rtsp->session[i].session[0]);
  43. r = rtsp_client_authenrization(rtsp, "RECORD", rtsp->media[i].uri, NULL, 0, rtsp->authenrization, sizeof(rtsp->authenrization));
  44. r = snprintf(rtsp->req, sizeof(rtsp->req), sc_format, rtsp->media[i].uri, rtsp->cseq++, rtsp->session[i].session, rtsp->range, rtsp->scale, rtsp->authenrization, USER_AGENT);
  45. return (r > 0 && r < sizeof(rtsp->req) && r == rtsp->handler.send(rtsp->param, rtsp->media[i].uri, rtsp->req, r)) ? 0 : -1;
  46. }
  47. int rtsp_client_record(struct rtsp_client_t *rtsp, const uint64_t *npt, const float *scale)
  48. {
  49. int r;
  50. assert(RTSP_SETUP == rtsp->state || RTSP_RECORD == rtsp->state || RTSP_PAUSE == rtsp->state);
  51. rtsp->state = RTSP_RECORD;
  52. rtsp->progress = 0;
  53. rtsp->scale[0] = rtsp->range[0] = '\0';
  54. if ( (scale && snprintf(rtsp->scale, sizeof(rtsp->scale), "Scale: %.2f\r\n", *scale) >= sizeof(rtsp->scale))
  55. || (npt && snprintf(rtsp->range, sizeof(rtsp->range), "Range: npt=%" PRIu64 ".%" PRIu64 "-\r\n", *npt / 1000, *npt % 1000) >= sizeof(rtsp->range)))
  56. return -1;
  57. if (rtsp->aggregate)
  58. {
  59. assert(rtsp->media_count > 0);
  60. assert(rtsp->aggregate_uri[0]);
  61. r = rtsp_client_authenrization(rtsp, "RECORD", rtsp->aggregate_uri, NULL, 0, rtsp->authenrization, sizeof(rtsp->authenrization));
  62. r = snprintf(rtsp->req, sizeof(rtsp->req), sc_format, rtsp->aggregate_uri, rtsp->cseq++, rtsp->session[0].session, rtsp->range, rtsp->scale, rtsp->authenrization, USER_AGENT);
  63. return (r > 0 && r < sizeof(rtsp->req) && r == rtsp->handler.send(rtsp->param, rtsp->aggregate_uri, rtsp->req, r)) ? 0 : -1;
  64. }
  65. else
  66. {
  67. return rtsp_client_media_record(rtsp, rtsp->progress);
  68. }
  69. }
  70. static int rtsp_client_media_record_onreply(struct rtsp_client_t* rtsp, void* parser)
  71. {
  72. int i, r;
  73. uint64_t npt0 = (uint64_t)(-1);
  74. uint64_t npt1 = (uint64_t)(-1);
  75. double scale = 0.0f;
  76. const char *prange, *pscale, *prtpinfo, *pnext;
  77. struct rtsp_header_range_t range;
  78. struct rtsp_header_rtp_info_t rtpinfo[N_MEDIA];
  79. struct rtsp_rtp_info_t rtpInfo[N_MEDIA];
  80. if (200 != http_get_status_code(parser))
  81. return -1;
  82. prange = http_get_header_by_name(parser, "Range");
  83. pscale = http_get_header_by_name(parser, "Scale");
  84. prtpinfo = http_get_header_by_name(parser, "RTP-Info");
  85. if (pscale)
  86. {
  87. scale = atof(pscale);
  88. }
  89. if (prange && 0 == rtsp_header_range(prange, &range))
  90. {
  91. assert(range.from_value == RTSP_RANGE_TIME_NORMAL);
  92. assert(range.to_value != RTSP_RANGE_TIME_NOW);
  93. npt0 = range.from;
  94. npt1 = range.to_value == RTSP_RANGE_TIME_NOVALUE ? -1 : range.to;
  95. }
  96. memset(rtpInfo, 0, sizeof(rtpInfo));
  97. for (i = 0; prtpinfo && i < sizeof(rtpInfo) / sizeof(rtpInfo[0]); i++)
  98. {
  99. prtpinfo += strspn(prtpinfo, " "); // skip space
  100. pnext = strchr(prtpinfo, ',');
  101. if (0 == rtsp_header_rtp_info(prtpinfo, &rtpinfo[i]))
  102. {
  103. rtpInfo[i].uri = rtpinfo[i].url;
  104. rtpInfo[i].seq = (unsigned int)rtpinfo[i].seq;
  105. rtpInfo[i].time = (unsigned int)rtpinfo[i].rtptime;
  106. }
  107. prtpinfo = pnext ? pnext + 1 : pnext;
  108. }
  109. r = rtsp->handler.onrecord(rtsp->param, rtsp->progress, (uint64_t)(-1) == npt0 ? NULL : &npt0, (uint64_t)(-1) == npt1 ? NULL : &npt1, pscale ? &scale : NULL, rtpInfo, i);
  110. if (0 == r && 0 == rtsp->aggregate && rtsp->media_count > ++rtsp->progress)
  111. {
  112. return rtsp_client_media_record(rtsp, rtsp->progress);
  113. }
  114. return r;
  115. }
  116. // aggregate control reply
  117. static int rtsp_client_aggregate_record_onreply(struct rtsp_client_t* rtsp, void* parser)
  118. {
  119. int code;
  120. assert(RTSP_RECORD == rtsp->state);
  121. assert(0 == rtsp->progress);
  122. assert(rtsp->aggregate);
  123. code = http_get_status_code(parser);
  124. if (459 == code) // 459 Aggregate operation not allowed (p26)
  125. {
  126. rtsp->aggregate = 0;
  127. return rtsp_client_media_record(rtsp, rtsp->progress);
  128. }
  129. else if (200 == code)
  130. {
  131. return rtsp_client_media_record_onreply(rtsp, parser);
  132. }
  133. else
  134. {
  135. return -1;
  136. }
  137. }
  138. int rtsp_client_record_onreply(struct rtsp_client_t* rtsp, void* parser)
  139. {
  140. assert(RTSP_RECORD == rtsp->state);
  141. assert(rtsp->progress < rtsp->media_count);
  142. if (rtsp->aggregate)
  143. return rtsp_client_aggregate_record_onreply(rtsp, parser);
  144. else
  145. return rtsp_client_media_record_onreply(rtsp, parser);
  146. }