2 # -*- coding: utf-8 -*-
4 # Copyright (c) 2019 Niklas Ekström
14 fcntl.F_SETPIPE_SZ = 1031
16 logging.basicConfig(format = '%(levelname)s, %(asctime)s, %(name)s, line %(lineno)d: %(message)s')
17 logger = logging.getLogger(__name__)
18 logger.setLevel(logging.INFO)
22 MSG_DEREGISTER_REQ = 3
23 MSG_DEREGISTER_RES = 4
29 MSG_CONNECT_RESPONSE = 10
36 while len(header) < 9:
37 data = drv.recv(9 - len(header))
39 logger.error('Connection to a314d was closed, terminating.')
42 (plen, stream_id, ptype) = struct.unpack('=IIB', header)
44 while len(payload) < plen:
45 data = drv.recv(plen - len(payload))
47 logger.error('Connection to a314d was closed, terminating.')
50 return (stream_id, ptype, payload)
52 def send_register_req(name):
53 m = struct.pack('=IIB', len(name), 0, MSG_REGISTER_REQ) + name
56 def send_read_mem_req(address, length):
57 m = struct.pack('=IIBII', 8, 0, MSG_READ_MEM_REQ, address, length)
60 def read_mem(address, length):
61 send_read_mem_req(address, length)
62 stream_id, ptype, payload = wait_for_msg()
63 if ptype != MSG_READ_MEM_RES:
64 logger.error('Expected MSG_READ_MEM_RES but got %s. Shutting down.', ptype)
68 def send_write_mem_req(address, data):
69 m = struct.pack('=IIBI', 4 + len(data), 0, MSG_WRITE_MEM_REQ, address) + data
72 def write_mem(address, data):
73 send_write_mem_req(address, data)
74 stream_id, ptype, payload = wait_for_msg()
75 if ptype != MSG_WRITE_MEM_RES:
76 logger.error('Expected MSG_WRITE_MEM_RES but got %s. Shutting down.', ptype)
79 def send_connect_response(stream_id, result):
80 m = struct.pack('=IIBB', 1, stream_id, MSG_CONNECT_RESPONSE, result)
83 def send_data(stream_id, data):
84 m = struct.pack('=IIB', len(data), stream_id, MSG_DATA) + data
87 def send_eos(stream_id):
88 m = struct.pack('=IIB', 0, stream_id, MSG_EOS)
91 def send_reset(stream_id):
92 m = struct.pack('=IIB', 0, stream_id, MSG_RESET)
95 current_stream_id = None
98 is_empty = [True, True]
100 def process_msg_data(payload):
101 global ptrs, first_msg, raw_received
104 ptrs = struct.unpack('>II', payload)
105 logger.debug('Received pointers %s', ptrs)
109 buf_index = payload[0]
111 if len(raw_received) < 900*2:
112 if not is_empty[buf_index]:
113 data = b'\x00' * (900*2)
114 send_write_mem_req(ptrs[buf_index], data)
115 is_empty[buf_index] = True
117 ldata = raw_received[0:900*2:2]
118 rdata = raw_received[1:900*2:2]
120 raw_received = raw_received[900*2:]
121 send_write_mem_req(ptrs[buf_index], data)
122 is_empty[buf_index] = False
124 def process_drv_msg(stream_id, ptype, payload):
125 global current_stream_id, first_msg
127 if ptype == MSG_CONNECT:
128 if payload == b'piaudio' and current_stream_id is None:
129 logger.info('Amiga connected')
130 current_stream_id = stream_id
132 send_connect_response(stream_id, 0)
134 send_connect_response(stream_id, 3)
135 elif current_stream_id == stream_id:
136 if ptype == MSG_DATA:
137 process_msg_data(payload)
138 elif ptype == MSG_EOS:
140 elif ptype == MSG_RESET:
141 current_stream_id = None
142 logger.info('Amiga disconnected')
147 idx = sys.argv.index('-ondemand')
152 fd = int(sys.argv[idx + 1])
153 drv = socket.socket(fileno=fd)
155 drv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
156 drv.connect(('localhost', 7110))
157 drv.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
159 send_register_req(b'piaudio')
160 _, _, payload = wait_for_msg()
162 logger.error('Unable to register piaudio with driver, shutting down')
168 PIPE_NAME = '/tmp/piaudio_pipe'
173 if (os.stat(PIPE_NAME).st_mode & 0o170000) != 0o10000:
174 logger.error('A file that is not a named pipe exists at ' + PIPE_NAME)
179 if not done and not exists:
183 logger.error('Unable to create named pipe at ' + PIPE_NAME)
188 pipe_fd = os.open(PIPE_NAME, os.O_RDONLY | os.O_NONBLOCK)
189 fcntl.fcntl(pipe_fd, fcntl.F_SETPIPE_SZ, 4096)
191 logger.error('Unable to open named pipe at ' + PIPE_NAME)
195 logger.info('piaudio service is running')
201 sel_fds.append(sys.stdin)
203 if len(raw_received) < 900*2:
204 sel_fds.append(pipe_fd)
206 rfd, wfd, xfd = select.select(sel_fds, [], [], 5.0)
210 line = sys.stdin.readline()
211 if not line or line.startswith('quit'):
212 if current_stream_id is not None:
213 send_reset(current_stream_id)
219 if current_stream_id is not None:
220 send_reset(current_stream_id)
229 (plen, stream_id, ptype) = struct.unpack('=IIB', rbuf[:9])
230 if len(rbuf) < 9 + plen:
234 payload = rbuf[:plen]
237 process_drv_msg(stream_id, ptype, payload)
239 data = os.read(pipe_fd, 900*2)
244 l = len(raw_received)
247 raw_received += b'\x00' * ((c + 1) * 900*2 - l)
249 pipe_fd = os.open(PIPE_NAME, os.O_RDONLY | os.O_NONBLOCK)
250 fcntl.fcntl(pipe_fd, fcntl.F_SETPIPE_SZ, 4096)