Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
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.

797 lines
17KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. /* jackpatch.c
  19. This program is just like ASSPatch, except that it works with Jack ports (audio and MIDI).
  20. */
  21. #pragma GCC diagnostic ignored "-Wunused-parameter"
  22. #include <string.h>
  23. #include <sys/stat.h>
  24. #include <unistd.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <unistd.h>
  28. #include <string.h>
  29. #include <signal.h>
  30. #include <getopt.h>
  31. #include <sys/types.h>
  32. #include <sys/time.h>
  33. #include <errno.h>
  34. #include <jack/jack.h>
  35. #include <lo/lo.h>
  36. #include <pthread.h>
  37. int client_active = 0;
  38. jack_client_t *client;
  39. pthread_mutex_t port_lock;
  40. lo_server losrv;
  41. lo_address nsm_addr;
  42. int nsm_is_active;
  43. char *project_file;
  44. #undef VERSION
  45. #define APP_TITLE "JACKPatch"
  46. #define VERSION "0.2"
  47. struct patch_record {
  48. struct {
  49. char *client;
  50. char *port;
  51. } src , dst;
  52. int active; /* true if patch has already been activate (by us) */
  53. struct patch_record *next;
  54. };
  55. struct port_record {
  56. char *port;
  57. int reg; /* true if registered, false if unregistered */
  58. struct port_record *next;
  59. };
  60. static struct port_record *new_ports = NULL;
  61. static struct port_record *known_ports = NULL;
  62. static struct patch_record *patch_list = NULL;
  63. /**
  64. * Pretty-print patch relationship of /pr/
  65. */
  66. void
  67. print_patch ( struct patch_record *pr, int mode )
  68. {
  69. printf( "%s from '%s:%s' to '%s:%s'\n", mode ? ">>" : "::",
  70. pr->src.client, pr->src.port, pr->dst.client, pr->dst.port );
  71. }
  72. void
  73. enqueue ( struct patch_record *p )
  74. {
  75. p->next = patch_list;
  76. patch_list = p;
  77. }
  78. void
  79. dequeue ( struct patch_record *pr )
  80. {
  81. if ( !pr )
  82. return;
  83. free( pr->src.port );
  84. free( pr->dst.port );
  85. free( pr->src.client );
  86. free( pr->dst.client );
  87. free( pr );
  88. }
  89. void
  90. enqueue_port ( struct port_record **q, const char *port, int reg )
  91. {
  92. struct port_record *p = malloc( sizeof( struct port_record ));
  93. p->port = strdup( port );
  94. p->reg = reg;
  95. p->next = *q;
  96. *q = p;
  97. }
  98. struct port_record *
  99. dequeue_port ( struct port_record **q )
  100. {
  101. if ( *q )
  102. {
  103. struct port_record *p = *q;
  104. *q = p->next;
  105. return p;
  106. }
  107. return NULL;
  108. }
  109. void enqueue_known_port ( const char *port )
  110. {
  111. enqueue_port( &known_ports, port, 1 );
  112. }
  113. const char * find_known_port ( const char *port )
  114. {
  115. struct port_record *pr;
  116. for ( pr = known_ports; pr; pr = pr->next )
  117. if ( !strcmp( port, pr->port ) )
  118. return pr->port;
  119. return NULL;
  120. }
  121. void
  122. enqueue_new_port ( const char *port, int reg )
  123. {
  124. pthread_mutex_lock( &port_lock );
  125. enqueue_port( &new_ports, port, reg );
  126. pthread_mutex_unlock( &port_lock );
  127. }
  128. struct port_record *
  129. dequeue_new_port ( void )
  130. {
  131. pthread_mutex_lock( &port_lock );
  132. struct port_record *p = dequeue_port( &new_ports );
  133. pthread_mutex_unlock( &port_lock );
  134. return p;
  135. }
  136. int
  137. process_patch ( const char *patch )
  138. {
  139. struct patch_record *pr;
  140. char *leftc, *rightc, *leftp, *rightp;
  141. char dir[3];
  142. int retval;
  143. retval = sscanf( patch, " %a[^:]:%a[^|] |%1[<>|] %a[^:]:%a[^\n]",
  144. &leftc, &leftp, dir, &rightc, &rightp );
  145. if ( retval == EOF )
  146. return -1;
  147. if ( retval != 5 )
  148. return 0;
  149. /* trim space */
  150. int j;
  151. for ( j = strlen( leftp ) - 1; j > 0; j-- )
  152. {
  153. if ( leftp[j] == ' ' || leftp[j] == '\t' )
  154. leftp[j] = 0;
  155. else
  156. break;
  157. }
  158. dir[2] = 0;
  159. pr = malloc( sizeof( struct patch_record ) );
  160. switch ( *dir )
  161. {
  162. case '<':
  163. pr->src.client = rightc;
  164. pr->src.port = rightp;
  165. pr->dst.client = leftc;
  166. pr->dst.port = leftp;
  167. enqueue( pr );
  168. break;
  169. case '>':
  170. pr->src.client = leftc;
  171. pr->src.port = leftp;
  172. pr->dst.client = rightc;
  173. pr->dst.port = rightp;
  174. enqueue( pr );
  175. break;
  176. case '|':
  177. pr->src.client = rightc;
  178. pr->src.port = rightp;
  179. pr->dst.client = leftc;
  180. pr->dst.port = leftp;
  181. enqueue( pr );
  182. pr = malloc( sizeof( struct patch_record ) );
  183. pr->src.client = strdup( leftc );
  184. pr->src.port = strdup( leftp );
  185. pr->dst.client = strdup( rightc );
  186. pr->dst.port = strdup( rightp );
  187. enqueue( pr );
  188. break;
  189. default:
  190. // fprintf( stderr, "Invalid token '|%s' at line %i of %s!", dir, i, file );
  191. free( pr );
  192. return 0;
  193. }
  194. pr->active = 0;
  195. print_patch( pr, 1 );
  196. return 1;
  197. }
  198. void
  199. clear_all_patches ( )
  200. {
  201. struct patch_record *pr;
  202. while ( patch_list )
  203. {
  204. pr = patch_list;
  205. patch_list = pr->next;
  206. dequeue( pr );
  207. }
  208. }
  209. /**
  210. * Crudely parse configuration file named by /file/ using fscanf
  211. */
  212. int
  213. read_config ( const char *file )
  214. {
  215. FILE *fp;
  216. int i = 0;
  217. if ( NULL == ( fp = fopen( file, "r" ) ) )
  218. return 0;
  219. clear_all_patches();
  220. while ( !feof( fp ) && !ferror( fp ) )
  221. {
  222. int retval;
  223. unsigned int k;
  224. char buf[BUFSIZ];
  225. i++;
  226. for ( k = 0; k < sizeof( buf ) - 1; k++ )
  227. {
  228. retval = fread( buf + k, 1, 1, fp );
  229. if ( retval != 1 )
  230. break;
  231. if ( buf[k] == '\n' )
  232. {
  233. if ( k == 0 )
  234. continue;
  235. else
  236. break;
  237. }
  238. }
  239. if ( retval == 0 )
  240. break;
  241. retval = process_patch( buf );
  242. if ( retval < 0 )
  243. break;
  244. if ( retval == 0 )
  245. {
  246. printf( "bad line %i.\n", i );
  247. continue;
  248. }
  249. }
  250. fclose( fp );
  251. return 1;
  252. }
  253. /* returns 0 if connection failed, true if succeeded. Already connected
  254. * is not considered failure */
  255. void
  256. connect_path ( struct patch_record *pr )
  257. {
  258. int r = 0;
  259. char srcport[512];
  260. char dstport[512];
  261. snprintf( srcport, 512, "%s:%s", pr->src.client, pr->src.port );
  262. snprintf( dstport, 512, "%s:%s", pr->dst.client, pr->dst.port );
  263. if ( pr->active )
  264. {
  265. /* patch is already active, don't bother JACK with it... */
  266. return;
  267. }
  268. if ( ! ( find_known_port( srcport ) && find_known_port( dstport ) ) )
  269. {
  270. /* one of the ports doesn't exist yet... don't attempt
  271. * connection, jack will just complain. */
  272. printf( "Not attempting connection because one of the ports is missing.\n" );
  273. return;
  274. }
  275. printf( "Connecting %s |> %s\n", srcport, dstport );
  276. r = jack_connect( client, srcport, dstport );
  277. print_patch( pr, r );
  278. if ( r == 0 || r == EEXIST )
  279. {
  280. pr->active = 1;
  281. return;
  282. }
  283. else
  284. {
  285. pr->active = 0;
  286. printf( "Error is %i\n", r );
  287. return;
  288. }
  289. }
  290. void
  291. do_for_matching_patches ( const char *portname, void (*func)( struct patch_record * ) )
  292. {
  293. struct patch_record *pr;
  294. char client[512];
  295. char port[512];
  296. sscanf( portname, "%[^:]:%[^\n]", client, port );
  297. for ( pr = patch_list; pr; pr = pr->next )
  298. {
  299. if ( ( !strcmp( client, pr->src.client ) && !strcmp( port, pr->src.port ) ) ||
  300. ( !strcmp( client, pr->dst.client ) && !strcmp( port, pr->dst.port ) ) )
  301. {
  302. func( pr );
  303. }
  304. }
  305. }
  306. void
  307. inactivate_path ( struct patch_record *pr )
  308. {
  309. pr->active = 0;
  310. }
  311. void
  312. inactivate_patch ( const char *portname )
  313. {
  314. do_for_matching_patches( portname, inactivate_path );
  315. }
  316. void
  317. activate_patch ( const char *portname )
  318. {
  319. do_for_matching_patches( portname, connect_path );
  320. }
  321. void remove_known_port ( const char *port )
  322. {
  323. /* remove it from the list of known ports */
  324. {
  325. struct port_record *pr;
  326. struct port_record *lp = NULL;
  327. for ( pr = known_ports; pr; lp = pr, pr = pr->next )
  328. if ( !strcmp( port, pr->port ) )
  329. {
  330. if ( lp )
  331. lp->next = pr->next;
  332. else
  333. known_ports = pr->next;
  334. free( pr->port );
  335. free( pr );
  336. break;
  337. }
  338. }
  339. /* now mark all patches including this port as inactive */
  340. inactivate_patch ( port );
  341. }
  342. /** called for every new port */
  343. void
  344. handle_new_port ( const char *portname )
  345. {
  346. enqueue_known_port( portname );
  347. printf( "New endpoint '%s' registered.\n", portname );
  348. /* this is a new port */
  349. activate_patch( portname );
  350. }
  351. void
  352. register_prexisting_ports ( void )
  353. {
  354. const char **port;
  355. const char **ports = jack_get_ports( client, NULL, NULL, 0 );
  356. if ( ! ports )
  357. return;
  358. for ( port = ports; *port; port++ )
  359. {
  360. handle_new_port( *port );
  361. }
  362. free( ports );
  363. }
  364. void
  365. snapshot ( const char *file )
  366. {
  367. FILE *fp;
  368. const char **port;
  369. const char **ports = jack_get_ports( client, NULL, NULL, JackPortIsOutput );
  370. if ( ! ports )
  371. return;
  372. if ( NULL == ( fp = fopen( file, "w" ) ) )
  373. {
  374. fprintf( stderr, "Error opening snapshot file for writing" );
  375. return;
  376. }
  377. clear_all_patches();
  378. for ( port = ports; *port; port++ )
  379. {
  380. jack_port_t *p;
  381. p = jack_port_by_name( client, *port );
  382. const char **connections;
  383. const char **connection;
  384. connections = jack_port_get_all_connections( client, p );
  385. if ( ! connections )
  386. continue;
  387. for ( connection = connections; *connection; connection++ )
  388. {
  389. char *s;
  390. asprintf( &s, "%-40s |> %s\n", *port, *connection );
  391. fprintf( fp, "%s", s );
  392. process_patch( s );
  393. free(s);
  394. printf( "++ %s |> %s\n", *port, *connection );
  395. }
  396. free( connections );
  397. }
  398. free( ports );
  399. fclose( fp );
  400. }
  401. static int die_now = 0;
  402. void
  403. signal_handler ( int x )
  404. {
  405. die_now = 1;
  406. }
  407. void
  408. die ( void )
  409. {
  410. if ( client_active )
  411. jack_deactivate( client );
  412. jack_client_close( client );
  413. client = NULL;
  414. exit( 0 );
  415. }
  416. /** set_traps
  417. *
  418. * Handle signals
  419. */
  420. void
  421. set_traps ( void )
  422. {
  423. signal( SIGHUP, signal_handler );
  424. signal( SIGINT, signal_handler );
  425. // signal( SIGQUIT, signal_handler );
  426. // signal( SIGSEGV, signal_handler );
  427. // signal( SIGPIPE, signal_handler );
  428. signal( SIGTERM, signal_handler );
  429. }
  430. /****************/
  431. /* OSC HANDLERS */
  432. /****************/
  433. int
  434. osc_announce_error ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  435. {
  436. if ( strcmp( types, "sis" ) )
  437. return -1;
  438. if ( strcmp( "/nsm/server/announce", &argv[0]->s ) )
  439. return -1;
  440. printf( "Failed to register with NSM: %s\n", &argv[2]->s );
  441. nsm_is_active = 0;
  442. return 0;
  443. }
  444. int
  445. osc_announce_reply ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  446. {
  447. if ( strcmp( "/nsm/server/announce", &argv[0]->s ) )
  448. return -1;
  449. printf( "Successfully registered. NSM says: %s", &argv[1]->s );
  450. nsm_is_active = 1;
  451. nsm_addr = lo_address_new_from_url( lo_address_get_url( lo_message_get_source( msg ) ) );
  452. return 0;
  453. }
  454. int
  455. osc_save ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  456. {
  457. snapshot( project_file );
  458. lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
  459. return 0;
  460. }
  461. void
  462. maybe_activate_jack_client ( void )
  463. {
  464. if ( ! client_active )
  465. {
  466. jack_activate( client );
  467. client_active = 1;
  468. }
  469. }
  470. int
  471. osc_open ( const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *user_data )
  472. {
  473. const char *new_path = &argv[0]->s;
  474. // const char *display_name = &argv[1]->s;
  475. char *new_filename;
  476. asprintf( &new_filename, "%s.jackpatch", new_path );
  477. struct stat st;
  478. if ( 0 == stat( new_filename, &st ) )
  479. {
  480. printf( "Reading patch definitions from: %s\n", new_filename );
  481. if ( read_config( new_filename ) )
  482. {
  483. /* wipe_ports(); */
  484. /* check_for_new_ports(); */
  485. maybe_activate_jack_client();
  486. register_prexisting_ports();
  487. }
  488. else
  489. {
  490. lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/error", "sis", path, -1, "Could not open file" );
  491. return 0;
  492. }
  493. }
  494. else
  495. {
  496. maybe_activate_jack_client();
  497. clear_all_patches();
  498. }
  499. if ( project_file )
  500. free( project_file );
  501. project_file = new_filename;
  502. lo_send_from( nsm_addr, losrv, LO_TT_IMMEDIATE, "/reply", "ss", path, "OK" );
  503. return 0;
  504. }
  505. void
  506. announce ( const char *nsm_url, const char *client_name, const char *process_name )
  507. {
  508. printf( "Announcing to NSM\n" );
  509. lo_address to = lo_address_new_from_url( nsm_url );
  510. int pid = (int)getpid();
  511. lo_send_from( to, losrv, LO_TT_IMMEDIATE, "/nsm/server/announce", "sssiii",
  512. client_name,
  513. ":switch:",
  514. process_name,
  515. 0, /* api_major_version */
  516. 8, /* api_minor_version */
  517. pid );
  518. lo_address_free( to );
  519. }
  520. void
  521. init_osc ( const char *osc_port )
  522. {
  523. losrv = lo_server_new( osc_port, NULL );
  524. //error_handler );
  525. char *url = lo_server_get_url(losrv);
  526. printf("OSC: %s\n",url);
  527. free(url);
  528. lo_server_add_method( losrv, "/nsm/client/save", "", osc_save, NULL );
  529. lo_server_add_method( losrv, "/nsm/client/open", "sss", osc_open, NULL );
  530. lo_server_add_method( losrv, "/error", "sis", osc_announce_error, NULL );
  531. lo_server_add_method( losrv, "/reply", "ssss", osc_announce_reply, NULL );
  532. }
  533. void
  534. check_for_new_ports ( void )
  535. {
  536. struct port_record *p = NULL;
  537. while ( ( p = dequeue_new_port() ) )
  538. {
  539. if ( p->reg )
  540. handle_new_port( p->port );
  541. else
  542. remove_known_port( p->port );
  543. free( p->port );
  544. free( p );
  545. }
  546. }
  547. void
  548. port_registration_callback( jack_port_id_t id, int reg, void *arg )
  549. {
  550. jack_port_t *p = jack_port_by_id( client, id );
  551. const char *port = jack_port_name( p );
  552. enqueue_new_port( port, reg );
  553. }
  554. /* */
  555. int
  556. main ( int argc, char **argv )
  557. {
  558. /* get_args( argc, argv ); */
  559. jack_status_t status;
  560. client = jack_client_open( APP_TITLE, JackNullOption, &status );
  561. jack_set_port_registration_callback( client, port_registration_callback, NULL );
  562. if ( ! client )
  563. {
  564. fprintf( stderr, "Could not register JACK client\n" );
  565. exit(1);
  566. }
  567. pthread_mutex_init( &port_lock, NULL );
  568. set_traps();
  569. if ( argc > 1 )
  570. {
  571. maybe_activate_jack_client();
  572. if ( ! strcmp( argv[1], "--save" ) )
  573. {
  574. if ( argc > 2 )
  575. {
  576. printf( "Saving current graph to: %s\n", argv[2] );
  577. snapshot( argv[2] );
  578. die();
  579. }
  580. }
  581. else
  582. {
  583. read_config( argv[1] );
  584. printf( "Monitoring...\n" );
  585. for ( ;; )
  586. {
  587. usleep( 50000 );
  588. check_for_new_ports();
  589. }
  590. }
  591. }
  592. init_osc( NULL );
  593. const char *nsm_url = getenv( "NSM_URL" );
  594. if ( nsm_url )
  595. {
  596. announce( nsm_url, APP_TITLE, argv[0] );
  597. }
  598. else
  599. {
  600. fprintf( stderr, "Could not register as NSM client.\n" );
  601. exit(1);
  602. }
  603. for ( ;; )
  604. {
  605. lo_server_recv_noblock( losrv, 500 );
  606. if ( client_active )
  607. check_for_new_ports();
  608. if ( die_now )
  609. die();
  610. }
  611. }