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.

AsioTimer.hpp 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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/platforms/asio/AsioWrapper.hpp>
  21. #include <ableton/util/SafeAsyncHandler.hpp>
  22. #include <functional>
  23. namespace ableton
  24. {
  25. namespace platforms
  26. {
  27. namespace asio
  28. {
  29. // This implementation is based on the boost::asio::system_timer concept.
  30. // Since boost::system_timer doesn't support move semantics, we create a wrapper
  31. // with a unique_ptr to get a movable type. It also handles an inconvenient
  32. // aspect of asio timers, which is that you must explicitly guard against the
  33. // handler firing after cancellation. We handle this by use of the SafeAsyncHandler
  34. // utility. AsioTimer therefore guarantees that a handler will not be called after
  35. // the destruction of the timer, or after the timer has been canceled.
  36. class AsioTimer
  37. {
  38. public:
  39. using ErrorCode = ::asio::error_code;
  40. using TimePoint = std::chrono::system_clock::time_point;
  41. AsioTimer(::asio::io_service& io)
  42. : mpTimer(new ::asio::system_timer(io))
  43. , mpAsyncHandler(std::make_shared<AsyncHandler>())
  44. {
  45. }
  46. ~AsioTimer()
  47. {
  48. // The timer may not be valid anymore if this instance was moved from
  49. if (mpTimer != nullptr)
  50. {
  51. // Ignore errors during cancellation
  52. cancel();
  53. }
  54. }
  55. AsioTimer(const AsioTimer&) = delete;
  56. AsioTimer& operator=(const AsioTimer&) = delete;
  57. // Enable move construction but not move assignment. Move assignment
  58. // would get weird - would have to handle outstanding handlers
  59. AsioTimer(AsioTimer&& rhs)
  60. : mpTimer(std::move(rhs.mpTimer))
  61. , mpAsyncHandler(std::move(rhs.mpAsyncHandler))
  62. {
  63. }
  64. void expires_at(std::chrono::system_clock::time_point tp)
  65. {
  66. mpTimer->expires_at(std::move(tp));
  67. }
  68. template <typename T>
  69. void expires_from_now(T duration)
  70. {
  71. mpTimer->expires_from_now(std::move(duration));
  72. }
  73. ErrorCode cancel()
  74. {
  75. ErrorCode ec;
  76. mpTimer->cancel(ec);
  77. mpAsyncHandler->mpHandler = nullptr;
  78. return ec;
  79. }
  80. template <typename Handler>
  81. void async_wait(Handler handler)
  82. {
  83. *mpAsyncHandler = std::move(handler);
  84. mpTimer->async_wait(util::makeAsyncSafe(mpAsyncHandler));
  85. }
  86. TimePoint now() const
  87. {
  88. return std::chrono::system_clock::now();
  89. }
  90. private:
  91. struct AsyncHandler
  92. {
  93. template <typename Handler>
  94. AsyncHandler& operator=(Handler handler)
  95. {
  96. mpHandler = [handler](ErrorCode ec) { handler(std::move(ec)); };
  97. return *this;
  98. }
  99. void operator()(ErrorCode ec)
  100. {
  101. if (mpHandler)
  102. {
  103. mpHandler(std::move(ec));
  104. }
  105. }
  106. std::function<void(const ErrorCode)> mpHandler;
  107. };
  108. std::unique_ptr<::asio::system_timer> mpTimer;
  109. std::shared_ptr<AsyncHandler> mpAsyncHandler;
  110. };
  111. } // namespace asio
  112. } // namespace platforms
  113. } // namespace ableton