Audio plugin host https://kx.studio/carla
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.

182 lines
4.9KB

  1. /* Copyright 2016, Ableton AG, Berlin. All rights reserved.
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. * If you would like to incorporate Link into a proprietary software application,
  17. * please contact <link-devs@ableton.com>.
  18. */
  19. #pragma once
  20. #include <ableton/discovery/IpV4Interface.hpp>
  21. #include <ableton/platforms/asio/AsioTimer.hpp>
  22. #include <ableton/platforms/asio/AsioWrapper.hpp>
  23. #include <ableton/platforms/asio/LockFreeCallbackDispatcher.hpp>
  24. #include <ableton/platforms/asio/Socket.hpp>
  25. #include <thread>
  26. namespace ableton
  27. {
  28. namespace platforms
  29. {
  30. namespace asio
  31. {
  32. template <typename ScanIpIfAddrs, typename LogT>
  33. class Context
  34. {
  35. public:
  36. using Timer = AsioTimer;
  37. using Log = LogT;
  38. template <typename Handler, typename Duration>
  39. using LockFreeCallbackDispatcher = LockFreeCallbackDispatcher<Handler, Duration>;
  40. template <std::size_t BufferSize>
  41. using Socket = asio::Socket<BufferSize>;
  42. Context()
  43. : Context(DefaultHandler{})
  44. {
  45. }
  46. template <typename ExceptionHandler>
  47. explicit Context(ExceptionHandler exceptHandler)
  48. : mpService(new ::asio::io_service())
  49. , mpWork(new ::asio::io_service::work(*mpService))
  50. {
  51. mThread =
  52. std::thread{[](::asio::io_service& service, ExceptionHandler handler) {
  53. for (;;)
  54. {
  55. try
  56. {
  57. service.run();
  58. break;
  59. }
  60. catch (const typename ExceptionHandler::Exception& exception)
  61. {
  62. handler(exception);
  63. }
  64. }
  65. },
  66. std::ref(*mpService), std::move(exceptHandler)};
  67. }
  68. Context(const Context&) = delete;
  69. Context(Context&& rhs)
  70. : mpService(std::move(rhs.mpService))
  71. , mpWork(std::move(rhs.mpWork))
  72. , mThread(std::move(rhs.mThread))
  73. , mLog(std::move(rhs.mLog))
  74. , mScanIpIfAddrs(std::move(rhs.mScanIpIfAddrs))
  75. {
  76. }
  77. ~Context()
  78. {
  79. if (mpService)
  80. {
  81. mpWork.reset();
  82. mThread.join();
  83. }
  84. }
  85. template <std::size_t BufferSize>
  86. Socket<BufferSize> openUnicastSocket(const ::asio::ip::address_v4& addr)
  87. {
  88. auto socket = Socket<BufferSize>{*mpService};
  89. socket.mpImpl->mSocket.set_option(
  90. ::asio::ip::multicast::enable_loopback(addr.is_loopback()));
  91. socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));
  92. socket.mpImpl->mSocket.bind(::asio::ip::udp::endpoint{addr, 0});
  93. return socket;
  94. }
  95. template <std::size_t BufferSize>
  96. Socket<BufferSize> openMulticastSocket(const ::asio::ip::address_v4& addr)
  97. {
  98. auto socket = Socket<BufferSize>{*mpService};
  99. socket.mpImpl->mSocket.set_option(::asio::ip::udp::socket::reuse_address(true));
  100. socket.mpImpl->mSocket.set_option(
  101. ::asio::socket_base::broadcast(!addr.is_loopback()));
  102. socket.mpImpl->mSocket.set_option(
  103. ::asio::ip::multicast::enable_loopback(addr.is_loopback()));
  104. socket.mpImpl->mSocket.set_option(::asio::ip::multicast::outbound_interface(addr));
  105. socket.mpImpl->mSocket.bind({::asio::ip::address::from_string("0.0.0.0"),
  106. discovery::multicastEndpoint().port()});
  107. socket.mpImpl->mSocket.set_option(::asio::ip::multicast::join_group(
  108. discovery::multicastEndpoint().address().to_v4(), addr));
  109. return socket;
  110. }
  111. std::vector<::asio::ip::address> scanNetworkInterfaces()
  112. {
  113. return mScanIpIfAddrs();
  114. }
  115. Timer makeTimer() const
  116. {
  117. return {*mpService};
  118. }
  119. Log& log()
  120. {
  121. return mLog;
  122. }
  123. template <typename Handler>
  124. void async(Handler handler)
  125. {
  126. mpService->post(std::move(handler));
  127. }
  128. Context clone() const
  129. {
  130. return {};
  131. }
  132. template <typename ExceptionHandler>
  133. Context clone(ExceptionHandler handler) const
  134. {
  135. return Context{std::move(handler)};
  136. }
  137. private:
  138. // Default handler is hidden and defines a hidden exception type
  139. // that will never be thrown by other code, so it effectively does
  140. // not catch.
  141. struct DefaultHandler
  142. {
  143. struct Exception
  144. {
  145. };
  146. void operator()(const Exception&)
  147. {
  148. }
  149. };
  150. std::unique_ptr<::asio::io_service> mpService;
  151. std::unique_ptr<::asio::io_service::work> mpWork;
  152. std::thread mThread;
  153. Log mLog;
  154. ScanIpIfAddrs mScanIpIfAddrs;
  155. };
  156. } // namespace asio
  157. } // namespace platforms
  158. } // namespace ableton