track.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /**
  2. * Copyright (c) 2020 Paul-Louis Ageneau
  3. *
  4. * This Source Code Form is subject to the terms of the Mozilla Public
  5. * License, v. 2.0. If a copy of the MPL was not distributed with this
  6. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  7. */
  8. #include "track.hpp"
  9. #include "internals.hpp"
  10. #include "logcounter.hpp"
  11. #include "peerconnection.hpp"
  12. #include "rtp.hpp"
  13. namespace rtc::impl {
  14. static LogCounter COUNTER_MEDIA_BAD_DIRECTION(plog::warning,
  15. "Number of media packets sent in invalid directions");
  16. static LogCounter COUNTER_QUEUE_FULL(plog::warning,
  17. "Number of media packets dropped due to a full queue");
  18. Track::Track(weak_ptr<PeerConnection> pc, Description::Media description)
  19. : mPeerConnection(pc), mMediaDescription(std::move(description)),
  20. mRecvQueue(RECV_QUEUE_LIMIT, [](const message_ptr &m) { return m->size(); }) {
  21. // Discard messages by default if track is send only
  22. if (mMediaDescription.direction() == Description::Direction::SendOnly)
  23. messageCallback = [](message_variant) {};
  24. }
  25. Track::~Track() {
  26. PLOG_VERBOSE << "Destroying Track";
  27. try {
  28. close();
  29. } catch (const std::exception &e) {
  30. PLOG_ERROR << e.what();
  31. }
  32. }
  33. string Track::mid() const {
  34. std::shared_lock lock(mMutex);
  35. return mMediaDescription.mid();
  36. }
  37. Description::Direction Track::direction() const {
  38. std::shared_lock lock(mMutex);
  39. return mMediaDescription.direction();
  40. }
  41. Description::Media Track::description() const {
  42. std::shared_lock lock(mMutex);
  43. return mMediaDescription;
  44. }
  45. void Track::setDescription(Description::Media description) {
  46. std::unique_lock lock(mMutex);
  47. if (description.mid() != mMediaDescription.mid())
  48. throw std::logic_error("Media description mid does not match track mid");
  49. mMediaDescription = std::move(description);
  50. }
  51. void Track::close() {
  52. PLOG_VERBOSE << "Closing Track";
  53. if (!mIsClosed.exchange(true))
  54. triggerClosed();
  55. setMediaHandler(nullptr);
  56. resetCallbacks();
  57. }
  58. optional<message_variant> Track::receive() {
  59. if (auto next = mRecvQueue.pop()) {
  60. message_ptr message = *next;
  61. if (message->type == Message::Control)
  62. return to_variant(**next); // The same message may be frowarded into multiple Tracks
  63. else
  64. return to_variant(std::move(*message));
  65. }
  66. return nullopt;
  67. }
  68. optional<message_variant> Track::peek() {
  69. if (auto next = mRecvQueue.peek()) {
  70. message_ptr message = *next;
  71. if (message->type == Message::Control)
  72. return to_variant(**next); // The same message may be forwarded into multiple Tracks
  73. else
  74. return to_variant(std::move(*message));
  75. }
  76. return nullopt;
  77. }
  78. size_t Track::availableAmount() const { return mRecvQueue.amount(); }
  79. bool Track::isOpen(void) const {
  80. #if RTC_ENABLE_MEDIA
  81. std::shared_lock lock(mMutex);
  82. return !mIsClosed && mDtlsSrtpTransport.lock();
  83. #else
  84. return false;
  85. #endif
  86. }
  87. bool Track::isClosed(void) const { return mIsClosed; }
  88. size_t Track::maxMessageSize() const {
  89. optional<size_t> mtu;
  90. if (auto pc = mPeerConnection.lock())
  91. mtu = pc->config.mtu;
  92. return mtu.value_or(DEFAULT_MTU) - 12 - 8 - 40; // SRTP/UDP/IPv6
  93. }
  94. #if RTC_ENABLE_MEDIA
  95. void Track::open(shared_ptr<DtlsSrtpTransport> transport) {
  96. {
  97. std::lock_guard lock(mMutex);
  98. mDtlsSrtpTransport = transport;
  99. }
  100. if (!mIsClosed)
  101. triggerOpen();
  102. }
  103. #endif
  104. void Track::incoming(message_ptr message) {
  105. if (!message)
  106. return;
  107. auto handler = getMediaHandler();
  108. auto dir = direction();
  109. if ((dir == Description::Direction::SendOnly || dir == Description::Direction::Inactive) &&
  110. message->type != Message::Control) {
  111. COUNTER_MEDIA_BAD_DIRECTION++;
  112. return;
  113. }
  114. if (handler) {
  115. message = handler->incoming(message);
  116. if (!message)
  117. return;
  118. }
  119. // Tail drop if queue is full
  120. if (mRecvQueue.full()) {
  121. COUNTER_QUEUE_FULL++;
  122. return;
  123. }
  124. mRecvQueue.push(message);
  125. triggerAvailable(mRecvQueue.size());
  126. }
  127. bool Track::outgoing(message_ptr message) {
  128. if (mIsClosed)
  129. throw std::runtime_error("Track is closed");
  130. auto handler = getMediaHandler();
  131. // If there is no handler, the track expects RTP or RTCP packets
  132. if (!handler && IsRtcp(*message))
  133. message->type = Message::Control; // to allow sending RTCP packets irrelevant of direction
  134. auto dir = direction();
  135. if ((dir == Description::Direction::RecvOnly || dir == Description::Direction::Inactive) &&
  136. message->type != Message::Control) {
  137. COUNTER_MEDIA_BAD_DIRECTION++;
  138. return false;
  139. }
  140. if (handler) {
  141. message = handler->outgoing(message);
  142. if (!message)
  143. return false;
  144. }
  145. return transportSend(message);
  146. }
  147. bool Track::transportSend([[maybe_unused]] message_ptr message) {
  148. #if RTC_ENABLE_MEDIA
  149. shared_ptr<DtlsSrtpTransport> transport;
  150. {
  151. std::shared_lock lock(mMutex);
  152. transport = mDtlsSrtpTransport.lock();
  153. if (!transport)
  154. throw std::runtime_error("Track is closed");
  155. // Set recommended medium-priority DSCP value
  156. // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5
  157. if (mMediaDescription.type() == "audio")
  158. message->dscp = 46; // EF: Expedited Forwarding
  159. else
  160. message->dscp = 36; // AF42: Assured Forwarding class 4, medium drop probability
  161. }
  162. return transport->sendMedia(message);
  163. #else
  164. throw std::runtime_error("Track is disabled (not compiled with media support)");
  165. #endif
  166. }
  167. void Track::setMediaHandler(shared_ptr<MediaHandler> handler) {
  168. auto currentHandler = getMediaHandler();
  169. if (currentHandler)
  170. currentHandler->onOutgoing(nullptr);
  171. {
  172. std::unique_lock lock(mMutex);
  173. mMediaHandler = handler;
  174. }
  175. if (handler)
  176. handler->onOutgoing(std::bind(&Track::transportSend, this, std::placeholders::_1));
  177. }
  178. shared_ptr<MediaHandler> Track::getMediaHandler() {
  179. std::shared_lock lock(mMutex);
  180. return mMediaHandler;
  181. }
  182. } // namespace rtc::impl