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.

189 lines
3.8KB

  1. #include "pcm-file-source.h"
  2. #include "cstringext.h"
  3. #include "base64.h"
  4. #include "rtp-profile.h"
  5. #include "rtp-payload.h"
  6. #include <assert.h>
  7. extern "C" uint32_t rtp_ssrc(void);
  8. PCMFileSource::PCMFileSource(const char *file)
  9. {
  10. m_fp = fopen(file, "rb");
  11. m_speed = 1.0;
  12. m_status = 0;
  13. m_rtp_clock = 0;
  14. m_rtcp_clock = 0;
  15. uint32_t ssrc = rtp_ssrc();
  16. static struct rtp_payload_t s_rtpfunc = {
  17. PCMFileSource::RTPAlloc,
  18. PCMFileSource::RTPFree,
  19. PCMFileSource::RTPPacket,
  20. };
  21. m_rtppacker = rtp_payload_encode_create(RTP_PAYLOAD_PCMA, "PCMA", (uint16_t)ssrc, ssrc, &s_rtpfunc, this);
  22. struct rtp_event_t event;
  23. event.on_rtcp = OnRTCPEvent;
  24. m_rtp = rtp_create(&event, this, ssrc, ssrc, 8000, 8000, 1);
  25. rtp_set_info(m_rtp, "RTSPServer", "test.pcm");
  26. }
  27. PCMFileSource::~PCMFileSource()
  28. {
  29. if (m_fp)
  30. fclose(m_fp);
  31. m_fp = NULL;
  32. if (m_rtp)
  33. rtp_destroy(m_rtp);
  34. if (m_rtppacker)
  35. rtp_payload_encode_destroy(m_rtppacker);
  36. }
  37. int PCMFileSource::SetTransport(const char* /*track*/, std::shared_ptr<IRTPTransport> transport)
  38. {
  39. m_transport = transport;
  40. return 0;
  41. }
  42. int PCMFileSource::Play()
  43. {
  44. if (!m_fp)
  45. return -1;
  46. m_status = 1;
  47. static uint32_t timestamp = 0;
  48. time64_t clock = time64_now();
  49. if (0 == m_rtp_clock)
  50. m_rtp_clock = clock;
  51. if (m_rtp_clock + 20 < clock)
  52. {
  53. uint8_t ptr[20 * 8]; // 20ms
  54. if (sizeof(ptr) == fread(ptr, 1, sizeof(ptr), m_fp))
  55. {
  56. rtp_payload_encode_input(m_rtppacker, ptr, sizeof(ptr), timestamp * 8 /*kHz*/);
  57. m_rtp_clock += 20;
  58. timestamp += 20;
  59. SendRTCP();
  60. return 1;
  61. }
  62. }
  63. return 0;
  64. }
  65. int PCMFileSource::Pause()
  66. {
  67. m_status = 2;
  68. m_rtp_clock = 0;
  69. return 0;
  70. }
  71. int PCMFileSource::Seek(int64_t pos)
  72. {
  73. if (!m_fp) return -1;
  74. m_pos = pos;
  75. m_rtp_clock = 0;
  76. return fseek(m_fp, (long)pos * 8, SEEK_CUR);
  77. }
  78. int PCMFileSource::SetSpeed(double speed)
  79. {
  80. m_speed = speed;
  81. return 0;
  82. }
  83. int PCMFileSource::GetDuration(int64_t& duration) const
  84. {
  85. if (!m_fp) return 0;
  86. long off = ftell(m_fp);
  87. fseek(m_fp, 0, SEEK_END);
  88. long total = ftell(m_fp);
  89. duration = total / 8; // 8000kHz, 8bits
  90. fseek(m_fp, off, SEEK_SET);
  91. return 0;
  92. }
  93. int PCMFileSource::GetSDPMedia(std::string& sdp) const
  94. {
  95. static const char* pattern =
  96. "m=audio 0 RTP/AVP %d\n";
  97. char m[64];
  98. snprintf(m, sizeof(m), pattern, RTP_PAYLOAD_PCMA);
  99. sdp = m;
  100. return 0;
  101. }
  102. int PCMFileSource::GetRTPInfo(const char* uri, char *rtpinfo, size_t bytes) const
  103. {
  104. uint16_t seq;
  105. uint32_t timestamp;
  106. rtp_payload_encode_getinfo(m_rtppacker, &seq, &timestamp);
  107. // url=rtsp://video.example.com/twister/video;seq=12312232;rtptime=78712811
  108. snprintf(rtpinfo, bytes, "url=%s;seq=%hu;rtptime=%u", uri, seq, timestamp);
  109. return 0;
  110. }
  111. void PCMFileSource::OnRTCPEvent(const struct rtcp_msg_t* msg)
  112. {
  113. msg;
  114. }
  115. void PCMFileSource::OnRTCPEvent(void* param, const struct rtcp_msg_t* msg)
  116. {
  117. PCMFileSource *self = (PCMFileSource *)param;
  118. self->OnRTCPEvent(msg);
  119. }
  120. int PCMFileSource::SendRTCP()
  121. {
  122. // make sure have sent RTP packet
  123. time64_t clock = time64_now();
  124. int interval = rtp_rtcp_interval(m_rtp);
  125. if (0 == m_rtcp_clock || m_rtcp_clock + interval < clock)
  126. {
  127. char rtcp[1024] = { 0 };
  128. size_t n = rtp_rtcp_report(m_rtp, rtcp, sizeof(rtcp));
  129. // send RTCP packet
  130. m_transport->Send(true, rtcp, n);
  131. m_rtcp_clock = clock;
  132. }
  133. return 0;
  134. }
  135. void* PCMFileSource::RTPAlloc(void* param, int bytes)
  136. {
  137. PCMFileSource *self = (PCMFileSource*)param;
  138. assert(bytes <= sizeof(self->m_packet));
  139. return self->m_packet;
  140. }
  141. void PCMFileSource::RTPFree(void* param, void *packet)
  142. {
  143. PCMFileSource *self = (PCMFileSource*)param;
  144. assert(self->m_packet == packet);
  145. }
  146. int PCMFileSource::RTPPacket(void* param, const void *packet, int bytes, uint32_t /*timestamp*/, int /*flags*/)
  147. {
  148. PCMFileSource *self = (PCMFileSource*)param;
  149. assert(self->m_packet == packet);
  150. int r = self->m_transport->Send(false, packet, bytes);
  151. if (r != bytes)
  152. return -1;
  153. return rtp_onsend(self->m_rtp, packet, bytes/*, time*/);
  154. }