I would like to serve a growing audio file (raw PCM audio for now) with the possibility of seeking. I tried to manage it with Apache, but in the end wasn't able to achieve what I wanted.
Now I managed to come up with a solution within Django that seems to work quite nicely. Basically I created a view that delivers a part of the file and then sends a response with status code 206 and Content-Range header.
### DJANGO VIEW
MAX_CHUNK_SIZE = 32000
HEADER_PATH = "/path/to/header.wav"
MAX_WAV_LENGTH = 4294967303
BYTES_PER_SECOND = 32000
def get_audio(request, file_name):
# get offset
pos = int(request.GET.get("pos", 0))
offset = pos * BYTES_PER_SECOND
# get range
r = request.META["HTTP_RANGE"]
start = int(r.replace("bytes=", "").split("-")[0])
start_o = start + offset
# in case this is the first request, a wave header is added
if start == 0:
with open(HEADER_PATH, "rb") as f:
data = f.read()
length = 44
else:
data = ""
length = 0
start_o -= 44
file_path = join(settings.STREAMS_DIR, file_name)
# wait up to 10 seconds if the end of the file is reached
# (in case it grows more)
for _ in range(10):
size = getsize(file_path)
if size - start_o > 0:
break
else:
sleep(1)
length += min(MAX_CHUNK_SIZE, size - start_o)
# if the length is zero (if end of file is reached and there is
# nothing more to server), set the total length to the actual
# served length
if length == 0:
total = size - offset + 44
# else, set the total length to the maximum possible wav length
# so that the browsers know that it has to send subsequent requests
else:
total = MAX_WAV_LENGTH
# get the actual data from the raw audio file
with open(file_path, "rb") as f:
f.seek(start_o)
data += f.read(length)
# send response with use of Content-Range
resp = HttpResponse(data, content_type="audio/x-wav", status=206)
resp["Content-Range"] = "bytes " + str(start) + "-" + str(start + length) + "/" + str(total)
return resp
In the browser, I can then simply request my audio like in the following way, to make it play from any point:
var fileName = "xyz.wav";
var start = 25; //seconds
audio = new Audio();
audio.src = "/getAudio/" + fileName + "?pos=" + start;
audio.play();
As I said, this all seems to work pretty well. But I would like to know this is a valid approach that I can use in production or if there are some major problems that I am not aware of.