I'm running the esp-adf pipeline_raw_http example and I'm trying to reimplement the server.py in flask. the esp board sends out the wav audio stream using http stream with the following code:
esp_err_t _http_stream_event_handle(http_stream_event_msg_t *msg)
{
esp_http_client_handle_t http = (esp_http_client_handle_t)msg->http_client;
char len_buf[16];
static int total_write = 0;
if (msg->event_id == HTTP_STREAM_PRE_REQUEST)
{
// set header
ESP_LOGI(TAG, "[ + ] HTTP client HTTP_STREAM_PRE_REQUEST, lenght=%d", msg->buffer_len);
esp_http_client_set_method(http, HTTP_METHOD_POST);
char dat[10] = {0};
snprintf(dat, sizeof(dat), "%d", EXAMPLE_AUDIO_SAMPLE_RATE);
esp_http_client_set_header(http, "x-audio-sample-rates", dat);
memset(dat, 0, sizeof(dat));
snprintf(dat, sizeof(dat), "%d", EXAMPLE_AUDIO_BITS);
esp_http_client_set_header(http, "x-audio-bits", dat);
memset(dat, 0, sizeof(dat));
snprintf(dat, sizeof(dat), "%d", EXAMPLE_AUDIO_CHANNELS);
esp_http_client_set_header(http, "x-audio-channel", dat);
total_write = 0;
return ESP_OK;
}
if (msg->event_id == HTTP_STREAM_ON_REQUEST)
{
// write data
int wlen = sprintf(len_buf, "%x\r\n", msg->buffer_len);
if (esp_http_client_write(http, len_buf, wlen) <= 0)
{
return ESP_FAIL;
}
if (esp_http_client_write(http, msg->buffer, msg->buffer_len) <= 0)
{
return ESP_FAIL;
}
if (esp_http_client_write(http, "\r\n", 2) <= 0)
{
return ESP_FAIL;
}
total_write += msg->buffer_len;
printf("\033[A\33[2K\rTotal bytes written: %d\n", total_write);
return msg->buffer_len;
}
if (msg->event_id == HTTP_STREAM_POST_REQUEST)
{
ESP_LOGI(TAG, "[ + ] HTTP client HTTP_STREAM_POST_REQUEST, write end chunked marker");
if (esp_http_client_write(http, "0\r\n\r\n", 5) <= 0)
{
return ESP_FAIL;
}
return ESP_OK;
}
if (msg->event_id == HTTP_STREAM_FINISH_REQUEST)
{
ESP_LOGI(TAG, "[ + ] HTTP client HTTP_STREAM_FINISH_REQUEST");
char *buf = calloc(1, 64);
assert(buf);
int read_len = esp_http_client_read(http, buf, 64);
if (read_len <= 0)
{
free(buf);
return ESP_FAIL;
}
buf[read_len] = 0;
ESP_LOGI(TAG, "Got HTTP Response = %s", (char *)buf);
free(buf);
return ESP_OK;
}
return ESP_OK;
}
the default server.py receives the stream with:
class Handler(BaseHTTPRequestHandler):
def _set_headers(self, length):
self.send_response(200)
if length > 0:
self.send_header('Content-length', str(length))
self.end_headers()
def _get_chunk_size(self):
data = self.rfile.read(2)
while data[-2:] != b"\r\n":
data += self.rfile.read(1)
return int(data[:-2], 16)
def _get_chunk_data(self, chunk_size):
data = self.rfile.read(chunk_size)
self.rfile.read(2)
return data
def _write_wav(self, data, rates, bits, ch):
t = datetime.datetime.utcnow()
time = t.strftime('%Y%m%dT%H%M%SZ')
filename = str.format('{}_{}_{}_{}.wav', time, rates, bits, ch)
wavfile = wave.open(filename, 'wb')
wavfile.setparams((ch, int(bits/8), rates, 0, 'NONE', 'NONE'))
wavfile.writeframesraw(bytearray(data))
wavfile.close()
return filename
def do_POST(self):
urlparts = parse.urlparse(self.path)
request_file_path = urlparts.path.strip('/')
total_bytes = 0
sample_rates = 0
bits = 0
channel = 0
print("Do Post......")
if (request_file_path == 'upload'
and self.headers.get('Transfer-Encoding', '').lower() == 'chunked'):
data = []
sample_rates = self.headers.get('x-audio-sample-rates', '').lower()
bits = self.headers.get('x-audio-bits', '').lower()
channel = self.headers.get('x-audio-channel', '').lower()
sample_rates = self.headers.get('x-audio-sample-rates', '').lower()
print("Audio information, sample rates: {}, bits: {}, channel(s): {}".format(sample_rates, bits, channel))
# https://stackoverflow.com/questions/24500752/how-can-i-read-exactly-one-response-chunk-with-pythons-http-client
while True:
chunk_size = self._get_chunk_size()
total_bytes += chunk_size
print("Total bytes received: {}".format(total_bytes))
sys.stdout.write("\033[F")
if (chunk_size == 0):
break
else:
chunk_data = self._get_chunk_data(chunk_size)
data += chunk_data
filename = self._write_wav(data, int(sample_rates), int(bits), int(channel))
self.send_response(200)
self.send_header("Content-type", "text/html;charset=utf-8")
self.send_header("Content-Length", str(total_bytes))
self.end_headers()
body = 'File {} was written, size {}'.format(filename, total_bytes)
self.wfile.write(body.encode('utf-8'))
I searched online but I can't find the flask equivalent of the rfile.read() in the _get_chunk_size(self): function, I tried with the request.stream.read() and the request.input_stream.read(), but the encoding wasn't right, the output of rfile.read(2) is b'10' and the datatype is bytes, when the function returns the data will become b'1000\r\n'. however with the request.stream.read(2) the output is "b'\x1b\x00'", if I change the read(2) to read(100), the output is "b'\xdf\x00\xde\x00\xc2\x00\xe7\x00\xdf\x00\xb5\x00\xd6\x00\xc5\x00\xe1\x00\x99\x00\xcc\x00\xb3\x00\xa9\x00\x8b\x00\xa8\x00\x88\x00\xa3\x00\x95\x00\x80\x00\x80\x00\x8b\x00h\x00\xa4\x00F\x00}\x00L\x00\x85\x00B\x00}\x00P\x00\x89\x00I\x00`\x00i\x00\xa5\x00k\x00\xb4\x00u\x00\xb7\x00p\x00\xb3\x00t\x00\xcf\x00v\x00\xf9\x00\x9c\x00\xea\x00w\x00\xec\x00u\x00'". am I reading the wrong thing here?