Trying to serve HTML5 <audio> element from Python+SSL to Android Chrome -
i have python-based web application server; great plain http. https, works browsers--except android chrome. chrome, html , icons fine on https, <audio> element fails start. see chrome pull 1 initial byte of mp3 (presumably way of testing file presence), served it. , chrome greys out <audio>
element.
i've pulled same single byte using curl, , works fine:
curl -r 0-1 -k https://localhost:8083/foo.mp3 > foo1.mp3
i've added various delays , flushes, without fixing problem.
it seem not content-range issue, i've changed code return full mp3 (with 200 code), same chrome behavior.
firefox happy (both android , linux), midori (a webkit based browser). on linux, chrome/chromium both happy it. android chrome--no luck.
i've extracted relevant bits of code; i'm assuming there's http nicety i'm missing (and, believe me, i've been looking). exercise it, plug in self-signed certificate pair @ hard-coded files "server.key" , "server.crt". put mp3 of choice @ "foo.mp3" , point browser at:
https://localhost:8083
tia suggestions! i'm sorry code runs little long; extracted bits reproduce this. left off range support, didn't want chase legacy code paths of chrome.
# # debug.py # sample code snippet debug chrome html5 <audio> ssl problem # import pdb import sys, socket, ssl, threading, os, time basehttpserver import basehttprequesthandler ourmp3 = "foo.mp3" # decode "range:" header option, return # (offset,length) or none if don't # region (tbd, multiple ranges , # multipart) # we're passed file's os.stat # range: field value. def decode_range(st, range): # byte units, please if not range.startswith("bytes="): return none range = range[6:] # single range if ',' in range: return none # start offset if range[0] == '-': range = range[1:] if not range.isdigit(): return none val1 = int(range) if val1 >= st.st_size: return none return (0, val1) # offset end... elif range[-1] == '-': range = range[:-1] if not range.isdigit(): return none val2 = int(range) if val2 >= st.st_size: return none return (val2, st.st_size - val2) # offset1 offset2 else: parts = range.split('-') if len(parts) != 2: return none if not all(p.isdigit() p in parts): return none val1 = int(parts[0]) val2 = int(parts[1]) if val1 >= val2: return none return (val1, val2-val1) class client(basehttprequesthandler): # send mp3 file ourmp3 def send_mp3(self): # simplicity, big buffer f = open(ourmp3, "rb") st = os.fstat(f.fileno()) buf = f.read() f.close() # partial ranged = 'range' in self.headers if ranged: tup = decode_range(st, self.headers['range']) assert tup startoff,nbyte = tup assert (nbyte + startoff) <= len(buf) self.send_response(206) else: startoff = 0 nbyte = len(buf) self.send_response(200) # headers self.send_response(200) self.send_header("content-type", "audio/mpeg") self.send_header("content-length", nbyte) if ranged: self.send_header("content-range", "bytes %d-%d/%d" % (startoff, startoff+nbyte-1, st.st_size)) self.send_header("last-modified", time.asctime(time.localtime(st.st_mtime))) self.end_headers() # let our upper layers write (or discard # it, head) return buf[startoff:(startoff+nbyte)] # send html5 <audio> player our mp3 def send_root(self): buf = \ ''' <html><head><title>test mp3</title></head>\r audio player:<br>\r <body><audio src="foo.mp3" controls autoplay></audio></body>\r </html>\r ''' self.send_response(200) self.send_header("content-type", "text/html") self.send_header("content-length", len(buf)) self.end_headers() return buf # process http get's def do_get(self): sys.stderr.write("get %r\n" % (self.path,)) path = self.path # root; our html play mp3 if (not path) or (path == '/'): buf = self.send_root() # our mp3 elif path.endswith(ourmp3): buf = self.send_mp3() # that's serve else: self.send_error(404) return none # body? if buf: self.wfile.write(buf) # dispatch web client def serve_client(conn, tup): h = client(conn, tup, none) conn.close() sys.exit(0) # endless server loop on port 8083 def server(): s = socket.socket(socket.af_inet, socket.sock_stream) s = ssl.wrap_socket(s, "server.key", "server.crt", server_side=true, suppress_ragged_eofs=false, do_handshake_on_connect=false) s.bind( ("", 8083) ) s.listen(10) while true: conn,tup = s.accept() sys.stderr.write("client %r\n" % (tup,)) conn.do_handshake() t = threading.thread(target=serve_client, args=(conn,tup)) t.start() if __name__ == "__main__": server()
Comments
Post a Comment