home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / sgi / al / intercom.py < prev    next >
Text File  |  1992-12-14  |  5KB  |  213 lines

  1. # intercom -- use mike and headset to *talk* to a person on another host.
  2. # For SGI 4D/35 or Indigo running IRIX 4.0.
  3. # Uses 16 bit sampling at 16000 samples/sec, or 32000 bytes/sec,
  4. # tranmitted in 32 1000-byte UDP packets.  (In each direction!)
  5. #
  6. # usage:
  7. #    intercom hostname    - start talking to person on other host
  8. #    intercom -r hostname    - called remotely to do the setup
  9.  
  10. from names import *
  11. import sys, time, posix, gl, fl, FL, al, AL, getopt, rand
  12. from socket import *
  13.  
  14. # UDP port numbers used (one for each direction!)
  15. PORT1 = 51042
  16. PORT2 = PORT1+1
  17.  
  18. # Figure out the user name
  19. try:
  20.     user = posix.environ['LOGNAME']
  21. except:
  22.     user = posix.environ['USER']
  23.  
  24. # Debug flags (Implemented as a list; non-empty means debugging is on)
  25. debug = []
  26.  
  27. def main():
  28.     remote = 0
  29.     opts, args = getopt.getopt(sys.argv[1:], 'rd')
  30.     for opt, arg in opts:
  31.         if opt == '-r': remote = 1
  32.         elif opt == '-d': debug.append(opt)
  33.     if len(args) <> 1:
  34.         msg = 'usage: intercom [-d] [-r] hostname'
  35.         msg = msg + ' (-r is for internal use only!)\n'
  36.         sys.stderr.write(msg)
  37.         sys.exit(2)
  38.     if remote:
  39.         server(args[0])
  40.     else:
  41.         client(args[0])
  42.  
  43. def client(hostname):
  44.     print 'client starting'
  45.     cmd = 'rsh ' + hostname + ' "cd ' + AUDIODIR
  46.     cmd = cmd + '; DISPLAY=:0; export DISPLAY'
  47.     cmd = cmd + '; ' + PYTHON + ' intercom.py -r '
  48.     for flag in debug: cmd = cmd + flag + ' '
  49.     cmd = cmd + gethostname()
  50.     cmd = cmd + '"'
  51.     if debug: print cmd
  52.     pipe = posix.popen(cmd, 'r')
  53.     ack = 0
  54.     nak = 0
  55.     while 1:
  56.         line = pipe.readline()
  57.         if not line: break
  58.         sys.stdout.write('remote: ' + line)
  59.         if line == 'NAK\n':
  60.             nak = 1
  61.             break
  62.         elif line == 'ACK\n':
  63.             ack = 1
  64.             break
  65.     if nak:
  66.         print 'Remote user doesn\'t want to talk to you.'
  67.         return
  68.     if not ack:
  69.         print 'No acknowledgement (remote side crashed?).'
  70.         return
  71.     #
  72.     print 'Ready...'
  73.     #
  74.     s = socket(AF_INET, SOCK_DGRAM)
  75.     s.bind('', PORT2)
  76.     #
  77.     otheraddr = gethostbyname(hostname), PORT1
  78.     try:
  79.         try:
  80.             ioloop(s, otheraddr)
  81.         except KeyboardInterrupt:
  82.             log('client got intr')
  83.         except error:
  84.             log('client got error')
  85.     finally:
  86.         s.sendto('', otheraddr)
  87.         log('client finished sending empty packet to server')
  88.     #
  89.     log('client exit')
  90.     print 'Done.'
  91.  
  92. def server(hostname):
  93.     print 'server starting'
  94.     sys.stdout.flush()
  95.     # 
  96.     if not remotedialog():
  97.         print 'NAK'
  98.         return
  99.     #
  100.     print 'ACK'
  101.     #
  102.     s = socket(AF_INET, SOCK_DGRAM)
  103.     s.bind('', PORT1)
  104.     #
  105.     # Close std{in,out,err} so rsh will exit; reopen them as dummies
  106.     #
  107.     sys.stdin.close()
  108.     sys.stdin = open('/dev/null', 'r')
  109.     sys.stdout.close()
  110.     sys.stdout = open('/dev/null', 'w')
  111.     sys.stderr.close()
  112.     if debug:
  113.         sys.stderr = open('/tmp/intercom.err', 'a')
  114.     else:
  115.         sys.stderr = open('/dev/null', 'w')
  116.     #
  117.     ioloop(s, (gethostbyname(hostname), PORT2))
  118.     log('server exit')
  119.     sys.exit(0)
  120.  
  121. def remotedialog():
  122.     gl.foreground()
  123.     gl.ringbell()
  124.     m1 = user + ' wants to talk to you over the audio channel.'
  125.     m2 = 'If it\'s OK, put on your headset and click Yes.'
  126.     m3 = 'If you\'re too busy, click No.'
  127.     return fl.show_question(m1, m2, m3)
  128.  
  129. def ioloop(s, otheraddr):
  130.     #
  131.     dev = AL.DEFAULT_DEVICE
  132.     params = al.queryparams(dev)
  133.     al.getparams(dev, params)
  134.     time.sleep(1)
  135.     saveparams = params[:]
  136.     for i in range(0, len(params), 2):
  137.         if params[i] in (AL.INPUT_RATE, AL.OUTPUT_RATE):
  138.             params[i+1] = AL.RATE_16000
  139.         elif params[i] == AL.INPUT_SOURCE:
  140.             params[i+1] = AL.INPUT_MIC
  141.     try:
  142.         al.setparams(dev, params)
  143.         ioloop1(s, otheraddr)
  144.     finally:
  145.         al.setparams(dev, saveparams)
  146.  
  147. def ioloop1(s, otheraddr):
  148.     #
  149.     # Watch out! data is in bytes, but the port counts in samples,
  150.     # which are two bytes each (for 16-bit samples).
  151.     # Luckily, we use mono, else it would be worse (2 samples/frame...)
  152.     #
  153.     SAMPSPERBUF = 500
  154.     BYTESPERSAMP = 2 # AL.SAMPLE_16
  155.     BUFSIZE = BYTESPERSAMP*SAMPSPERBUF
  156.     QSIZE = 4*SAMPSPERBUF
  157.     #
  158.     config = al.newconfig()
  159.     config.setqueuesize(QSIZE)
  160.     config.setwidth(AL.SAMPLE_16)
  161.     config.setchannels(AL.MONO)
  162.     #
  163.     pid = posix.fork()
  164.     if pid:
  165.         # Parent -- speaker/headphones handler
  166.         log('parent started')
  167.         spkr = al.openport('spkr', 'w', config)
  168.         while 1:
  169.             data = s.recv(BUFSIZE)
  170.             if len(data) == 0:
  171.                 # EOF packet
  172.                 log('parent got empty packet; killing child')
  173.                 posix.kill(pid, 15)
  174.                 return
  175.             # Discard whole packet if we are too much behind
  176.             if spkr.getfillable() > len(data) / BYTESPERSAMP:
  177.                 if len(debug) >= 2:
  178.                     log('parent Q full; dropping packet')
  179.                 spkr.writesamps(data)
  180.     else:
  181.         # Child -- microphone handler
  182.         log('child started')
  183.         try:
  184.             try:
  185.                 mike = al.openport('mike', 'r', config)
  186.                 # Sleep a while to let the other side get started
  187.                 time.sleep(1)
  188.                 # Drain the queue before starting to read
  189.                 data = mike.readsamps(mike.getfilled())
  190.                 # Loop, sending packets from the mike to the net
  191.                 while 1:
  192.                     data = mike.readsamps(SAMPSPERBUF)
  193.                     s.sendto(data, otheraddr)
  194.             except KeyboardInterrupt:
  195.                 log('child got interrupt; exiting')
  196.                 posix._exit(0)
  197.             except error:
  198.                 log('child got error; exiting')
  199.                 posix._exit(1)
  200.         finally:
  201.             log('child got unexpected error; leaving w/ traceback')
  202.  
  203. def log(msg):
  204.     if not debug: return
  205.     if type(msg) <> type(''):
  206.         msg = `msg`
  207.     
  208.     f = open('/tmp/intercom.log', 'a')
  209.     f.write(`sys.argv` + ' ' + `posix.getpid()` + ': ' + msg + '\n')
  210.     f.close()
  211.  
  212. main()
  213.