blob: fd983d39adfbcd80b4b2eece390b1fdba6b9cccf [file] [log] [blame]
Guido van Rossum50692d61991-09-15 21:05:15 +00001# 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
Guido van Rossum5b397961991-09-15 21:26:44 +000010from names import *
Guido van Rossum50692d61991-09-15 21:05:15 +000011import sys, time, posix, gl, fl, FL, al, AL, getopt, rand
12from socket import *
13
Guido van Rossum50692d61991-09-15 21:05:15 +000014# UDP port numbers used (one for each direction!)
15PORT1 = 51042
16PORT2 = PORT1+1
17
18# Figure out the user name
19try:
20 user = posix.environ['LOGNAME']
21except:
22 user = posix.environ['USER']
23
24# Debug flags (Implemented as a list; non-empty means debugging is on)
25debug = []
26
27def main():
28 remote = 0
29 opts, args = getopt.getopt(sys.argv[1:], 'rd')
30 for opt, arg in opts:
Guido van Rossum14f43cf1992-03-30 13:30:03 +000031 if opt == '-r': remote = 1
32 elif opt == '-d': debug.append(opt)
Guido van Rossum50692d61991-09-15 21:05:15 +000033 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
43def client(hostname):
44 print 'client starting'
45 cmd = 'rsh ' + hostname + ' "cd ' + AUDIODIR
46 cmd = cmd + '; DISPLAY=:0; export DISPLAY'
Guido van Rossum488b7d91991-12-24 13:55:16 +000047 cmd = cmd + '; ' + PYTHON + ' intercom.py -r '
Guido van Rossum50692d61991-09-15 21:05:15 +000048 for flag in debug: cmd = cmd + flag + ' '
49 cmd = cmd + gethostname()
50 cmd = cmd + '"'
Guido van Rossum488b7d91991-12-24 13:55:16 +000051 if debug: print cmd
Guido van Rossum50692d61991-09-15 21:05:15 +000052 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)
Guido van Rossum14f43cf1992-03-30 13:30:03 +000059 if line == 'NAK\n':
Guido van Rossum50692d61991-09-15 21:05:15 +000060 nak = 1
61 break
Guido van Rossum14f43cf1992-03-30 13:30:03 +000062 elif line == 'ACK\n':
Guido van Rossum50692d61991-09-15 21:05:15 +000063 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:
Guido van Rossum6f1f3911992-04-17 16:32:53 +000079 try:
80 ioloop(s, otheraddr)
81 except KeyboardInterrupt:
82 log('client got intr')
83 except error:
84 log('client got error')
Guido van Rossum50692d61991-09-15 21:05:15 +000085 finally:
86 s.sendto('', otheraddr)
87 log('client finished sending empty packet to server')
88 #
89 log('client exit')
90 print 'Done.'
91
92def 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
121def 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
129def 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
Guido van Rossum14f43cf1992-03-30 13:30:03 +0000139 elif params[i] == AL.INPUT_SOURCE:
Guido van Rossum50692d61991-09-15 21:05:15 +0000140 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
147def 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)
Guido van Rossum14f43cf1992-03-30 13:30:03 +0000170 if len(data) == 0:
Guido van Rossum50692d61991-09-15 21:05:15 +0000171 # 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:
Guido van Rossume2663441992-12-14 15:05:16 +0000184 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)
Guido van Rossum50692d61991-09-15 21:05:15 +0000200 finally:
201 log('child got unexpected error; leaving w/ traceback')
202
203def 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
212main()