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.

406 lines
11KB

  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. #if LINK_PLATFORM_MACOSX
  22. #include <ableton/platforms/darwin/Darwin.hpp>
  23. #elif LINK_PLATFORM_LINUX
  24. #include <ableton/platforms/linux/Linux.hpp>
  25. #endif
  26. #include <chrono>
  27. #include <cstdint>
  28. #include <type_traits>
  29. #include <utility>
  30. #include <vector>
  31. #if LINK_PLATFORM_WINDOWS
  32. #include <WS2tcpip.h>
  33. #include <WinSock2.h>
  34. #include <Windows.h>
  35. #endif
  36. namespace ableton
  37. {
  38. namespace discovery
  39. {
  40. // Concept: NetworkByteStreamSerializable
  41. //
  42. // A type that can be encoded to a stream of bytes and decoded from a
  43. // stream of bytes in network byte order. The following type is for
  44. // documentation purposes only.
  45. struct NetworkByteStreamSerializable
  46. {
  47. friend std::uint32_t sizeInByteStream(const NetworkByteStreamSerializable&);
  48. // The byte stream pointed to by 'out' must have sufficient space to
  49. // hold this object, as defined by sizeInByteStream.
  50. template <typename It>
  51. friend It toNetworkByteStream(const NetworkByteStreamSerializable&, It out);
  52. };
  53. // Deserialization aspect of the concept. Outside of the demonstration
  54. // type above because clients must specify the type
  55. // explicitly. Default implementation just defers to a class static
  56. // method on T. For types that can't provide such a method, specialize
  57. // this template.
  58. template <typename T>
  59. struct Deserialize
  60. {
  61. // Throws std::runtime_exception if parsing the type from the given
  62. // byte range fails. Returns a pair of the correctly parsed value
  63. // and an iterator to the next byte to parse.
  64. template <typename It>
  65. static std::pair<T, It> fromNetworkByteStream(It begin, It end)
  66. {
  67. return T::fromNetworkByteStream(std::move(begin), std::move(end));
  68. }
  69. };
  70. // Default size implementation. Works for primitive types.
  71. template <typename T>
  72. std::uint32_t sizeInByteStream(T)
  73. {
  74. return sizeof(T);
  75. }
  76. namespace detail
  77. {
  78. // utilities for implementing concept for primitive types
  79. template <typename T, typename It>
  80. It copyToByteStream(T t, It out)
  81. {
  82. using namespace std;
  83. return copy_n(
  84. reinterpret_cast<typename iterator_traits<It>::pointer>(&t), sizeof(t), out);
  85. }
  86. template <typename T, typename It>
  87. std::pair<T, It> copyFromByteStream(It begin, const It end)
  88. {
  89. using namespace std;
  90. using ItDiff = typename iterator_traits<It>::difference_type;
  91. if (distance(begin, end) < static_cast<ItDiff>(sizeof(T)))
  92. {
  93. throw range_error("Parsing type from byte stream failed");
  94. }
  95. else
  96. {
  97. T t;
  98. const auto n = sizeof(t);
  99. copy_n(begin, n, reinterpret_cast<uint8_t*>(&t));
  100. return make_pair(t, begin + n);
  101. }
  102. }
  103. } // namespace detail
  104. // Model the concept for unsigned integral types
  105. // uint8_t
  106. template <typename It>
  107. It toNetworkByteStream(const uint8_t byte, It out)
  108. {
  109. return detail::copyToByteStream(byte, std::move(out));
  110. }
  111. template <>
  112. struct Deserialize<uint8_t>
  113. {
  114. template <typename It>
  115. static std::pair<uint8_t, It> fromNetworkByteStream(It begin, It end)
  116. {
  117. return detail::copyFromByteStream<uint8_t>(std::move(begin), std::move(end));
  118. }
  119. };
  120. // uint16_t
  121. template <typename It>
  122. It toNetworkByteStream(uint16_t s, It out)
  123. {
  124. return detail::copyToByteStream(htons(s), std::move(out));
  125. }
  126. template <>
  127. struct Deserialize<uint16_t>
  128. {
  129. template <typename It>
  130. static std::pair<uint16_t, It> fromNetworkByteStream(It begin, It end)
  131. {
  132. auto result = detail::copyFromByteStream<uint16_t>(std::move(begin), std::move(end));
  133. result.first = ntohs(result.first);
  134. return result;
  135. }
  136. };
  137. // uint32_t
  138. template <typename It>
  139. It toNetworkByteStream(uint32_t l, It out)
  140. {
  141. return detail::copyToByteStream(htonl(l), std::move(out));
  142. }
  143. template <>
  144. struct Deserialize<uint32_t>
  145. {
  146. template <typename It>
  147. static std::pair<uint32_t, It> fromNetworkByteStream(It begin, It end)
  148. {
  149. auto result = detail::copyFromByteStream<uint32_t>(std::move(begin), std::move(end));
  150. result.first = ntohl(result.first);
  151. return result;
  152. }
  153. };
  154. // int32_t in terms of uint32_t
  155. template <typename It>
  156. It toNetworkByteStream(int32_t l, It out)
  157. {
  158. return toNetworkByteStream(reinterpret_cast<const uint32_t&>(l), std::move(out));
  159. }
  160. template <>
  161. struct Deserialize<int32_t>
  162. {
  163. template <typename It>
  164. static std::pair<int32_t, It> fromNetworkByteStream(It begin, It end)
  165. {
  166. auto result =
  167. Deserialize<uint32_t>::fromNetworkByteStream(std::move(begin), std::move(end));
  168. return std::make_pair(reinterpret_cast<const int32_t&>(result.first), result.second);
  169. }
  170. };
  171. // uint64_t
  172. template <typename It>
  173. It toNetworkByteStream(uint64_t ll, It out)
  174. {
  175. return detail::copyToByteStream(htonll(ll), std::move(out));
  176. }
  177. template <>
  178. struct Deserialize<uint64_t>
  179. {
  180. template <typename It>
  181. static std::pair<uint64_t, It> fromNetworkByteStream(It begin, It end)
  182. {
  183. auto result = detail::copyFromByteStream<uint64_t>(std::move(begin), std::move(end));
  184. result.first = ntohll(result.first);
  185. return result;
  186. }
  187. };
  188. // int64_t in terms of uint64_t
  189. template <typename It>
  190. It toNetworkByteStream(int64_t ll, It out)
  191. {
  192. return toNetworkByteStream(reinterpret_cast<const uint64_t&>(ll), std::move(out));
  193. }
  194. template <>
  195. struct Deserialize<int64_t>
  196. {
  197. template <typename It>
  198. static std::pair<int64_t, It> fromNetworkByteStream(It begin, It end)
  199. {
  200. auto result =
  201. Deserialize<uint64_t>::fromNetworkByteStream(std::move(begin), std::move(end));
  202. return std::make_pair(reinterpret_cast<const int64_t&>(result.first), result.second);
  203. }
  204. };
  205. // overloads for std::chrono durations
  206. template <typename Rep, typename Ratio>
  207. std::uint32_t sizeInByteStream(const std::chrono::duration<Rep, Ratio> dur)
  208. {
  209. return sizeInByteStream(dur.count());
  210. }
  211. template <typename Rep, typename Ratio, typename It>
  212. It toNetworkByteStream(const std::chrono::duration<Rep, Ratio> dur, It out)
  213. {
  214. return toNetworkByteStream(dur.count(), std::move(out));
  215. }
  216. template <typename Rep, typename Ratio>
  217. struct Deserialize<std::chrono::duration<Rep, Ratio>>
  218. {
  219. template <typename It>
  220. static std::pair<std::chrono::duration<Rep, Ratio>, It> fromNetworkByteStream(
  221. It begin, It end)
  222. {
  223. using namespace std;
  224. auto result = Deserialize<Rep>::fromNetworkByteStream(move(begin), move(end));
  225. return make_pair(std::chrono::duration<Rep, Ratio>{result.first}, result.second);
  226. }
  227. };
  228. namespace detail
  229. {
  230. // Generic serialize/deserialize utilities for containers
  231. template <typename Container>
  232. std::uint32_t containerSizeInByteStream(const Container& container)
  233. {
  234. std::uint32_t totalSize = 0;
  235. for (const auto& val : container)
  236. {
  237. totalSize += sizeInByteStream(val);
  238. }
  239. return totalSize;
  240. }
  241. template <typename Container, typename It>
  242. It containerToNetworkByteStream(const Container& container, It out)
  243. {
  244. for (const auto& val : container)
  245. {
  246. out = toNetworkByteStream(val, out);
  247. }
  248. return out;
  249. }
  250. template <typename T, typename BytesIt, typename InsertIt>
  251. BytesIt deserializeContainer(BytesIt bytesBegin,
  252. const BytesIt bytesEnd,
  253. InsertIt contBegin,
  254. const std::uint32_t maxElements)
  255. {
  256. using namespace std;
  257. std::uint32_t numElements = 0;
  258. while (bytesBegin < bytesEnd && numElements < maxElements)
  259. {
  260. T newVal;
  261. tie(newVal, bytesBegin) = Deserialize<T>::fromNetworkByteStream(bytesBegin, bytesEnd);
  262. *contBegin++ = newVal;
  263. ++numElements;
  264. }
  265. return bytesBegin;
  266. }
  267. } // detail
  268. // Need specific overloads for each container type, but use above
  269. // utilities for common implementation
  270. // array
  271. template <typename T, std::size_t Size>
  272. std::uint32_t sizeInByteStream(const std::array<T, Size>& arr)
  273. {
  274. return detail::containerSizeInByteStream(arr);
  275. }
  276. template <typename T, std::size_t Size, typename It>
  277. It toNetworkByteStream(const std::array<T, Size>& arr, It out)
  278. {
  279. return detail::containerToNetworkByteStream(arr, std::move(out));
  280. }
  281. template <typename T, std::size_t Size>
  282. struct Deserialize<std::array<T, Size>>
  283. {
  284. template <typename It>
  285. static std::pair<std::array<T, Size>, It> fromNetworkByteStream(It begin, It end)
  286. {
  287. using namespace std;
  288. array<T, Size> result{};
  289. auto resultIt =
  290. detail::deserializeContainer<T>(move(begin), move(end), move(result.begin()), Size);
  291. return make_pair(move(result), move(resultIt));
  292. }
  293. };
  294. // vector
  295. template <typename T, typename Alloc>
  296. std::uint32_t sizeInByteStream(const std::vector<T, Alloc>& vec)
  297. {
  298. return detail::containerSizeInByteStream(vec);
  299. }
  300. template <typename T, typename Alloc, typename It>
  301. It toNetworkByteStream(const std::vector<T, Alloc>& vec, It out)
  302. {
  303. return detail::containerToNetworkByteStream(vec, std::move(out));
  304. }
  305. template <typename T, typename Alloc>
  306. struct Deserialize<std::vector<T, Alloc>>
  307. {
  308. template <typename It>
  309. static std::pair<std::vector<T, Alloc>, It> fromNetworkByteStream(
  310. It bytesBegin, It bytesEnd)
  311. {
  312. using namespace std;
  313. vector<T, Alloc> result;
  314. // Use the number of bytes remaining in the stream as the upper
  315. // bound on the number of elements that could be deserialized
  316. // since we don't have a better heuristic.
  317. auto resultIt = detail::deserializeContainer<T>(move(bytesBegin), move(bytesEnd),
  318. back_inserter(result), static_cast<uint32_t>(distance(bytesBegin, bytesEnd)));
  319. return make_pair(move(result), move(resultIt));
  320. }
  321. };
  322. // 3-tuple
  323. template <typename X, typename Y, typename Z>
  324. std::uint32_t sizeInByteStream(const std::tuple<X, Y, Z>& tup)
  325. {
  326. return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup))
  327. + sizeInByteStream(std::get<2>(tup));
  328. }
  329. template <typename X, typename Y, typename Z, typename It>
  330. It toNetworkByteStream(const std::tuple<X, Y, Z>& tup, It out)
  331. {
  332. return toNetworkByteStream(
  333. std::get<2>(tup), toNetworkByteStream(std::get<1>(tup),
  334. toNetworkByteStream(std::get<0>(tup), std::move(out))));
  335. }
  336. template <typename X, typename Y, typename Z>
  337. struct Deserialize<std::tuple<X, Y, Z>>
  338. {
  339. template <typename It>
  340. static std::pair<std::tuple<X, Y, Z>, It> fromNetworkByteStream(It begin, It end)
  341. {
  342. using namespace std;
  343. auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);
  344. auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);
  345. auto zres = Deserialize<Z>::fromNetworkByteStream(yres.second, end);
  346. return make_pair(
  347. std::tuple<X, Y, Z>{move(xres.first), move(yres.first), move(zres.first)},
  348. move(zres.second));
  349. }
  350. };
  351. } // namespace discovery
  352. } // namespace ableton