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.

384 lines
8.5KB

  1. #include "bridge.hpp"
  2. #include "util/common.hpp"
  3. #include "dsp/ringbuffer.hpp"
  4. #include <unistd.h>
  5. #ifdef ARCH_WIN
  6. #include <winsock2.h>
  7. #include <ws2tcpip.h>
  8. #else
  9. #include <sys/socket.h>
  10. #include <netinet/in.h>
  11. #include <arpa/inet.h>
  12. #include <netinet/tcp.h>
  13. #include <fcntl.h>
  14. #endif
  15. #include <thread>
  16. namespace rack {
  17. enum BridgeCommand {
  18. NO_COMMAND = 0,
  19. START_COMMAND,
  20. QUIT_COMMAND,
  21. CHANNEL_SET_COMMAND,
  22. AUDIO_SAMPLE_RATE_SET_COMMAND,
  23. AUDIO_CHANNELS_SET_COMMAND,
  24. AUDIO_BUFFER_SEND_COMMAND,
  25. MIDI_MESSAGE_SEND_COMMAND,
  26. NUM_COMMANDS
  27. };
  28. static const int RECV_BUFFER_SIZE = (1<<13);
  29. static const int RECV_QUEUE_SIZE = (1<<17);
  30. static AudioIO *audioListeners[BRIDGE_CHANNELS];
  31. static std::thread serverThread;
  32. static bool serverQuit;
  33. struct BridgeClientConnection {
  34. RingBuffer<uint8_t, RECV_QUEUE_SIZE> recvQueue;
  35. BridgeCommand currentCommand = START_COMMAND;
  36. bool closeRequested = false;
  37. int channel = -1;
  38. int sampleRate = -1;
  39. int audioChannels = 0;
  40. int audioBufferLength = -1;
  41. /** Does not check if the queue has enough data.
  42. You must do that yourself before calling this method.
  43. */
  44. template <typename T>
  45. T shift() {
  46. T x;
  47. recvQueue.shiftBuffer((uint8_t*) &x, sizeof(x));
  48. return x;
  49. }
  50. /** Steps the state machine
  51. Returns true if step() should be called again
  52. */
  53. bool step() {
  54. switch (currentCommand) {
  55. case NO_COMMAND: {
  56. if (recvQueue.size() >= 1) {
  57. // Read command type
  58. uint8_t c = shift<uint8_t>();
  59. currentCommand = (BridgeCommand) c;
  60. return true;
  61. }
  62. } break;
  63. case START_COMMAND: {
  64. // To prevent other TCP protocols from connecting, require a "password" on startup to continue the connection.
  65. const int password = 0xff00fefd;
  66. if (recvQueue.size() >= 4) {
  67. int p = shift<uint32_t>();
  68. if (p == password) {
  69. currentCommand = NO_COMMAND;
  70. return true;
  71. }
  72. else {
  73. closeRequested = true;
  74. }
  75. }
  76. } break;
  77. case QUIT_COMMAND: {
  78. closeRequested = true;
  79. currentCommand = NO_COMMAND;
  80. debug("Quitting!");
  81. } break;
  82. case CHANNEL_SET_COMMAND: {
  83. if (recvQueue.size() >= 1) {
  84. channel = shift<uint8_t>();
  85. debug("Set channel %d", channel);
  86. currentCommand = NO_COMMAND;
  87. return true;
  88. }
  89. } break;
  90. case AUDIO_SAMPLE_RATE_SET_COMMAND: {
  91. if (recvQueue.size() >= 4) {
  92. sampleRate = shift<uint32_t>();
  93. debug("Set sample rate %d", sampleRate);
  94. currentCommand = NO_COMMAND;
  95. return true;
  96. }
  97. } break;
  98. case AUDIO_CHANNELS_SET_COMMAND: {
  99. if (recvQueue.size() >= 1) {
  100. audioChannels = shift<uint8_t>();
  101. debug("Set audio channels %d", channel);
  102. currentCommand = NO_COMMAND;
  103. return true;
  104. }
  105. } break;
  106. case AUDIO_BUFFER_SEND_COMMAND: {
  107. if (audioBufferLength < 0) {
  108. // Get audio buffer size
  109. if (recvQueue.size() >= 4) {
  110. audioBufferLength = shift<uint32_t>();
  111. if (audioBufferLength <= RECV_QUEUE_SIZE) {
  112. return true;
  113. }
  114. else {
  115. // Audio buffer is too large
  116. closeRequested = true;
  117. }
  118. }
  119. }
  120. else {
  121. if (recvQueue.size() >= (size_t) (sizeof(float) * audioBufferLength)) {
  122. float input[audioBufferLength];
  123. float output[audioBufferLength];
  124. memset(output, 0, sizeof(output));
  125. recvQueue.shiftBuffer((uint8_t*) input, sizeof(float) * audioBufferLength);
  126. int frames = audioBufferLength / 2;
  127. processStream(input, output, frames);
  128. audioBufferLength = -1;
  129. currentCommand = NO_COMMAND;
  130. return true;
  131. }
  132. }
  133. } break;
  134. case MIDI_MESSAGE_SEND_COMMAND: {
  135. if (recvQueue.size() >= 3) {
  136. uint8_t midiBuffer[3];
  137. recvQueue.shiftBuffer(midiBuffer, 3);
  138. debug("MIDI: %02x %02x %02x", midiBuffer[0], midiBuffer[1], midiBuffer[2]);
  139. currentCommand = NO_COMMAND;
  140. return true;
  141. }
  142. } break;
  143. default: {
  144. warn("Bridge client: bad command detected, closing");
  145. closeRequested = true;
  146. } break;
  147. }
  148. return false;
  149. }
  150. void recv(uint8_t *buffer, int length) {
  151. // Make sure we can fill the buffer
  152. if (recvQueue.capacity() < (size_t) length) {
  153. // If we can't accept it, future messages will be incomplete
  154. closeRequested = true;
  155. return;
  156. }
  157. recvQueue.pushBuffer(buffer, length);
  158. // Loop the state machine until it returns false
  159. while (step()) {}
  160. }
  161. void processStream(const float *input, float *output, int frames) {
  162. if (!(0 <= channel && channel < BRIDGE_CHANNELS))
  163. return;
  164. if (!audioListeners[channel])
  165. return;
  166. audioListeners[channel]->processStream(input, output, frames);
  167. }
  168. };
  169. static void clientRun(int client) {
  170. int err;
  171. BridgeClientConnection connection;
  172. // // Get client address
  173. // struct sockaddr_in addr;
  174. // socklen_t clientAddrLen = sizeof(addr);
  175. // err = getpeername(client, (struct sockaddr*) &addr, &clientAddrLen);
  176. // assert(!err);
  177. // // Get client IP address
  178. // struct in_addr ipAddr = addr.sin_addr;
  179. // char ipBuffer[INET_ADDRSTRLEN];
  180. // inet_ntop(AF_INET, &ipAddr, ipBuffer, INET_ADDRSTRLEN);
  181. // info("Bridge client %s connected", ipBuffer);
  182. info("Bridge client connected");
  183. #ifdef ARCH_MAC
  184. // Avoid SIGPIPE
  185. int flag = 1;
  186. setsockopt(client, SOL_SOCKET, SO_NOSIGPIPE, &flag, sizeof(int));
  187. #endif
  188. #ifdef ARCH_WIN
  189. unsigned long blockingMode = 1;
  190. ioctlsocket(client, FIONBIO, &blockingMode);
  191. #else
  192. err = fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) & ~O_NONBLOCK);
  193. #endif
  194. while (!connection.closeRequested) {
  195. uint8_t buffer[RECV_BUFFER_SIZE];
  196. #ifdef ARCH_LIN
  197. ssize_t received = recv(client, (char*) buffer, sizeof(buffer), MSG_NOSIGNAL);
  198. #else
  199. ssize_t received = recv(client, (char*) buffer, sizeof(buffer), 0);
  200. #endif
  201. if (received <= 0)
  202. break;
  203. connection.recv(buffer, received);
  204. }
  205. err = close(client);
  206. (void) err;
  207. info("Bridge client closed");
  208. }
  209. static void serverRun() {
  210. int err;
  211. // Initialize sockets
  212. #ifdef ARCH_WIN
  213. WSADATA wsaData;
  214. err = WSAStartup(MAKEWORD(2,2), &wsaData);
  215. defer({
  216. WSACleanup();
  217. });
  218. if (err) {
  219. warn("Could not initialize Winsock");
  220. return;
  221. }
  222. #endif
  223. // Get address
  224. #ifdef ARCH_WIN
  225. struct addrinfo hints;
  226. struct addrinfo *result = NULL;
  227. ZeroMemory(&hints, sizeof(hints));
  228. hints.ai_family = AF_INET;
  229. hints.ai_socktype = SOCK_STREAM;
  230. hints.ai_protocol = IPPROTO_TCP;
  231. hints.ai_flags = AI_PASSIVE;
  232. err = getaddrinfo(NULL, "5000", &hints, &result);
  233. if (err) {
  234. warn("Could not get Bridge server address");
  235. return;
  236. }
  237. defer({
  238. freeaddrinfo(result);
  239. });
  240. #else
  241. struct sockaddr_in addr;
  242. memset(&addr, 0, sizeof(addr));
  243. addr.sin_family = AF_INET;
  244. inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
  245. addr.sin_port = htons(5000);
  246. #endif
  247. // Open socket
  248. #ifdef ARCH_WIN
  249. SOCKET server = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
  250. if (server == INVALID_SOCKET) {
  251. #else
  252. int server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  253. if (server < 0) {
  254. #endif
  255. warn("Bridge server socket() failed");
  256. return;
  257. }
  258. defer({
  259. close(server);
  260. });
  261. // Bind socket to address
  262. #ifdef ARCH_WIN
  263. err = bind(server, result->ai_addr, (int)result->ai_addrlen);
  264. #else
  265. err = bind(server, (struct sockaddr*) &addr, sizeof(addr));
  266. #endif
  267. if (err) {
  268. warn("Bridge server bind() failed");
  269. return;
  270. }
  271. // Listen for clients
  272. err = listen(server, 20);
  273. if (err) {
  274. warn("Bridge server listen() failed");
  275. return;
  276. }
  277. info("Bridge server started");
  278. // Make server non-blocking
  279. #ifdef ARCH_WIN
  280. unsigned long blockingMode = 1;
  281. ioctlsocket(server, FIONBIO, &blockingMode);
  282. #else
  283. err = fcntl(server, F_SETFL, fcntl(server, F_GETFL, 0) | O_NONBLOCK);
  284. #endif
  285. // Accept clients
  286. serverQuit = false;
  287. while (!serverQuit) {
  288. int client = accept(server, NULL, NULL);
  289. if (client < 0) {
  290. // Wait a bit before attempting to accept another client
  291. std::this_thread::sleep_for(std::chrono::duration<float>(0.1));
  292. continue;
  293. }
  294. // Launch client thread
  295. std::thread clientThread(clientRun, client);
  296. clientThread.detach();
  297. }
  298. info("Bridge server closed");
  299. }
  300. void bridgeInit() {
  301. serverThread = std::thread(serverRun);
  302. }
  303. void bridgeDestroy() {
  304. serverQuit = true;
  305. serverThread.join();
  306. }
  307. void bridgeAudioSubscribe(int channel, AudioIO *audio) {
  308. if (!(0 <= channel && channel < BRIDGE_CHANNELS))
  309. return;
  310. if (audioListeners[channel])
  311. return;
  312. audioListeners[channel] = audio;
  313. }
  314. void bridgeAudioUnsubscribe(int channel, AudioIO *audio) {
  315. if (!(0 <= channel && channel < BRIDGE_CHANNELS))
  316. return;
  317. if (audioListeners[channel] != audio)
  318. return;
  319. audioListeners[channel] = NULL;
  320. }
  321. bool bridgeAudioIsSubscribed(int channel, AudioIO *audio) {
  322. if (!(0 <= channel && channel < BRIDGE_CHANNELS))
  323. return false;
  324. return (audioListeners[channel] == audio);
  325. }
  326. } // namespace rack