Changeset 51bb400466101d3a545817ba7e27f9d25568ab51

Show
Ignore:
Timestamp:
07/04/09 01:15:59 (3 years ago)
Author:
Nedko Arnaudov <nedko@…>
Children:
b05530c4ff96e00046ae4e9555794b66265081b2
Parents:
c6dad257c20c3ef9c3f58a6f82ce1d1077782fe6
git-committer:
Nedko Arnaudov <nedko@arnaudov.name> / 2009-07-04T01:15:59Z+0300
Message:

Switch from liblo to unix pipes

Files:
2 modified

Legend:

Unmodified
Added
Removed
  • lv2_ui.c

    rb22a23b r51bb400  
    3333#include <sys/types.h> 
    3434#include <unistd.h> 
     35#include <fcntl.h> 
     36#include <locale.h> 
    3537#include <errno.h> 
    36  
    37 #include <lo/lo.h> 
    3838 
    3939#include <lv2.h> 
     
    4141#include "lv2_external_ui.h" 
    4242 
    43 #define MAX_OSC_PATH 1024 
    44  
    4543struct control 
    4644{ 
     
    5149  void (* ui_closed)(LV2UI_Controller controller); 
    5250 
    53   lo_server osc_server; 
    54  
    5551  bool running;              /* true if UI launched and 'exiting' not received */ 
    5652  bool visible;              /* true if 'show' sent */ 
    5753 
    58   lo_address osc_address;    /* non-NULL if 'update' received */ 
    59  
    60   char osc_control_path[MAX_OSC_PATH]; 
    61   char osc_hide_path[MAX_OSC_PATH]; 
    62   char osc_quit_path[MAX_OSC_PATH]; 
    63   char osc_show_path[MAX_OSC_PATH]; 
     54  int send_pipe;             /* the pipe end that is used for sending messages to UI */ 
     55  int recv_pipe;             /* the pipe end that is used for receiving messages from UI */ 
    6456}; 
    6557 
    66 #undef control_ptr 
    67  
    68 static 
    69 int 
    70 osc_debug_handler( 
    71   const char * path, 
    72   const char * types, 
    73   lo_arg ** argv, 
    74   int argc, 
    75   void * data, 
    76   void * user_data) 
    77 { 
    78   int i; 
    79  
    80   printf("got unhandled OSC message:\n"); 
    81   printf("path: <%s>\n", path); 
    82   fflush(stdout); 
    83   for (i = 0; i < argc; i++) 
    84   { 
    85     printf("arg %d '%c' ", i, types[i]); 
    86     lo_arg_pp(types[i], argv[i]); 
    87     printf("\n"); 
    88   } 
    89   fflush(stdout); 
    90  
    91   return 1; 
    92 } 
    93  
    94 int 
    95 osc_exiting_handler( 
    96   struct control * control_ptr, 
    97   lo_arg ** argv) 
    98 { 
    99   //printf("OSC: got UI exit notification\n"); 
    100  
    101   control_ptr->running = false; 
    102   control_ptr->visible = false; 
    103  
    104   if (control_ptr->osc_address) 
    105   { 
    106     lo_address_free(control_ptr->osc_address); 
    107   } 
    108  
    109   control_ptr->ui_closed(control_ptr->controller); 
    110  
    111   return 0; 
    112 } 
    113  
    114 int 
    115 osc_control_handler( 
    116   struct control * control_ptr, 
    117   lo_arg ** argv) 
    118 { 
    119   int port = argv[0]->i; 
    120   float value = argv[1]->f; 
    121  
    122   //printf("OSC control handler: port %d = %f\n", port, value); 
    123  
    124   control_ptr->write_function(control_ptr->controller, (uint32_t)port, sizeof(float), 0, &value); 
    125  
    126   return 0; 
    127 } 
    128  
    129 int 
    130 osc_update_handler( 
    131   struct control * control_ptr, 
    132   lo_arg ** argv) 
    133 { 
    134   const char * url = &argv[0]->s; 
    135   char * path; 
    136   char * host; 
    137   char * port; 
    138  
    139   //printf("OSC: got update request from <%s>\n", url); 
    140  
    141   if (control_ptr->osc_address) 
    142   { 
    143     return 0; 
    144   } 
    145  
    146   host = lo_url_get_hostname(url); 
    147   port = lo_url_get_port(url); 
    148   control_ptr->osc_address = lo_address_new(host, port); 
    149   free(host); 
    150   free(port); 
    151  
    152   path = lo_url_get_path(url); 
    153  
    154   sprintf(control_ptr->osc_control_path, "%scontrol", path); 
    155   sprintf(control_ptr->osc_hide_path, "%shide", path); 
    156   sprintf(control_ptr->osc_show_path, "%sshow", path); 
    157   sprintf(control_ptr->osc_quit_path, "%squit", path); 
    158  
    159   free(path); 
    160  
    161   control_ptr->running = true; 
    162  
    163   return 0; 
    164 } 
    165  
    166 #define control_ptr ((struct control *)user_data) 
    167  
    168 static 
    169 int 
    170 osc_message_handler( 
    171   const char * path, 
    172   const char * types, 
    173   lo_arg ** argv, 
    174   int argc, 
    175   void * data, 
    176   void * user_data) 
    177 { 
    178   const char *method; 
    179  
    180   method = path; 
    181   if (method[0] != '/' || method[1] != '/') 
    182     return osc_debug_handler(path, types, argv, argc, data, user_data); 
    183   method += 2; 
    184  
    185   if (!strcmp(method, "update") && argc == 1 && !strcmp(types, "s")) 
    186   { 
    187     return osc_update_handler(control_ptr, argv); 
    188   } 
    189   else if (!strcmp(method, "control") && argc == 2 && !strcmp(types, "if")) 
    190   { 
    191     return osc_control_handler(control_ptr, argv); 
    192   } 
    193   else if (!strcmp(method, "exiting") && argc == 0) 
    194   { 
    195     return osc_exiting_handler(control_ptr, argv); 
    196   } 
    197  
    198   return osc_debug_handler(path, types, argv, argc, data, user_data); 
    199 } 
    200  
    201 #undef control_ptr 
     58static 
     59char * 
     60read_line( 
     61  struct control * control_ptr) 
     62{ 
     63  ssize_t ret; 
     64  char ch; 
     65  char buf[100]; 
     66  char * ptr; 
     67 
     68  ptr = buf; 
     69 
     70loop: 
     71  ret = read(control_ptr->recv_pipe, &ch, 1); 
     72  if (ret == 1 && ch != '\n') 
     73  { 
     74    *ptr++ = ch; 
     75    goto loop; 
     76  } 
     77 
     78  if (ptr != buf) 
     79  { 
     80    *ptr = 0; 
     81    //printf("recv: \"%s\"\n", buf); 
     82    return strdup(buf); 
     83  } 
     84 
     85  return NULL; 
     86} 
    20287 
    20388#define control_ptr ((struct control *)_this_) 
     
    20893  struct lv2_external_ui * _this_) 
    20994{ 
     95  char * msg; 
     96  char * port_index_str; 
     97  char * port_value_str; 
     98  int port; 
     99  float value; 
     100  char * locale; 
     101 
    210102  //printf("run() called\n"); 
    211   while (lo_server_recv_noblock(control_ptr->osc_server, 0) != 0) {} 
     103 
     104  msg = read_line(control_ptr); 
     105  if (msg == NULL) 
     106  { 
     107    return; 
     108  } 
     109 
     110  locale = strdup(setlocale(LC_NUMERIC, NULL)); 
     111  setlocale(LC_NUMERIC, "POSIX"); 
     112 
     113  if (!strcmp(msg, "port_value")) 
     114  { 
     115    port_index_str = read_line(control_ptr); 
     116    port_value_str = read_line(control_ptr); 
     117 
     118    port = atoi(port_index_str); 
     119    if (sscanf(port_value_str, "%f", &value) == 1) 
     120    { 
     121      //printf("port %d = %f\n", port, value); 
     122      control_ptr->write_function(control_ptr->controller, (uint32_t)port, sizeof(float), 0, &value); 
     123    } 
     124    else 
     125    { 
     126      fprintf(stderr, "failed to convert \"%s\" to float\n", port_value_str); 
     127    } 
     128 
     129    free(port_index_str); 
     130    free(port_value_str); 
     131  } 
     132  else if (!strcmp(msg, "exiting")) 
     133  { 
     134    //printf("got UI exit notification\n"); 
     135    control_ptr->running = false; 
     136    control_ptr->visible = false; 
     137    control_ptr->ui_closed(control_ptr->controller); 
     138  } 
     139  else 
     140  { 
     141    printf("unknown message: \"%s\"\n", msg); 
     142  } 
     143 
     144  setlocale(LC_NUMERIC, locale); 
     145  free(locale); 
     146 
     147  free(msg); 
    212148} 
    213149 
     
    224160  } 
    225161 
    226   if (control_ptr->osc_address) 
    227   { 
    228     lo_send(control_ptr->osc_address, control_ptr->osc_show_path, ""); 
    229     control_ptr->visible = true; 
    230   } 
     162  write(control_ptr->send_pipe, "show\n", 5); 
     163  control_ptr->visible = true; 
    231164} 
    232165 
     
    238171  //printf("hide() called\n"); 
    239172 
    240   if (!control_ptr->visible || !control_ptr->osc_address) 
     173  if (!control_ptr->visible) 
    241174  { 
    242175    return; 
    243176  } 
    244177 
    245   lo_send(control_ptr->osc_address, control_ptr->osc_hide_path, ""); 
     178  write(control_ptr->send_pipe, "hide\n", 5); 
    246179  control_ptr->visible = false; 
    247180} 
     
    263196  struct lv2_external_ui_host * ui_host_ptr; 
    264197  char * filename; 
    265   char * osc_url; 
     198  int pipe1[2]; /* written by host process, read by plugin UI process */ 
     199  int pipe2[2]; /* written by plugin UI process, read by host process */ 
     200  char ui_recv_pipe[100]; 
     201  char ui_send_pipe[100]; 
     202  int oldflags; 
    266203 
    267204  //printf("instantiate('%s', '%s') called\n", plugin_uri, bundle_path); 
     
    297234  control_ptr->ui_closed = ui_host_ptr->ui_closed; 
    298235 
     236  if (pipe(pipe1) != 0) 
     237  { 
     238    fprintf(stderr, "pipe1 creation failed."); 
     239  } 
     240 
     241  if (pipe(pipe2) != 0) 
     242  { 
     243    fprintf(stderr, "pipe2 creation failed."); 
     244  } 
     245 
     246  snprintf(ui_recv_pipe, sizeof(ui_recv_pipe), "%d", pipe1[0]); /* [0] means reading end */ 
     247  snprintf(ui_send_pipe, sizeof(ui_send_pipe), "%d", pipe2[1]); /* [1] means writting end */ 
     248 
    299249  filename = malloc(strlen(bundle_path) + strlen(UI_EXECUTABLE) + 1); 
    300250  if (filename == NULL) 
     
    308258  control_ptr->running = false; 
    309259  control_ptr->visible = false; 
    310   control_ptr->osc_address = NULL; 
    311  
    312   control_ptr->osc_server = lo_server_new(NULL, NULL); 
    313   osc_url = lo_server_get_url(control_ptr->osc_server); 
    314   //printf("host OSC URL is %s\n", osc_url); 
    315   lo_server_add_method(control_ptr->osc_server, NULL, NULL, osc_message_handler, control_ptr); 
    316  
    317   if (fork() == 0) 
    318   { 
     260 
     261  switch (vfork()) 
     262  { 
     263  case 0:                       /* child process */ 
     264    /* fork duplicated the handles, close pipe ends that are used by parent process */ 
     265    /* it looks we cant do this for vfork() */ 
     266    //close(pipe1[1]); 
     267    //close(pipe2[0]); 
     268 
    319269    execlp( 
    320270      "python", 
    321271      "python", 
    322272      filename, 
    323       osc_url, 
    324273      plugin_uri, 
    325274      bundle_path, 
    326275      ui_host_ptr->plugin_human_id != NULL ? ui_host_ptr->plugin_human_id : "", 
     276      ui_recv_pipe,             /* reading end */ 
     277      ui_send_pipe,             /* writting end */ 
    327278      NULL); 
    328279    fprintf(stderr, "exec of UI failed: %s", strerror(errno)); 
    329280    exit(1); 
    330   } 
    331  
    332   while (!control_ptr->running) 
    333   { 
    334     if (lo_server_recv_noblock(control_ptr->osc_server, 0) == 0) 
    335     { 
    336       usleep(300000); 
    337     } 
    338   } 
     281  case -1: 
     282    fprintf(stderr, "fork() failed to create new process for plugin UI"); 
     283    goto fail_free_control; 
     284  } 
     285 
     286  /* fork duplicated the handles, close pipe ends that are used by the child process */ 
     287  close(pipe1[0]); 
     288  close(pipe2[1]); 
     289 
     290  control_ptr->send_pipe = pipe1[1]; /* [1] means writting end */ 
     291  control_ptr->recv_pipe = pipe2[0]; /* [0] means reading end */ 
     292 
     293  oldflags = fcntl(control_ptr->recv_pipe, F_GETFL); 
     294  fcntl(control_ptr->recv_pipe, F_SETFL, oldflags | O_NONBLOCK); 
    339295 
    340296  *widget = (LV2UI_Widget)control_ptr; 
     
    369325  const void * buffer) 
    370326{ 
     327  char buf[100]; 
     328  int len; 
     329  char * locale; 
     330 
    371331  //printf("port_event(%u, %f) called\n", (unsigned int)port_index, *(float *)buffer); 
    372332 
    373   lo_send(control_ptr->osc_address, control_ptr->osc_control_path, "if", (int)port_index, *(float *)buffer); 
     333  locale = strdup(setlocale(LC_NUMERIC, NULL)); 
     334  setlocale(LC_NUMERIC, "POSIX"); 
     335 
     336  write(control_ptr->send_pipe, "port_value\n", 11); 
     337  len = sprintf(buf, "%u\n", (unsigned int)port_index); 
     338  write(control_ptr->send_pipe, buf, len); 
     339  len = sprintf(buf, "%.10f\n", *(float *)buffer); 
     340  write(control_ptr->send_pipe, buf, len); 
     341  fsync(control_ptr->send_pipe); 
     342 
     343  setlocale(LC_NUMERIC, locale); 
     344  free(locale); 
    374345} 
    375346 
  • ui

    r1e11982 r51bb400  
    1919 
    2020import sys 
     21import os 
     22import fcntl 
    2123import gtk 
    2224import gobject 
     
    2426from math import pi, sin, cos, atan2, log, sqrt, hypot, log10 
    2527from colorsys import hls_to_rgb, rgb_to_hls 
    26 import liblo 
    2728 
    2829def map_coords_linear(x,y): 
     
    874875        self.invalidate_all() 
    875876 
    876 class dssi_ui: 
     877class filter_ui: 
    877878    def __init__(self, argv): 
    878879        self.fake = len(argv) == 1 
     
    885886 
    886887        #print repr(argv) 
    887         self.host_osc_url = argv[1] 
    888         self.plugin_uri = argv[2] 
    889         self.bundle_path = argv[3] 
    890         self.human_id = argv[4] 
    891  
    892         self.server = liblo.Server() 
    893         self.server.add_method(None, None, self.on_osc) 
    894         self.send_update() 
    895  
    896     def send_update(self): 
    897         if self.fake: 
    898             return 
    899         #print "UI -> update -> host" 
    900         liblo.send(self.host_osc_url, "//update", self.server.get_url()) 
    901  
    902     def send_port_value(self, port_index, value): 
    903         if self.fake: 
    904             return 
    905         liblo.send(self.host_osc_url, "//control", int(port_index), float(value)) 
    906  
    907     def send_exiting(self): 
    908         if self.fake: 
    909             return 
    910         liblo.send(self.host_osc_url, "//exiting") 
    911  
    912     def run(self): 
    913         if self.fake: 
    914             if not self.shown: 
    915                 self.shown = True 
    916                 self.on_show() 
    917             return 
    918  
    919         while self.server.recv(0): 
    920             pass 
    921  
    922     def on_osc(self, path, args, types): 
    923         if path == "/control" and types == "if": 
    924             self.on_port_value_changed(args[0], args[1]) 
    925         elif path == "/show" and types == "": 
    926             self.on_show() 
    927         elif path == "/hide" and types == "": 
    928             self.on_hide() 
    929         elif path == "/quit" and types == "": 
    930             self.on_quit() 
    931         else: 
    932             print "Unhandled OSC message. path='%s' types='%s', args=%s" % (path, types, repr(args)) 
    933  
    934     def on_port_value_changed(self, port_index, port_value): 
    935         return 
    936  
    937     def on_show(self): 
    938         return 
    939  
    940     def on_hide(self): 
    941         return 
    942  
    943     def on_quit(self): 
    944         return 
    945  
    946 class filter_ui(dssi_ui): 
    947     def __init__(self, argv): 
    948         dssi_ui.__init__(self, argv) 
     888        self.plugin_uri = argv[1] 
     889        self.bundle_path = argv[2] 
     890        self.human_id = argv[3] 
     891 
     892        self.recv_pipe_fd = int(argv[4]) 
     893        self.send_pipe_fd = int(argv[5]) 
     894 
     895        oldflags = fcntl.fcntl(self.recv_pipe_fd, fcntl.F_GETFL) 
     896        fcntl.fcntl(self.recv_pipe_fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK) 
     897 
     898        self.recv_pipe = os.fdopen(self.recv_pipe_fd, 'r') 
     899        self.send_pipe = os.fdopen(self.send_pipe_fd, 'w') 
    949900 
    950901        if self.plugin_uri == "http://nedko.aranaudov.org/soft/filter/2/mono": 
     
    11881139            self.send_port_value(port_index + self.port_base, value) 
    11891140 
     1141    def send(self, lines): 
     1142        for line in lines: 
     1143            #print 'send: "' + line + '"' 
     1144            self.send_pipe.write(line + "\n") 
     1145            self.send_pipe.flush() 
     1146 
     1147    def send_exiting(self): 
     1148        self.send(["exiting"]) 
     1149 
     1150    def send_port_value(self, port_index, value): 
     1151        self.send(["port_value", str(port_index), "%.10f" % value]) 
     1152 
     1153    def recv_line(self): 
     1154        return self.recv_pipe.readline().strip() 
     1155 
     1156    def recv_command(self): 
     1157        try: 
     1158            msg = self.recv_line() 
     1159 
     1160            if msg == "port_value": 
     1161                port_index = int(self.recv_line()) 
     1162                port_value = float(self.recv_line()) 
     1163                #print "port_value_change recevied: %d %f" % (port_index, port_value) 
     1164                self.on_port_value_changed(port_index, port_value) 
     1165            elif msg == "show": 
     1166                self.on_show() 
     1167            elif msg == "hide": 
     1168                self.on_hide() 
     1169            elif msg == "quit": 
     1170                self.on_quit() 
     1171            else: 
     1172                print 'unknown message: "' + msg + '"' 
     1173 
     1174            return True 
     1175        except IOError: 
     1176            return False 
     1177 
     1178    def on_recv(self, fd, cond): 
     1179        #print "on_recv" 
     1180        if cond == gobject.IO_HUP: 
     1181            gtk.main_quit() 
     1182            return False 
     1183 
     1184        while True: 
     1185            if not self.recv_command(): 
     1186                break 
     1187 
     1188        return True 
     1189 
    11901190    def run(self): 
    11911191        self.window.connect("destroy", self.on_window_closed) 
    1192         gobject.timeout_add(50, self.on_idle) 
     1192 
     1193        if self.fake: 
     1194            if not self.shown: 
     1195                self.shown = True 
     1196                self.on_show() 
     1197        else: 
     1198            gobject.io_add_watch(self.recv_pipe_fd, gobject.IO_IN | gobject.IO_HUP, self.on_recv) 
     1199 
    11931200        gtk.main() 
    1194  
    1195     def on_idle(self): 
    1196         dssi_ui.run(self) 
    1197         return True 
    11981201 
    11991202    def on_port_value_changed(self, port_index, port_value):