ESP32 ADF as server to stream audio to browser?
Posted: Wed Mar 18, 2020 8:53 am
firefox browser supports opus codec.I changed this example https://github.com/espressif/esp-adf/tr ... e_raw_http to stream opus to server.The example connects to the server, but I need to be a server. DOES ADF HTTP Stream only supports client mode, or I'm wrong?
What to do next?
1.Start the server as in the examples for ESP32 IDF
2.How to direct there an audio stream?
Will I need to use Raw Stream?
What to do next?
1.Start the server as in the examples for ESP32 IDF
2.How to direct there an audio stream?
Will I need to use Raw Stream?
Code: Select all
/* Stream opus file to server
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_wifi.h"
//#include "esp_http_server.h"//must be a server
#include "esp_http_client.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_common.h"
#include "audio_hal.h"
#include "i2s_stream.h"
#include "opus_encoder.h"
#include "http_stream.h"
#include "esp_peripherals.h"
#include "periph_wifi.h"
#include "periph_button.h"
#include "board.h"
static const char *TAG = "REC_OPUS_SDCARD";
#define SAMPLE_RATE 16000
#define CHANNEL 1
#define BIT_RATE 64000
#define COMPLEXITY 10
//=================================================================================================//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//=================================================================================================//
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_header(http, "x-audio-sample-rates", "16000");
esp_http_client_set_header(http, "x-audio-bits", "16");
esp_http_client_set_header(http, "x-audio-channel", "1");
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;
}
//=================================================================================================//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//=================================================================================================//
void app_main(void)
{
audio_pipeline_handle_t pipeline;
audio_element_handle_t i2s_stream_reader, opus_encoder,http_stream_writer;/////????? fatfs_stream_writer,
esp_log_level_set("*", ESP_LOG_WARN);
esp_log_level_set(TAG, ESP_LOG_INFO);
ESP_LOGI(TAG, "[ 1 ] periph ini");
// Initialize peripherals management
esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
esp_periph_set_handle_t set = esp_periph_set_init(&periph_cfg);
//=================================================================================================//
//+++++++++++++++++++++++++++++++++++++++ wi-fi +++++++++++++++++++++++++++++++++++++++++++++++++++//
//=================================================================================================//
esp_err_t err = nvs_flash_init();
if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
ESP_ERROR_CHECK(nvs_flash_erase());
err = nvs_flash_init();
}
tcpip_adapter_init();
periph_wifi_cfg_t wifi_cfg = {
.ssid = CONFIG_WIFI_SSID,//CONFIG_WIFI_SSID
.password = CONFIG_WIFI_PASSWORD,//CONFIG_WIFI_PASSWORD
};
esp_periph_handle_t wifi_handle = periph_wifi_init(&wifi_cfg);
esp_periph_start(set, wifi_handle);
periph_wifi_wait_for_connected(wifi_handle, portMAX_DELAY);
//=================================================================================================//
//++++++++++++++++++++++++++++++++++++++ button +++++++++++++++++++++++++++++++++++++++++++++++++++//
//=================================================================================================//
periph_button_cfg_t btn_cfg = {
.gpio_mask = GPIO_SEL_36 | GPIO_SEL_39, //REC BTN & MODE BTN
};
esp_periph_handle_t button_handle = periph_button_init(&btn_cfg);
esp_periph_start(set, button_handle);
//=================================================================================================//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//=================================================================================================//
ESP_LOGI(TAG, "[ 2 ] Start codec chip");
audio_board_handle_t board_handle = audio_board_init();
audio_hal_ctrl_codec(board_handle->audio_hal, AUDIO_HAL_CODEC_MODE_ENCODE, AUDIO_HAL_CTRL_START);
ESP_LOGI(TAG, "[3.0] Create audio pipeline for recording");
audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
pipeline = audio_pipeline_init(&pipeline_cfg);
mem_assert(pipeline);
ESP_LOGI(TAG, "[3.1] Create http stream to post data to server");
http_stream_cfg_t http_cfg = HTTP_STREAM_CFG_DEFAULT();
http_cfg.type = AUDIO_STREAM_WRITER;
http_cfg.event_handle = _http_stream_event_handle;
http_stream_writer = http_stream_init(&http_cfg);
ESP_LOGI(TAG, "[3.2] Create i2s stream to read audio data from codec chip");
i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
i2s_cfg.type = AUDIO_STREAM_READER;
i2s_cfg.i2s_config.sample_rate = SAMPLE_RATE;
if (CHANNEL == 1) {
i2s_cfg.i2s_config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT;
} else {
i2s_cfg.i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
}
#if defined CONFIG_ESP_LYRAT_MINI_V1_1_BOARD
i2s_cfg.i2s_port = 1;
#endif
i2s_stream_reader = i2s_stream_init(&i2s_cfg);
ESP_LOGI(TAG, "[3.3] Create opus encoder to encode opus format");
opus_encoder_cfg_t opus_cfg = DEFAULT_OPUS_ENCODER_CONFIG();
opus_cfg.sample_rate = SAMPLE_RATE;
opus_cfg.channel = CHANNEL;
opus_cfg.bitrate = BIT_RATE;
opus_cfg.complexity = COMPLEXITY;
opus_encoder = encoder_opus_init(&opus_cfg);
ESP_LOGI(TAG, "[3.4] Register all elements to audio pipeline");//1 audio //2 codec //3 http
audio_pipeline_register(pipeline, i2s_stream_reader, "i2s");
audio_pipeline_register(pipeline, opus_encoder, "opus");
audio_pipeline_register(pipeline, http_stream_writer, "http");//*
ESP_LOGI(TAG, "[3.5] Link it together [codec_chip]-->i2s_stream-->opus_encoder-->http");
audio_pipeline_link(pipeline, (const char *[]) {"i2s", "opus", "http"}, 3);
ESP_LOGI(TAG, "[ 4 ] Setup event listener");
audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
audio_event_iface_handle_t evt = audio_event_iface_init(&evt_cfg);
ESP_LOGI(TAG, "[4.1] Listening event from pipeline");
audio_pipeline_set_listener(pipeline, evt);
ESP_LOGI(TAG, "[4.2] Listening event from peripherals");
audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);
while (1) {
audio_event_iface_msg_t msg;
esp_err_t ret = audio_event_iface_listen(evt, &msg, portMAX_DELAY);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
continue;
}
if (msg.source_type != PERIPH_ID_BUTTON) {
continue;
}
// It's not REC button
if ((int)msg.data == GPIO_NUM_39) {//MODE
break;
}
// It's not REC button
if ((int)msg.data != GPIO_NUM_36) {// если нажатая кнопка не равна кнопке REC (GPIO_NUM_36) пропускаем оставшуюся часть
continue;
}
if (msg.cmd == PERIPH_BUTTON_PRESSED) {//если кнопка нажата то ...
ESP_LOGI(TAG, "[ * ] Resuming pipeline");
audio_element_set_uri(http_stream_writer, CONFIG_SERVER_URI);
audio_pipeline_run(pipeline);
} else if (msg.cmd == PERIPH_BUTTON_RELEASE || msg.cmd == PERIPH_BUTTON_LONG_RELEASE) {
ESP_LOGI(TAG, "[ * ] Stop pipeline");
audio_pipeline_stop(pipeline);
audio_pipeline_wait_for_stop(pipeline);
audio_pipeline_terminate(pipeline);
}
}
ESP_LOGI(TAG, "[ 7 ] Stop audio_pipeline");
audio_pipeline_terminate(pipeline);
audio_pipeline_unregister(pipeline, http_stream_writer);//*
audio_pipeline_unregister(pipeline, opus_encoder);
audio_pipeline_unregister(pipeline, i2s_stream_reader);
/* Terminate the pipeline before removing the listener */
audio_pipeline_remove_listener(pipeline);
/* Stop all peripherals before removing the listener */
esp_periph_set_stop_all(set);
audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), evt);
/* Make sure audio_pipeline_remove_listener & audio_event_iface_remove_listener are called before destroying event_iface */
audio_event_iface_destroy(evt);
/* Release all resources */
audio_pipeline_deinit(pipeline);
audio_element_deinit(http_stream_writer);
audio_element_deinit(opus_encoder);
audio_element_deinit(i2s_stream_reader);
esp_periph_set_destroy(set);
}