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.

294 lines
7.8KB

  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/NetworkByteStreamSerializable.hpp>
  21. #include <functional>
  22. #include <unordered_map>
  23. namespace ableton
  24. {
  25. namespace discovery
  26. {
  27. struct PayloadEntryHeader
  28. {
  29. using Key = std::uint32_t;
  30. using Size = std::uint32_t;
  31. Key key;
  32. Size size;
  33. friend Size sizeInByteStream(const PayloadEntryHeader& header)
  34. {
  35. return sizeInByteStream(header.key) + sizeInByteStream(header.size);
  36. }
  37. template <typename It>
  38. friend It toNetworkByteStream(const PayloadEntryHeader& header, It out)
  39. {
  40. return toNetworkByteStream(
  41. header.size, toNetworkByteStream(header.key, std::move(out)));
  42. }
  43. template <typename It>
  44. static std::pair<PayloadEntryHeader, It> fromNetworkByteStream(It begin, const It end)
  45. {
  46. using namespace std;
  47. Key key;
  48. Size size;
  49. tie(key, begin) = Deserialize<Key>::fromNetworkByteStream(begin, end);
  50. tie(size, begin) = Deserialize<Size>::fromNetworkByteStream(begin, end);
  51. return make_pair(PayloadEntryHeader{move(key), move(size)}, move(begin));
  52. }
  53. };
  54. template <typename EntryType>
  55. struct PayloadEntry
  56. {
  57. PayloadEntry(EntryType entryVal)
  58. : value(std::move(entryVal))
  59. {
  60. header = {EntryType::key, sizeInByteStream(value)};
  61. }
  62. PayloadEntryHeader header;
  63. EntryType value;
  64. friend std::uint32_t sizeInByteStream(const PayloadEntry& entry)
  65. {
  66. return sizeInByteStream(entry.header) + sizeInByteStream(entry.value);
  67. }
  68. template <typename It>
  69. friend It toNetworkByteStream(const PayloadEntry& entry, It out)
  70. {
  71. return toNetworkByteStream(
  72. entry.value, toNetworkByteStream(entry.header, std::move(out)));
  73. }
  74. };
  75. namespace detail
  76. {
  77. template <typename It>
  78. using HandlerMap =
  79. std::unordered_map<typename PayloadEntryHeader::Key, std::function<void(It, It)>>;
  80. // Given an index of handlers and a byte range, parse the bytes as a
  81. // sequence of payload entries and invoke the appropriate handler for
  82. // each entry type. Entries that are encountered that do not have a
  83. // corresponding handler in the map are ignored. Throws
  84. // std::runtime_error if parsing fails for any entry. Note that if an
  85. // exception is thrown, some of the handlers may have already been called.
  86. template <typename It>
  87. void parseByteStream(HandlerMap<It>& map, It bsBegin, const It bsEnd)
  88. {
  89. using namespace std;
  90. while (bsBegin < bsEnd)
  91. {
  92. // Try to parse an entry header at this location in the byte stream
  93. PayloadEntryHeader header;
  94. It valueBegin;
  95. tie(header, valueBegin) =
  96. Deserialize<PayloadEntryHeader>::fromNetworkByteStream(bsBegin, bsEnd);
  97. // Ensure that the reported size of the entry does not exceed the
  98. // length of the byte stream
  99. It valueEnd = valueBegin + header.size;
  100. if (bsEnd < valueEnd)
  101. {
  102. throw range_error("Payload with incorrect size.");
  103. }
  104. // The next entry will start at the end of this one
  105. bsBegin = valueEnd;
  106. // Use the appropriate handler for this entry, if available
  107. auto handlerIt = map.find(header.key);
  108. if (handlerIt != end(map))
  109. {
  110. handlerIt->second(move(valueBegin), move(valueEnd));
  111. }
  112. }
  113. }
  114. } // namespace detail
  115. // Payload encoding
  116. template <typename... Entries>
  117. struct Payload;
  118. template <typename First, typename Rest>
  119. struct Payload<First, Rest>
  120. {
  121. Payload(First first, Rest rest)
  122. : mFirst(std::move(first))
  123. , mRest(std::move(rest))
  124. {
  125. }
  126. Payload(PayloadEntry<First> first, Rest rest)
  127. : mFirst(std::move(first))
  128. , mRest(std::move(rest))
  129. {
  130. }
  131. template <typename RhsFirst, typename RhsRest>
  132. using PayloadSum =
  133. Payload<First, typename Rest::template PayloadSum<RhsFirst, RhsRest>>;
  134. // Concatenate payloads together into a single payload
  135. template <typename RhsFirst, typename RhsRest>
  136. friend PayloadSum<RhsFirst, RhsRest> operator+(
  137. Payload lhs, Payload<RhsFirst, RhsRest> rhs)
  138. {
  139. return {std::move(lhs.mFirst), std::move(lhs.mRest) + std::move(rhs)};
  140. }
  141. friend std::size_t sizeInByteStream(const Payload& payload)
  142. {
  143. return sizeInByteStream(payload.mFirst) + sizeInByteStream(payload.mRest);
  144. }
  145. template <typename It>
  146. friend It toNetworkByteStream(const Payload& payload, It streamIt)
  147. {
  148. return toNetworkByteStream(
  149. payload.mRest, toNetworkByteStream(payload.mFirst, std::move(streamIt)));
  150. }
  151. PayloadEntry<First> mFirst;
  152. Rest mRest;
  153. };
  154. template <>
  155. struct Payload<>
  156. {
  157. template <typename RhsFirst, typename RhsRest>
  158. using PayloadSum = Payload<RhsFirst, RhsRest>;
  159. template <typename RhsFirst, typename RhsRest>
  160. friend PayloadSum<RhsFirst, RhsRest> operator+(Payload, Payload<RhsFirst, RhsRest> rhs)
  161. {
  162. return rhs;
  163. }
  164. friend std::size_t sizeInByteStream(const Payload&)
  165. {
  166. return 0;
  167. }
  168. template <typename It>
  169. friend It toNetworkByteStream(const Payload&, It streamIt)
  170. {
  171. return streamIt;
  172. }
  173. };
  174. template <typename... Entries>
  175. struct PayloadBuilder;
  176. // Payload factory function
  177. template <typename... Entries>
  178. auto makePayload(Entries... entries)
  179. -> decltype(PayloadBuilder<Entries...>{}(std::move(entries)...))
  180. {
  181. return PayloadBuilder<Entries...>{}(std::move(entries)...);
  182. }
  183. template <typename First, typename... Rest>
  184. struct PayloadBuilder<First, Rest...>
  185. {
  186. auto operator()(First first, Rest... rest)
  187. -> Payload<First, decltype(makePayload(std::move(rest)...))>
  188. {
  189. return {std::move(first), makePayload(std::move(rest)...)};
  190. }
  191. };
  192. template <>
  193. struct PayloadBuilder<>
  194. {
  195. Payload<> operator()()
  196. {
  197. return {};
  198. }
  199. };
  200. // Parse payloads to values
  201. template <typename... Entries>
  202. struct ParsePayload;
  203. template <typename First, typename... Rest>
  204. struct ParsePayload<First, Rest...>
  205. {
  206. template <typename It, typename... Handlers>
  207. static void parse(It begin, It end, Handlers... handlers)
  208. {
  209. detail::HandlerMap<It> map;
  210. collectHandlers(map, std::move(handlers)...);
  211. detail::parseByteStream(map, std::move(begin), std::move(end));
  212. }
  213. template <typename It, typename FirstHandler, typename... RestHandlers>
  214. static void collectHandlers(
  215. detail::HandlerMap<It>& map, FirstHandler handler, RestHandlers... rest)
  216. {
  217. using namespace std;
  218. map[First::key] = [handler](const It begin, const It end) {
  219. const auto res = First::fromNetworkByteStream(begin, end);
  220. if (res.second != end)
  221. {
  222. std::ostringstream stringStream;
  223. stringStream << "Parsing payload entry " << First::key
  224. << " did not consume the expected number of bytes. "
  225. << " Expected: " << distance(begin, end)
  226. << ", Actual: " << distance(begin, res.second);
  227. throw range_error(stringStream.str());
  228. }
  229. handler(res.first);
  230. };
  231. ParsePayload<Rest...>::collectHandlers(map, std::move(rest)...);
  232. }
  233. };
  234. template <>
  235. struct ParsePayload<>
  236. {
  237. template <typename It>
  238. static void collectHandlers(detail::HandlerMap<It>&)
  239. {
  240. }
  241. };
  242. template <typename... Entries, typename It, typename... Handlers>
  243. void parsePayload(It begin, It end, Handlers... handlers)
  244. {
  245. using namespace std;
  246. ParsePayload<Entries...>::parse(move(begin), move(end), move(handlers)...);
  247. }
  248. } // namespace discovery
  249. } // namespace ableton