jack2 codebase
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.

437 lines
15KB

  1. /*
  2. Copyright (C) 2008-2011 Torben Horn
  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. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "JackAVBDriver.h"
  16. #include "JackEngineControl.h"
  17. #include "JackLockedEngine.h"
  18. #include "JackGraphManager.h"
  19. #include "JackWaitThreadedDriver.h"
  20. #include "JackTools.h"
  21. #include "driver_interface.h"
  22. #define MIN(x,y) ((x)<(y) ? (x) : (y))
  23. using namespace std;
  24. /*
  25. * "enp4s0"
  26. */
  27. namespace Jack
  28. {
  29. JackAVBDriver::JackAVBDriver(const char* name, const char* alias, JackLockedEngine* engine, JackSynchro* table,
  30. char* stream_id, char* destination_mac, char* eth_dev,
  31. int sample_rate, int period_size, int adjust, int num_periods, int capture_ports, int playback_ports)
  32. : JackWaiterDriver(name, alias, engine, table)
  33. {
  34. jack_log("JackAVBDriver::JackAVBPDriver Ethernet Device %s", eth_dev);
  35. jack_log("Stream ID: %02x %02x %02x %02x %02x %02x %02x %02x",
  36. (uint8_t) stream_id[0],
  37. (uint8_t) stream_id[1],
  38. (uint8_t) stream_id[2],
  39. (uint8_t) stream_id[3],
  40. (uint8_t) stream_id[4],
  41. (uint8_t) stream_id[5],
  42. (uint8_t) stream_id[6],
  43. (uint8_t) stream_id[7]);
  44. jack_log("Destination MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
  45. (uint8_t) destination_mac[0],
  46. (uint8_t) destination_mac[1],
  47. (uint8_t) destination_mac[2],
  48. (uint8_t) destination_mac[3],
  49. (uint8_t) destination_mac[4],
  50. (uint8_t) destination_mac[5]);
  51. printf("JackAVBDriver::JackAVBPDriver Ethernet Device %s\n", eth_dev);
  52. printf("Stream ID: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  53. (uint8_t) stream_id[0],
  54. (uint8_t) stream_id[1],
  55. (uint8_t) stream_id[2],
  56. (uint8_t) stream_id[3],
  57. (uint8_t) stream_id[4],
  58. (uint8_t) stream_id[5],
  59. (uint8_t) stream_id[6],
  60. (uint8_t) stream_id[7]);
  61. printf("Destination MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
  62. (uint8_t) destination_mac[0],
  63. (uint8_t) destination_mac[1],
  64. (uint8_t) destination_mac[2],
  65. (uint8_t) destination_mac[3],
  66. (uint8_t) destination_mac[4],
  67. (uint8_t) destination_mac[5]);
  68. num_packets_even_odd = 0; // even = 0, odd = 1
  69. init_1722_driver( &(this->ieee1722mc),
  70. eth_dev,
  71. stream_id,
  72. destination_mac,
  73. sample_rate,
  74. period_size,
  75. num_periods,
  76. adjust,
  77. capture_ports,
  78. playback_ports
  79. );
  80. }
  81. JackAVBDriver::~JackAVBDriver()
  82. {
  83. // No destructor yet.
  84. }
  85. //open, close, attach and detach------------------------------------------------------
  86. int JackAVBDriver::Close()
  87. {
  88. // Generic audio driver close
  89. int res = JackWaiterDriver::Close();
  90. FreePorts();
  91. shutdown_1722_driver(&ieee1722mc);
  92. return res;
  93. }
  94. int JackAVBDriver::AllocPorts()
  95. {
  96. jack_port_id_t port_index;
  97. char buf[64];
  98. int chn = 0;
  99. for (chn = 0; chn < ieee1722mc.capture_channels; chn++) {
  100. memset(buf, 0, sizeof(buf));
  101. snprintf (buf, sizeof(buf) - 1, "system:capture_%u", chn + 1);
  102. if (fEngine->PortRegister(fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE,
  103. CaptureDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
  104. jack_error("driver: cannot register port for %s", buf);
  105. return -1;
  106. }
  107. ieee1722mc.capture_ports = jack_slist_append (ieee1722mc.capture_ports, (void *)(intptr_t)port_index);
  108. }
  109. for (chn = 0; chn < ieee1722mc.playback_channels; chn++) {
  110. memset(buf, 0, sizeof(buf));
  111. snprintf (buf, sizeof(buf) - 1, "system:playback_%u", chn + 1);
  112. if (fEngine->PortRegister(fClientControl.fRefNum, buf, JACK_DEFAULT_AUDIO_TYPE,
  113. PlaybackDriverFlags, fEngineControl->fBufferSize, &port_index) < 0) {
  114. jack_error("driver: cannot register port for %s", buf);
  115. return -1;
  116. }
  117. ieee1722mc.playback_ports = jack_slist_append (ieee1722mc.playback_ports, (void *)(intptr_t)port_index);
  118. }
  119. //port = fGraphManager->GetPort(port_index);
  120. return 0;
  121. }
  122. //init and restart--------------------------------------------------------------------
  123. bool JackAVBDriver::Initialize()
  124. {
  125. jack_log("JackAVBDriver::Init");
  126. FreePorts();
  127. //display some additional infos
  128. printf("AVB IEEE1722 AVTP driver started\n");
  129. if (startup_1722_driver(&ieee1722mc)) {
  130. return false;
  131. }
  132. //register jack ports
  133. if (AllocPorts() != 0) {
  134. jack_error("Can't allocate ports.");
  135. return false;
  136. }
  137. //monitor
  138. //driver parametering
  139. JackTimedDriver::SetBufferSize(ieee1722mc.period_size);
  140. JackTimedDriver::SetSampleRate(ieee1722mc.sample_rate);
  141. JackDriver::NotifyBufferSize(ieee1722mc.period_size);
  142. JackDriver::NotifySampleRate(ieee1722mc.sample_rate);
  143. return true;
  144. }
  145. //jack ports and buffers--------------------------------------------------------------
  146. //driver processes--------------------------------------------------------------------
  147. int JackAVBDriver::Read()
  148. {
  149. int ret = 0;
  150. JSList *node = ieee1722mc.capture_ports;
  151. uint64_t cumulative_ipg_ns = 0;
  152. int n = 0;
  153. for(n=0; n<ieee1722mc.num_packets; n++){
  154. cumulative_ipg_ns += wait_recv_ts_1722_mediaclockstream( &ieee1722mc, n );
  155. // jack_log("duration: %lld", cumulative_ipg_ns);
  156. }
  157. //printf("no: %d ipg: %lld ns, period_usec: %lld\n", n, cumulative_ipg_ns, ieee1722mc.period_usecs );fflush(stdout);
  158. float cumulative_ipg_us = cumulative_ipg_ns / 1000;
  159. if ( cumulative_ipg_us > ieee1722mc.period_usecs) {
  160. ret = 1;
  161. NotifyXRun(fBeginDateUst, cumulative_ipg_us);
  162. jack_error("netxruns... duration: %fms", cumulative_ipg_us / 1000);
  163. }
  164. JackDriver::CycleTakeBeginTime();
  165. if ( ret ) {
  166. return -1;
  167. }
  168. while (node != NULL) {
  169. jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data;
  170. JackPort *port = fGraphManager->GetPort(port_index);
  171. jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize);
  172. //memcpy(buf, 0, ieee1722mc.period_size * sizeof(jack_default_audio_sample_t));
  173. node = jack_slist_next (node);
  174. }
  175. return 0;
  176. }
  177. int JackAVBDriver::Write()
  178. {
  179. JSList *node = ieee1722mc.playback_ports;
  180. while (node != NULL) {
  181. jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data;
  182. JackPort *port = fGraphManager->GetPort(port_index);
  183. jack_default_audio_sample_t* buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(port_index, fEngineControl->fBufferSize);
  184. //memcpy(buf, 0, ieee1722mc.period_size * sizeof(jack_default_audio_sample_t));
  185. node = jack_slist_next (node);
  186. }
  187. return 0;
  188. }
  189. void
  190. JackAVBDriver::FreePorts ()
  191. {
  192. JSList *node = ieee1722mc.capture_ports;
  193. while (node != NULL) {
  194. JSList *this_node = node;
  195. jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data;
  196. node = jack_slist_remove_link(node, this_node);
  197. jack_slist_free_1(this_node);
  198. fEngine->PortUnRegister(fClientControl.fRefNum, port_index);
  199. }
  200. ieee1722mc.capture_ports = NULL;
  201. node = ieee1722mc.playback_ports;
  202. while (node != NULL) {
  203. JSList *this_node = node;
  204. jack_port_id_t port_index = (jack_port_id_t)(intptr_t) node->data;
  205. node = jack_slist_remove_link(node, this_node);
  206. jack_slist_free_1(this_node);
  207. fEngine->PortUnRegister(fClientControl.fRefNum, port_index);
  208. }
  209. ieee1722mc.playback_ports = NULL;
  210. }
  211. //driver loader-----------------------------------------------------------------------
  212. #ifdef __cplusplus
  213. extern "C"
  214. {
  215. #endif
  216. inline int argumentsSplitDelimiters(char* inputString, char* outputArray, int array_len)
  217. {
  218. int tokenCnt=0;
  219. char *token;
  220. char *der_string = strdup(inputString);
  221. for(int m=0;m<array_len;m++){
  222. if(( token = strsep(&der_string, ":")) != NULL ){
  223. outputArray[m] = (char)strtol(strdup(token), NULL, 16); // number base 16
  224. } else {
  225. tokenCnt = m;
  226. break;
  227. }
  228. }
  229. free(der_string);
  230. return tokenCnt;
  231. }
  232. SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor ()
  233. {
  234. jack_driver_desc_t * desc;
  235. jack_driver_desc_filler_t filler;
  236. jack_driver_param_value_t value;
  237. desc = jack_driver_descriptor_construct("avb", JackDriverMaster, "IEEE 1722 AVTP slave backend component", &filler);
  238. value.ui = 2U;
  239. jack_driver_descriptor_add_parameter(desc, &filler, "audio-ins", 'i', JackDriverParamUInt, &value, NULL, "Number of capture channels (defaults to 1)", NULL);
  240. jack_driver_descriptor_add_parameter(desc, &filler, "audio-outs", 'o', JackDriverParamUInt, &value, NULL, "Number of playback channels (defaults to 1)", NULL);
  241. value.ui = 48000U;
  242. jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
  243. value.ui = 64U;
  244. jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
  245. value.ui = 1U;
  246. jack_driver_descriptor_add_parameter(desc, &filler, "num-periods", 'n', JackDriverParamUInt, &value, NULL, "Network latency setting in no. of periods", NULL);
  247. value.ui = 0U;
  248. jack_driver_descriptor_add_parameter(desc, &filler, "adjust", 'a', JackDriverParamUInt, &value, NULL, "Adjust Timestamps", NULL);
  249. sprintf( value.str, "enp4s0");
  250. jack_driver_descriptor_add_parameter(desc, &filler, "eth-dev", 'e', JackDriverParamString, &value, NULL, "AVB Ethernet Device", NULL);
  251. sprintf( value.str, "00:22:97:00:41:2c:00:00");
  252. jack_driver_descriptor_add_parameter(desc, &filler, "stream-id", 's', JackDriverParamString, &value, NULL, "Stream ID for listening", NULL);
  253. sprintf( value.str, "91:e0:f0:11:11:11");
  254. jack_driver_descriptor_add_parameter(desc, &filler, "dst-mac", 'm', JackDriverParamString, &value, NULL, "Multicast Destination MAC Address for listening", NULL);
  255. return desc;
  256. }
  257. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  258. {
  259. unsigned int sample_rate = 48000;
  260. jack_nframes_t period_size = 64;
  261. unsigned int capture_ports = 2;
  262. unsigned int playback_ports = 2;
  263. int num_periods = 2;
  264. int adjust = 0;
  265. char sid[8];
  266. char dmac[6];
  267. char eth_dev[32];
  268. int dont_htonl_floats = 0;
  269. int always_deadline = 0;
  270. int jitter_val = 0;
  271. const JSList * node;
  272. const jack_driver_param_t * param;
  273. printf("foo bar\n");fflush(stdout);
  274. for (node = params; node; node = jack_slist_next(node)) {
  275. param = (const jack_driver_param_t*) node->data;
  276. switch (param->character) {
  277. case 'i':
  278. capture_ports = param->value.ui;
  279. break;
  280. case 'o':
  281. playback_ports = param->value.ui;
  282. break;
  283. case 'r':
  284. sample_rate = param->value.ui;
  285. break;
  286. case 'p':
  287. period_size = param->value.ui;
  288. break;
  289. case 'n':
  290. num_periods = param->value.ui;
  291. break;
  292. case 'a':
  293. adjust = param->value.ui;
  294. break;
  295. case 'e':
  296. sprintf(eth_dev, "%s", param->value.str);
  297. printf("Eth Dev: %s %s\n", param->value.str, eth_dev);fflush(stdout);
  298. break;
  299. case 's':
  300. // split stream ID
  301. argumentsSplitDelimiters((char *)param->value.str, sid, 8);
  302. printf("Stream ID: %s %02x %02x %02x %02x %02x %02x %02x %02x \n", param->value.str,
  303. sid[0], sid[1], sid[2], sid[3], sid[4], sid[5], sid[6], sid[7]);fflush(stdout);
  304. break;
  305. case 'm':
  306. // split destination mac address
  307. argumentsSplitDelimiters((char *)param->value.str, dmac, 6);
  308. printf("Destination MAC Address: %s %02x %02x %02x %02x %02x %02x \n", param->value.str,
  309. dmac[0], dmac[1], dmac[2], dmac[3], dmac[4], dmac[5]);fflush(stdout);
  310. break;
  311. }
  312. }
  313. try {
  314. Jack::JackDriverClientInterface* driver = new Jack::JackWaitThreadedDriver (
  315. new Jack::JackAVBDriver("system", "avb_mc", engine, table, sid, dmac, eth_dev,
  316. sample_rate, period_size, num_periods, adjust, capture_ports, playback_ports));
  317. if (driver->Open(period_size, sample_rate, 1, 1, capture_ports, playback_ports,
  318. 0, "from_master", "to_master", 0, 0) == 0) {
  319. return driver;
  320. } else {
  321. delete driver;
  322. return NULL;
  323. }
  324. } catch (...) {
  325. return NULL;
  326. }
  327. }
  328. #ifdef __cplusplus
  329. }
  330. #endif
  331. }