track.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /**
  2. * Copyright (c) 2020 Paul-Louis Ageneau
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "track.hpp"
  19. #include "internals.hpp"
  20. #include "logcounter.hpp"
  21. #include "peerconnection.hpp"
  22. namespace rtc::impl {
  23. static LogCounter COUNTER_MEDIA_BAD_DIRECTION(plog::warning,
  24. "Number of media packets sent in invalid directions");
  25. static LogCounter COUNTER_QUEUE_FULL(plog::warning,
  26. "Number of media packets dropped due to a full queue");
  27. Track::Track(weak_ptr<PeerConnection> pc, Description::Media description)
  28. : mPeerConnection(pc), mMediaDescription(std::move(description)),
  29. mRecvQueue(RECV_QUEUE_LIMIT, message_size_func) {}
  30. Track::~Track() {
  31. PLOG_VERBOSE << "Destroying Track";
  32. close();
  33. }
  34. string Track::mid() const {
  35. std::shared_lock lock(mMutex);
  36. return mMediaDescription.mid();
  37. }
  38. Description::Direction Track::direction() const {
  39. std::shared_lock lock(mMutex);
  40. return mMediaDescription.direction();
  41. }
  42. Description::Media Track::description() const {
  43. std::shared_lock lock(mMutex);
  44. return mMediaDescription;
  45. }
  46. void Track::setDescription(Description::Media description) {
  47. std::unique_lock lock(mMutex);
  48. if (description.mid() != mMediaDescription.mid())
  49. throw std::logic_error("Media description mid does not match track mid");
  50. mMediaDescription = std::move(description);
  51. }
  52. void Track::close() {
  53. PLOG_VERBOSE << "Closing Track";
  54. if (!mIsClosed.exchange(true))
  55. triggerClosed();
  56. setMediaHandler(nullptr);
  57. resetCallbacks();
  58. }
  59. optional<message_variant> Track::receive() {
  60. if (auto next = mRecvQueue.tryPop())
  61. return to_variant(std::move(**next));
  62. return nullopt;
  63. }
  64. optional<message_variant> Track::peek() {
  65. if (auto next = mRecvQueue.peek())
  66. return to_variant(std::move(**next));
  67. return nullopt;
  68. }
  69. size_t Track::availableAmount() const { return mRecvQueue.amount(); }
  70. bool Track::isOpen(void) const {
  71. #if RTC_ENABLE_MEDIA
  72. std::shared_lock lock(mMutex);
  73. return !mIsClosed && mDtlsSrtpTransport.lock();
  74. #else
  75. return !mIsClosed;
  76. #endif
  77. }
  78. bool Track::isClosed(void) const { return mIsClosed; }
  79. size_t Track::maxMessageSize() const {
  80. optional<size_t> mtu;
  81. if (auto pc = mPeerConnection.lock())
  82. mtu = pc->config.mtu;
  83. return mtu.value_or(DEFAULT_MTU) - 12 - 8 - 40; // SRTP/UDP/IPv6
  84. }
  85. #if RTC_ENABLE_MEDIA
  86. void Track::open(shared_ptr<DtlsSrtpTransport> transport) {
  87. {
  88. std::lock_guard lock(mMutex);
  89. mDtlsSrtpTransport = transport;
  90. }
  91. if (!mIsClosed)
  92. triggerOpen();
  93. }
  94. #endif
  95. void Track::incoming(message_ptr message) {
  96. if (!message)
  97. return;
  98. // TODO
  99. auto dir = direction();
  100. if ((dir == Description::Direction::SendOnly || dir == Description::Direction::Inactive) &&
  101. message->type != Message::Control) {
  102. COUNTER_MEDIA_BAD_DIRECTION++;
  103. return;
  104. }
  105. if (auto handler = getMediaHandler()) {
  106. message = handler->incoming(message);
  107. if (!message)
  108. return;
  109. }
  110. // Tail drop if queue is full
  111. if (mRecvQueue.full()) {
  112. COUNTER_QUEUE_FULL++;
  113. return;
  114. }
  115. mRecvQueue.push(message);
  116. triggerAvailable(mRecvQueue.size());
  117. }
  118. bool Track::outgoing(message_ptr message) {
  119. if (mIsClosed)
  120. throw std::runtime_error("Track is closed");
  121. auto dir = direction();
  122. if ((dir == Description::Direction::RecvOnly || dir == Description::Direction::Inactive)) {
  123. COUNTER_MEDIA_BAD_DIRECTION++;
  124. return false;
  125. }
  126. if (auto handler = getMediaHandler()) {
  127. message = handler->outgoing(message);
  128. if (!message)
  129. return false;
  130. }
  131. return transportSend(message);
  132. }
  133. bool Track::transportSend([[maybe_unused]] message_ptr message) {
  134. #if RTC_ENABLE_MEDIA
  135. shared_ptr<DtlsSrtpTransport> transport;
  136. {
  137. std::shared_lock lock(mMutex);
  138. transport = mDtlsSrtpTransport.lock();
  139. if (!transport)
  140. throw std::runtime_error("Track is closed");
  141. // Set recommended medium-priority DSCP value
  142. // See https://www.rfc-editor.org/rfc/rfc8837.html#section-5
  143. if (mMediaDescription.type() == "audio")
  144. message->dscp = 46; // EF: Expedited Forwarding
  145. else
  146. message->dscp = 36; // AF42: Assured Forwarding class 4, medium drop probability
  147. }
  148. return transport->sendMedia(message);
  149. #else
  150. PLOG_WARNING << "Ignoring track send (not compiled with media support)";
  151. return false;
  152. #endif
  153. }
  154. void Track::setMediaHandler(shared_ptr<MediaHandler> handler) {
  155. {
  156. std::unique_lock lock(mMutex);
  157. if (mMediaHandler)
  158. mMediaHandler->onOutgoing(nullptr);
  159. mMediaHandler = handler;
  160. }
  161. if (handler)
  162. handler->onOutgoing(std::bind(&Track::transportSend, this, std::placeholders::_1));
  163. }
  164. shared_ptr<MediaHandler> Track::getMediaHandler() {
  165. std::shared_lock lock(mMutex);
  166. return mMediaHandler;
  167. }
  168. } // namespace rtc::impl