From 1a5f5283bb711d953909392fb55a72fd8f319cff Mon Sep 17 00:00:00 2001 From: philippe44 Date: Sun, 8 Mar 2020 16:51:24 -0700 Subject: [PATCH 01/13] make AirPlay work in AP mode --- components/raop/raop.c | 6 ++++++ components/raop/raop_sink.c | 2 +- components/raop/util.c | 29 +++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/components/raop/raop.c b/components/raop/raop.c index a01303e1..2d989a86 100644 --- a/components/raop/raop.c +++ b/components/raop/raop.c @@ -436,6 +436,12 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock) char *buf_pad, *p, *data_b64 = NULL, data[32]; LOG_INFO("[%p]: challenge %s", ctx, buf); + + // try to re-acquire IP address if we were missing it + if (S_ADDR(ctx->host) == INADDR_ANY) { + S_ADDR(ctx->host) = get_localhost(NULL); + LOG_INFO("[%p]: IP was missing, trying to get it %s", ctx, inet_ntoa(ctx->host)); + } // need to pad the base64 string as apple device don't base64_pad(buf, &buf_pad); diff --git a/components/raop/raop_sink.c b/components/raop/raop_sink.c index 1424e94f..73b711f5 100644 --- a/components/raop/raop_sink.c +++ b/components/raop/raop_sink.c @@ -163,7 +163,7 @@ void raop_sink_init(raop_cmd_vcb_t cmd_cb, raop_data_cb_t data_cb) { free(sink_name_buffer); } - LOG_INFO( "mdns hostname set to: [%s] with servicename %s", hostname, sink_name); + LOG_INFO( "mdns hostname for ip %s set to: [%s] with servicename %s", inet_ntoa(host), hostname, sink_name); // create RAOP instance, latency is set by controller uint8_t mac[6]; diff --git a/components/raop/util.c b/components/raop/util.c index 13744409..f2a9be77 100644 --- a/components/raop/util.c +++ b/components/raop/util.c @@ -23,12 +23,7 @@ #ifdef WIN32 #include #else -/* -#include -#include -#include -#include -*/ +#include "tcpip_adapter.h" #include #endif @@ -84,8 +79,26 @@ in_addr_t get_localhost(char **name) } else return INADDR_ANY; #else - // missing platform here ... - return INADDR_ANY; + tcpip_adapter_ip_info_t ipInfo; + tcpip_adapter_if_t if_type = TCPIP_ADAPTER_IF_STA; + + // then get IP address + tcpip_adapter_get_ip_info(if_type, &ipInfo); + + // we might be in AP mode + if (ipInfo.ip.addr == INADDR_ANY) { + if_type = TCPIP_ADAPTER_IF_AP; + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ipInfo); + } + + // get hostname if required + if (name) { + const char *hostname; + tcpip_adapter_get_hostname(if_type, &hostname); + *name = strdup(hostname); + } + + return ipInfo.ip.addr; #endif } From b60ea2e356b336820f97a1734b28996a2b03b956 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Sun, 8 Mar 2020 16:51:45 -0700 Subject: [PATCH 02/13] make AirPlay work in AP mode - release --- plugin/SqueezeESP32/PlayerSettings.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/SqueezeESP32/PlayerSettings.pm b/plugin/SqueezeESP32/PlayerSettings.pm index f4fc24b0..4c88dcfd 100644 --- a/plugin/SqueezeESP32/PlayerSettings.pm +++ b/plugin/SqueezeESP32/PlayerSettings.pm @@ -21,7 +21,7 @@ sub needsClient { sub validFor { my ($class, $client) = @_; - return $client->model eq 'squeezeesp32'; + return $client->model eq 'squeezeesp32' && $client->displayWidth; } sub page { From 6398bbfe9f1cb5780ced8b069b1d563bc59710eb Mon Sep 17 00:00:00 2001 From: philippe44 Date: Sun, 8 Mar 2020 21:47:27 -0700 Subject: [PATCH 03/13] Improve AirPlay robustness to bad network conditions - release need to add a decent PID loop ... --- components/raop/rtp.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/components/raop/rtp.c b/components/raop/rtp.c index de3f41a4..536e6f1e 100644 --- a/components/raop/rtp.c +++ b/components/raop/rtp.c @@ -510,14 +510,14 @@ static void buffer_push_packet(rtp_t *ctx) { // not ready to play yet if (!ctx->playing || ctx->synchro.status != (RTP_SYNC | NTP_SYNC)) return; - // maybe re-evaluate time in loop in case data callback blocks ... - now = gettime_ms(); - // there is always at least one frame in the buffer do { + // re-evaluate time in loop in case data callback blocks ... + now = gettime_ms(); + // try to manage playtime so that we overflow as late as possible if we miss NTP (2^31 / 10 / 44100) curframe = ctx->audio_buffer + BUFIDX(ctx->ab_read); - playtime = ctx->synchro.time + (((s32_t)(curframe->rtptime - ctx->synchro.rtp)) * 1000) / RAOP_SAMPLE_RATE; + playtime = ctx->synchro.time + (((s32_t)(curframe->rtptime - ctx->synchro.rtp)) * 10) / (RAOP_SAMPLE_RATE / 100); if (now > playtime) { LOG_DEBUG("[%p]: discarded frame now:%u missed by:%d (W:%hu R:%hu)", ctx, now, now - playtime, ctx->ab_write, ctx->ab_read); @@ -653,9 +653,14 @@ static void *rtp_thread_func(void *arg) { u16_t flags = ntohs(*(u16_t*)(pktp+2)); u32_t remote_gap = NTP2MS(remote - ctx->timing.remote); - // something is wrong and if we are supposed to be NTP synced, better ask for re-sync + // try to get NTP every 3 sec or every time if we are not synced + if (!count-- || !(ctx->synchro.status && NTP_SYNC)) { + rtp_request_timing(ctx); + count = 3; + } + + // something is wrong, we should not have such gap if (remote_gap > 10000) { - if (ctx->synchro.status & NTP_SYNC) rtp_request_timing(ctx); LOG_WARN("discarding remote timing information %u", remote_gap); break; } @@ -683,11 +688,6 @@ static void *rtp_thread_func(void *arg) { LOG_DEBUG("[%p]: sync packet latency:%d rtp_latency:%u rtp:%u remote ntp:%llx, local time:%u local rtp:%u (now:%u)", ctx, ctx->latency, rtp_now_latency, rtp_now, remote, ctx->synchro.time, ctx->synchro.rtp, gettime_ms()); - if (!count--) { - rtp_request_timing(ctx); - count = 3; - } - if ((ctx->synchro.status & RTP_SYNC) && (ctx->synchro.status & NTP_SYNC)) ctx->cmd_cb(RAOP_TIMING); break; @@ -699,7 +699,7 @@ static void *rtp_thread_func(void *arg) { u32_t reference = ntohl(*(u32_t*)(pktp+12)); // only low 32 bits in our case u64_t remote =(((u64_t) ntohl(*(u32_t*)(pktp+16))) << 32) + ntohl(*(u32_t*)(pktp+20)); u32_t roundtrip = gettime_ms() - reference; - + // better discard sync packets when roundtrip is suspicious and ask for another one if (roundtrip > 100) { rtp_request_timing(ctx); @@ -785,7 +785,7 @@ static bool rtp_request_resend(rtp_t *ctx, seq_t first, seq_t last) { // do not request silly ranges (happens in case of network large blackouts) if (seq_order(last, first) || last - first > BUFFER_FRAMES / 2) return false; - ctx->resent_req += last - first + 1; + ctx->resent_req += (seq_t) (last - first) + 1; LOG_DEBUG("resend request [W:%hu R:%hu first=%hu last=%hu]", ctx->ab_write, ctx->ab_read, first, last); From 9e4fa4dd53cdf95a1e5973e32e48997b614d8405 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 15:10:37 -0700 Subject: [PATCH 04/13] Update README.md --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 531128de..7ce32dce 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,14 @@ Works with the SqueezeAMP see [here](https://forums.slimdevices.com/showthread.p Use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file. ### 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 or an external amplifier if you want direct speaker connection. +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/4000765857347.html?spm=2114.12010615.8148356.11.5d963cd0j669ns) or an external amplifier if you want direct speaker connection. + +The board showed above has the following IO sets +- amplifier: GPIO21 +- key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 +- key1: not sure, somethign with GPIO36 +- jack insertion: GPIO39 (inserted low) +- LED: GPIO22 (active low) ### ESP32-WROVER + I2S DAC Squeezelite-esp32 requires esp32 chipset and 4MB PSRAM. ESP32-WROVER meets these requirements. To get an audio output an I2S DAC can be used. Cheap PCM5102 I2S DACs work others may also work. PCM5012 DACs can be hooked up via: @@ -137,10 +144,11 @@ Where (all parameters are optionals except gpio) - "shifted": action to take when a button is pressed/released and shifted (see above/below) - "longshifted": action to take when a button is long-pressed/released and shifted (see above/below) -Where \ is either the name of another configuration to load or one amongst +Where \ is either the name of another configuration to load (remap) or one amongst ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, - BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT + BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, + KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH, One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config From 761fc21e336c59a2d7e18846093d97cd4648e058 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 15:11:23 -0700 Subject: [PATCH 05/13] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ce32dce..1a5b5a1a 100644 --- a/README.md +++ b/README.md @@ -145,10 +145,10 @@ Where (all parameters are optionals except gpio) - "longshifted": action to take when a button is long-pressed/released and shifted (see above/below) Where \ is either the name of another configuration to load (remap) or one amongst - ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, + ```ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, - KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH, + KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH``` One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config From 404f4108aa4cdc59ba955b763e0cfd1aecd46011 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 15:12:12 -0700 Subject: [PATCH 06/13] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1a5b5a1a..007bd3f1 100644 --- a/README.md +++ b/README.md @@ -144,12 +144,13 @@ Where (all parameters are optionals except gpio) - "shifted": action to take when a button is pressed/released and shifted (see above/below) - "longshifted": action to take when a button is long-pressed/released and shifted (see above/below) -Where \ is either the name of another configuration to load (remap) or one amongst - ```ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, +Where \ is either the name of another configuration to load (remap) or one amongst + ``` + ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, - KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH``` - + KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH + ``` One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config For example a config named "buttons" : From 71e0a67ac4d821c97d644d9e891b8f37a13bbd21 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 15:12:45 -0700 Subject: [PATCH 07/13] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 007bd3f1..484a85a5 100644 --- a/README.md +++ b/README.md @@ -145,12 +145,14 @@ Where (all parameters are optionals except gpio) - "longshifted": action to take when a button is long-pressed/released and shifted (see above/below) Where \ is either the name of another configuration to load (remap) or one amongst + ``` ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH ``` + One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config For example a config named "buttons" : From 42c0aa712ac2e2f2ddd6fb8871147e07a160c952 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 15:13:32 -0700 Subject: [PATCH 08/13] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 484a85a5..7e3eab0d 100644 --- a/README.md +++ b/README.md @@ -146,12 +146,12 @@ Where (all parameters are optionals except gpio) Where \ is either the name of another configuration to load (remap) or one amongst - ``` - ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, - ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, - BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, - KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH - ``` +``` +ACTRLS_NONE, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, +ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, +BCTRLS_PUSH, BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, +KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH +``` One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config From bbe42f68a34bdce8727ac6603f8737767cd5c27e Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 19:45:44 -0700 Subject: [PATCH 09/13] Tweak A1S to make it work with devkit + correct one minor bug in buttons - release --- components/services/buttons.c | 6 ++-- components/services/monitor.c | 3 +- components/squeezelite/a1s/ac101.c | 48 ++++++++++++++--------------- components/squeezelite/output_i2s.c | 2 ++ 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/components/services/buttons.c b/components/services/buttons.c index eed67640..424c6c65 100644 --- a/components/services/buttons.c +++ b/components/services/buttons.c @@ -191,7 +191,7 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu if (n_buttons >= MAX_BUTTONS) return; - ESP_LOGI(TAG, "Creating button using GPIO %u, type %u, pull-up/down %u, long press %u shifter %u", gpio, type, pull, long_press, shifter_gpio); + ESP_LOGI(TAG, "Creating button using GPIO %u, type %u, pull-up/down %u, long press %u shifter %d", gpio, type, pull, long_press, shifter_gpio); if (!n_buttons) { button_evt_queue = xQueueCreate(BUTTON_QUEUE_LEN, sizeof(struct button_s)); @@ -209,7 +209,6 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu buttons[n_buttons].debounce = debounce ? debounce: DEBOUNCE; buttons[n_buttons].handler = handler; buttons[n_buttons].long_press = long_press; - buttons[n_buttons].level = -1; buttons[n_buttons].shifter_gpio = shifter_gpio; buttons[n_buttons].type = type; buttons[n_buttons].timer = xTimerCreate("buttonTimer", buttons[n_buttons].debounce / portTICK_RATE_MS, pdFALSE, (void *) &buttons[n_buttons], buttons_timer); @@ -247,6 +246,9 @@ void button_create(void *client, int gpio, int type, bool pull, int debounce, bu // nasty ESP32 bug: fire-up constantly INT on GPIO 36/39 if ADC1, AMP, Hall used which WiFi does when PS is activated if (gpio == 36 || gpio == 39) gpio36_39_used = true; + + // and initialize level ... + buttons[n_buttons].level = gpio_get_level(gpio); gpio_isr_handler_add(gpio, gpio_isr_handler, (void*) &buttons[n_buttons]); gpio_intr_enable(gpio); diff --git a/components/services/monitor.c b/components/services/monitor.c index 1fb246f1..eb032244 100644 --- a/components/services/monitor.c +++ b/components/services/monitor.c @@ -116,7 +116,8 @@ static void jack_handler_default(void *id, button_event_e event, button_press_e * */ bool jack_inserted_svc (void) { - return button_is_pressed(jack.gpio, NULL); + if (jack.gpio != -1) return button_is_pressed(jack.gpio, NULL); + else return true; } /**************************************************************************************** diff --git a/components/squeezelite/a1s/ac101.c b/components/squeezelite/a1s/ac101.c index 420d2d78..a7678eb1 100644 --- a/components/squeezelite/a1s/ac101.c +++ b/components/squeezelite/a1s/ac101.c @@ -35,7 +35,7 @@ const static char TAG[] = "AC101"; -#define SPKOUT_EN ((1 << 11) | (1 << 7)) +#define SPKOUT_EN ((1 << 9) | (1 << 11) | (1 << 7) | (1 << 5)) #define EAROUT_EN ((1 << 11) | (1 << 12) | (1 << 13)) #define BIN(a,b,c,d) 0b##a##b##c##d @@ -132,8 +132,8 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) { //Path Configuration i2c_write_reg(DAC_MXR_SRC, BIN(1000,1000,0000,0000)); // DAC from I2S i2c_write_reg(DAC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable DAC - i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,0000,0000,000)); // enable DAC/Analogue (see note on offset removal and PA) - i2c_write_reg(OMIXER_DACA_CTRL, BIN(1100,0000,0000,000)); // enable DAC/Analogue (see note on offset removal and PA) + i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,0000,0000,0000)); // enable DAC/Analogue (see note on offset removal and PA) + i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,1111,0000,0000)); // this toggle is needed for headphone PA offset #if ENABLE_ADC i2c_write_reg(OMIXER_SR, BIN(0000,0001,0000,0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?) #else @@ -149,8 +149,7 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) { // enable earphone & speaker i2c_write_reg(SPKOUT_CTRL, 0x0220); - i2c_write_reg(OMIXER_DACA_CTRL, 0xff00); - i2c_write_reg(HPOUT_CTRL, 0x3801); + i2c_write_reg(HPOUT_CTRL, 0xf801); // set gain for speaker and earphone ac101_set_spk_volume(100); @@ -206,9 +205,10 @@ static void speaker(bool active) { * headset */ static void headset(bool active) { + // there might be aneed to toggle OMIXER_DACA_CTRL 11:8, not sure uint16_t value = i2c_read_reg(HPOUT_CTRL); if (active) i2c_write_reg(HPOUT_CTRL, value | EAROUT_EN); - else i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN); + else i2c_write_reg(HPOUT_CTRL, value & ~EAROUT_EN); } /**************************************************************************************** @@ -284,14 +284,14 @@ static int ac101_get_spk_volume(void) { * Set normalized (0..100) volume */ static void ac101_set_spk_volume(uint8_t volume) { - volume = max(volume, 0x1f); - volume = ((int) volume * 0x1f) / 100; - volume |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f; - i2c_write_reg(SPKOUT_CTRL, volume); + uint16_t value = max(volume, 100); + value = ((int) value * 0x1f) / 100; + value |= i2c_read_reg(SPKOUT_CTRL) & ~0x1f; + i2c_write_reg(SPKOUT_CTRL, value); } /**************************************************************************************** - * Get normalized (0..100) earphonz volume + * Get normalized (0..100) earphone volume */ static int ac101_get_earph_volume(void) { return (((i2c_read_reg(HPOUT_CTRL) >> 4) & 0x3f) * 100) / 0x3f; @@ -301,10 +301,10 @@ static int ac101_get_earph_volume(void) { * Set normalized (0..100) earphone volume */ static void ac101_set_earph_volume(uint8_t volume) { - volume = max(volume, 0x3f); - volume = (((int) volume * 0x3f) / 100) << 4; - volume |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4); - i2c_write_reg(HPOUT_CTRL, volume); + uint16_t value = max(volume, 100); + value = (((int) value * 0x3f) / 100) << 4; + value |= i2c_read_reg(HPOUT_CTRL) & ~(0x3f << 4); + i2c_write_reg(HPOUT_CTRL, value); } /**************************************************************************************** @@ -345,17 +345,16 @@ static void ac101_start(ac_module_t mode) { i2c_write_reg(0x50, 0x3bc0); } if (mode == AC_MODULE_ADC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) { - //I2S1_SDOUT_CTRL - //i2c_write_reg(PLL_CTRL2, 0x8120); + // I2S1_SDOUT_CTRL + // i2c_write_reg(PLL_CTRL2, 0x8120); i2c_write_reg(0x04, 0x800c); i2c_write_reg(0x05, 0x800c); - //res |= i2c_write_reg(0x06, 0x3000); + // res |= i2c_write_reg(0x06, 0x3000); } if (mode == AC_MODULE_DAC || mode == AC_MODULE_ADC_DAC || mode == AC_MODULE_LINE) { - headset(true); - speaker(true); - ac101_set_earph_volume(100); - ac101_set_spk_volume(100); + uint16_t value = i2c_read_reg(PLL_CTRL2); + value |= 0x8000; + i2c_write_reg(PLL_CTRL2, value); } } @@ -363,8 +362,9 @@ static void ac101_start(ac_module_t mode) { * */ static void ac101_stop(void) { - speaker(false); - headset(false); + uint16_t value = i2c_read_reg(PLL_CTRL2); + value &= ~0x8000; + i2c_write_reg(PLL_CTRL2, value); } /**************************************************************************************** diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index 1a05a498..9cbd60bc 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -274,6 +274,8 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch 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); esp_pthread_cfg_t cfg = esp_pthread_get_default_config(); From 9967f13478686887390b50406b319a7bba6dec74 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 22:32:30 -0700 Subject: [PATCH 10/13] Update README.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 7e3eab0d..5e456339 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,12 @@ The board showed above has the following IO sets - jack insertion: GPIO39 (inserted low) - LED: GPIO22 (active low) +So a possible config woudl be +- set_GPIO: 21=amp,22=green:0,39=jack:0 +- a button mapping: +```[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}] +``` + ### ESP32-WROVER + I2S DAC Squeezelite-esp32 requires esp32 chipset and 4MB PSRAM. ESP32-WROVER meets these requirements. To get an audio output an I2S DAC can be used. Cheap PCM5102 I2S DACs work others may also work. PCM5012 DACs can be hooked up via: From d96f5a98e0bf6c901b885a81059f78d819f27574 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 22:33:02 -0700 Subject: [PATCH 11/13] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5e456339..a388098d 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ The board showed above has the following IO sets - jack insertion: GPIO39 (inserted low) - LED: GPIO22 (active low) -So a possible config woudl be +So a possible config would be - set_GPIO: 21=amp,22=green:0,39=jack:0 - a button mapping: -```[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}] +``` +[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}] ``` ### ESP32-WROVER + I2S DAC From c7ebb4ec9abefa2a5e4b0b246273c4478d7c6cde Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 22:33:42 -0700 Subject: [PATCH 12/13] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a388098d..ca2d3e48 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includ The board showed above has the following IO sets - amplifier: GPIO21 -- key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 -- key1: not sure, somethign with GPIO36 +- key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 (to be confirmed width dipswitches) +- key1: not sure, something with GPIO36 - jack insertion: GPIO39 (inserted low) - LED: GPIO22 (active low) From d713830e727bbdf56272080bab471f932c2130e7 Mon Sep 17 00:00:00 2001 From: philippe44 Date: Mon, 9 Mar 2020 22:34:05 -0700 Subject: [PATCH 13/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca2d3e48..0e4b41f3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file. ### 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/4000765857347.html?spm=2114.12010615.8148356.11.5d963cd0j669ns) or an external amplifier if you want direct speaker connection. -The board showed above has the following IO sets +The board showed above has the following IO set - amplifier: GPIO21 - key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 (to be confirmed width dipswitches) - key1: not sure, something with GPIO36