mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2026-03-22 22:39:27 +00:00
Compare commits
6 Commits
I2S-4MFlas
...
I2S-4MFlas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9588ae9f39 | ||
|
|
c0c37bd98a | ||
|
|
d5a8e3a4a2 | ||
|
|
d4b0bc4edb | ||
|
|
635d382d71 | ||
|
|
5d09d4f853 |
1
.github/workflows/CrossBuild.yml
vendored
1
.github/workflows/CrossBuild.yml
vendored
@@ -1,6 +1,5 @@
|
||||
# This is a basic workflow to help you get started with Actions
|
||||
name: Cross-Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore: [ master ]
|
||||
|
||||
@@ -71,7 +71,7 @@ NB: You can use the pre-build binaries SqueezeAMP4MBFlash which has all the hard
|
||||
- spdif_config: bck=33,ws=25,do=15
|
||||
|
||||
### ESP32-A1S
|
||||
Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4001060963585.html) or an external amplifier if you want direct speaker connection. Note that there is a version with AC101 codec and another one with ES8388 (see below)
|
||||
Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4001060963585.html) or an external amplifier if you want direct speaker connection. Note that there is a version with AC101 codec and another one with ES8388 with probably two variants - these boards are a mess (see below)
|
||||
|
||||
The board shown above has the following IO set
|
||||
- amplifier: GPIO21
|
||||
@@ -95,8 +95,10 @@ So a possible config would be
|
||||
for AC101
|
||||
- dac_config: model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32
|
||||
|
||||
for ES8388
|
||||
for ES8388 (it seems that there are variants with same version number - a total mess)
|
||||
- dac_config: model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16
|
||||
or
|
||||
- dac_config: model=ES8388,bck=27,ws=25,do=26,sda=33,scl=32,i2c=16
|
||||
### T-WATCH2020 by LilyGo
|
||||
This is a fun [smartwatch](http://www.lilygo.cn/prod_view.aspx?TypeId=50036&Id=1290&FId=t3:50036:3) based on ESP32. It has a 240x240 ST7789 screen and onboard audio. Not very useful to listen to anything but it works. This is an example of a device that requires an I2C set of commands for its dac (see below). There is a build-option if you decide to rebuild everything by yourself, otherwise the I2S default option works with the following parameters
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ static EXT_RAM_ATTR struct led_s {
|
||||
TimerHandle_t timer;
|
||||
} leds[MAX_LED];
|
||||
|
||||
static EXT_RAM_ATTR struct {
|
||||
// can't use EXT_RAM_ATTR for initialized structure
|
||||
static struct {
|
||||
int gpio;
|
||||
int active;
|
||||
int pwm;
|
||||
|
||||
@@ -145,7 +145,7 @@ static void monitor_callback(TimerHandle_t xTimer) {
|
||||
*
|
||||
*/
|
||||
static void jack_handler_default(void *id, button_event_e event, button_press_e mode, bool long_press) {
|
||||
ESP_LOGD(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed");
|
||||
ESP_LOGI(TAG, "Jack %s", event == BUTTON_PRESSED ? "inserted" : "removed");
|
||||
if (jack_handler_svc) (*jack_handler_svc)(event == BUTTON_PRESSED);
|
||||
}
|
||||
|
||||
|
||||
20
components/squeezelite/external/dac_external.c
vendored
20
components/squeezelite/external/dac_external.c
vendored
@@ -20,8 +20,8 @@
|
||||
|
||||
static const char TAG[] = "DAC external";
|
||||
|
||||
static void speaker(bool active) { }
|
||||
static void headset(bool active) { }
|
||||
static void speaker(bool active);
|
||||
static void headset(bool active);
|
||||
static bool volume(unsigned left, unsigned right) { return false; }
|
||||
static void power(adac_power_e mode);
|
||||
static bool init(char *config, int i2c_port_num, i2s_config_t *i2s_config);
|
||||
@@ -95,6 +95,22 @@ static void power(adac_power_e mode) {
|
||||
else i2c_json_execute("poweron");
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* speaker
|
||||
*/
|
||||
static void speaker(bool active) {
|
||||
if (active) i2c_json_execute("speakeron");
|
||||
else i2c_json_execute("speakeroff");
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* headset
|
||||
*/
|
||||
static void headset(bool active) {
|
||||
if (active) i2c_json_execute("headseton");
|
||||
else i2c_json_execute("headsetoff");
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -129,8 +129,13 @@ static bool handler(u8_t *data, int len){
|
||||
jack_mutes_amp = pkt->config == 0;
|
||||
config_set_value(NVS_TYPE_STR, "jack_mutes_amp", jack_mutes_amp ? "y" : "n");
|
||||
|
||||
if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false);
|
||||
else adac->speaker(true);
|
||||
if (jack_mutes_amp && jack_inserted_svc()) {
|
||||
adac->speaker(false);
|
||||
if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, !amp_control.active);
|
||||
} else {
|
||||
adac->speaker(true);
|
||||
if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, amp_control.active);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_INFO("got AUDO %02x", pkt->config);
|
||||
@@ -151,13 +156,12 @@ static void jack_handler(bool inserted) {
|
||||
// jack detection bounces a bit but that seems fine
|
||||
if (jack_mutes_amp) {
|
||||
LOG_INFO("switching amplifier %s", inserted ? "OFF" : "ON");
|
||||
if (inserted) adac->speaker(false);
|
||||
else adac->speaker(true);
|
||||
adac->speaker(!inserted);
|
||||
if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, inserted ? !amp_control.active : amp_control.active);
|
||||
}
|
||||
|
||||
// activate headset
|
||||
if (inserted) adac->headset(true);
|
||||
else adac->headset(false);
|
||||
adac->headset(inserted);
|
||||
|
||||
// and chain if any
|
||||
if (jack_handler_chain) (jack_handler_chain)(inserted);
|
||||
@@ -343,12 +347,13 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
||||
jack_handler_chain = jack_handler_svc;
|
||||
jack_handler_svc = jack_handler;
|
||||
|
||||
parse_set_GPIO(set_amp_gpio);
|
||||
|
||||
if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false);
|
||||
else adac->speaker(true);
|
||||
|
||||
adac->headset(jack_inserted_svc());
|
||||
|
||||
parse_set_GPIO(set_amp_gpio);
|
||||
|
||||
// create task as a FreeRTOS task but uses stack in internal RAM
|
||||
{
|
||||
@@ -455,7 +460,10 @@ static void output_thread_i2s(void *arg) {
|
||||
adac->speaker(false);
|
||||
led_blink(LED_GREEN, 200, 1000);
|
||||
} else if (output.state == OUTPUT_RUNNING) {
|
||||
if (!jack_mutes_amp || !jack_inserted_svc()) adac->speaker(true);
|
||||
if (!jack_mutes_amp || !jack_inserted_svc()) {
|
||||
if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, amp_control.active);
|
||||
adac->speaker(true);
|
||||
}
|
||||
led_on(LED_GREEN);
|
||||
}
|
||||
}
|
||||
@@ -513,7 +521,6 @@ static void output_thread_i2s(void *arg) {
|
||||
i2s_zero_dma_buffer(CONFIG_I2S_NUM);
|
||||
i2s_start(CONFIG_I2S_NUM);
|
||||
adac->power(ADAC_ON);
|
||||
if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, amp_control.active);
|
||||
}
|
||||
|
||||
// this does not work well as set_sample_rates resets the fifos (and it's too early)
|
||||
|
||||
@@ -80,35 +80,6 @@ static esp_err_t _httpd_server_init(struct httpd_data *hd)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void _httpd_process_ctrl_msg(struct httpd_data *hd)
|
||||
{
|
||||
struct httpd_ctrl_data msg;
|
||||
int ret = recv(hd->ctrl_fd, &msg, sizeof(msg), 0);
|
||||
if (ret <= 0) {
|
||||
ESP_LOGW(TAG, LOG_FMT("error in recv (%d)"), errno);
|
||||
return;
|
||||
}
|
||||
if (ret != sizeof(msg)) {
|
||||
ESP_LOGW(TAG, LOG_FMT("incomplete msg"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.hc_msg) {
|
||||
case HTTPD_CTRL_WORK:
|
||||
if (msg.hc_work) {
|
||||
ESP_LOGD(TAG, LOG_FMT("work"));
|
||||
(*msg.hc_work)(msg.hc_work_arg);
|
||||
}
|
||||
break;
|
||||
case HTTPD_CTRL_SHUTDOWN:
|
||||
ESP_LOGD(TAG, LOG_FMT("shutdown"));
|
||||
hd->hd_td.status = THREAD_STOPPING;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t _httpd_accept_conn(struct httpd_data *hd, int listen_fd)
|
||||
{
|
||||
/* If no space is available for new session, close the least recently used one */
|
||||
@@ -164,13 +135,10 @@ static esp_err_t _httpd_server(struct httpd_data *hd)
|
||||
* older connections will be closed) */
|
||||
FD_SET(hd->listen_fd, &read_set);
|
||||
}
|
||||
FD_SET(hd->ctrl_fd, &read_set);
|
||||
|
||||
int tmp_max_fd;
|
||||
httpd_sess_set_descriptors(hd, &read_set, &tmp_max_fd);
|
||||
int maxfd = MAX(hd->listen_fd, tmp_max_fd);
|
||||
tmp_max_fd = maxfd;
|
||||
maxfd = MAX(hd->ctrl_fd, tmp_max_fd);
|
||||
int maxfd;
|
||||
httpd_sess_set_descriptors(hd, &read_set, &maxfd);
|
||||
maxfd = MAX(hd->listen_fd, maxfd);
|
||||
|
||||
ESP_LOGD(TAG, LOG_FMT("doing select maxfd+1 = %d"), maxfd + 1);
|
||||
int active_cnt = select(maxfd + 1, &read_set, NULL, NULL, NULL);
|
||||
@@ -180,8 +148,6 @@ static esp_err_t _httpd_server(struct httpd_data *hd)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Case0: Do we have a control message? */
|
||||
|
||||
/* Case1: Do we have any activity on the current data
|
||||
* sessions? */
|
||||
int fd = -1;
|
||||
|
||||
Reference in New Issue
Block a user