Compare commits

...

24 Commits

Author SHA1 Message Date
Philippe G
369a9cb9bc add mono channel option - release 2021-02-06 18:02:33 -08:00
philippe44
b9deead084 Update README.md 2021-01-31 15:13:39 -08:00
philippe44
723e7442af Update README.md 2021-01-31 15:07:09 -08:00
Christian Herzog
8189a59d59 typo 2021-01-25 08:24:09 +01:00
philippe44
cc209be4f9 Update README.md 2021-01-24 00:31:08 -08:00
philippe44
1d9e8e863c Update README.md 2021-01-24 00:29:50 -08:00
philippe44
c37fd57b2c Update README.md 2021-01-24 00:29:19 -08:00
philippe44
54420387ab Update README.md 2021-01-24 00:28:56 -08:00
philippe44
173b2d13da Update README.md 2021-01-24 00:18:16 -08:00
philippe44
d60506c63f Update README.md 2021-01-23 23:52:37 -08:00
philippe44
2d80c44181 Update README.md 2021-01-23 23:51:18 -08:00
Philippe G
eb5df86733 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-01-18 22:55:30 -08:00
Philippe G
096e1d636d SSD1322 enhancement - release
at the expense of power but needed for 5.5' displays
2021-01-18 22:49:27 -08:00
philippe44
434836782c Update README.md 2021-01-16 12:02:03 -08:00
Philippe G
3b9e50ada7 alac corrected - release 2021-01-11 19:24:52 -08:00
Philippe G
78a16e41dc simplify alac writebuf alloc 2021-01-10 21:57:22 -08:00
Philippe G
2bc4a8c807 more alac fixes 2021-01-10 16:14:38 -08:00
Philippe G
c521fba4a6 pcm remaining bytes guardrail 2021-01-10 02:23:23 -08:00
Philippe G
174942f509 better alac management 2021-01-10 02:13:46 -08:00
Philippe G
9bf7b250e0 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-01-09 23:51:58 -08:00
Philippe G
32c2a4d68a 24àx320 VU-display fixes + alac decoder code style 2021-01-09 23:51:52 -08:00
Sebastien
64f96c68dc Update esp-idf docker image to latest v4.0 release 2021-01-09 16:54:34 -05:00
Philippe G
9807bf5476 Merge branch 'master-cmake' of https://github.com/sle118/squeezelite-esp32 into master-cmake 2021-01-08 15:05:52 -08:00
Philippe G
5a630887c4 IP reassembly flags consistents with new CONFIG 2021-01-08 15:03:01 -08:00
17 changed files with 95 additions and 75 deletions

View File

@@ -80,7 +80,7 @@ jobs:
run: |
env | grep "artifact\|tag\|GITHUB\|version\|NUMBER\|TARGET" >${TARGET_BUILD_NAME}-env.txt
echo "${tag}" >version.txt
docker run --env-file=${TARGET_BUILD_NAME}-env.txt --rm -v $PWD:/project -w /project sle118/squeezelite-esp32:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
docker run --env-file=${TARGET_BUILD_NAME}-env.txt --rm -v $PWD:/project -w /project sle118/idf:release-v4.0 /bin/bash -c "cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig && idf.py build && zip -r build_output.zip build && zip build/${artifact_file_name} partitions*.csv build/*.bin build/bootloader/bootloader.bin build/partition_table/partition-table.bin build/flash_project_args build/size_*.txt"
# - name: Build Mock firmware
# run: |
# mkdir -p build

View File

@@ -24,7 +24,7 @@ Other features include
- Firmware over-the-air update
## Supported Hardware
Any esp32-based hardware with at least 4MB of flash and 4MB of PSRAM will be capable of running squeezelite-esp32 and there are various boards that include such chip. A few are mentionned below, but any should work.
Any esp32-based hardware with at least 4MB of flash and 4MB of PSRAM will be capable of running squeezelite-esp32 and there are various boards that include such chip. A few are mentionned below, but any should work. You can find various help & instructions [here](https://forums.slimdevices.com/showthread.php?112697-ANNOUNCE-Squeezelite-ESP32-(dedicated-thread))
### Raw WROVER module
Per above description, a [WROVER module](https://www.espressif.com/en/products/modules/esp32) is enough to run Squeezelite-esp32, but that requires a bit of tinkering to extend it to have analogue audio or hardware buttons (e.g.)
@@ -45,13 +45,18 @@ NB: You can use the pre-build binaries SqueezeAMP4MBFlash which has all the hard
### 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 set
The board shown above has the following IO set
- amplifier: GPIO21
- key2: GPIO13, key3: GPIO19, key4: GPIO23, key5: GPIO18, key6: GPIO5 (to be confirmed with dip switches)
- key1: not sure, something with GPIO36
- key1: not sure, using GPIO36 in a matrix
- jack insertion: GPIO39 (inserted low)
- LED: GPIO22 (active low)
(note that GPIO need pullups)
- D4 -> GPIO22 used for green LED (active low)
- D5 -> GPIO19 (muxed with key3)
- The IO connector also brings GPIO5, GPIO18, GPIO19, GPIO21, GPIO22 and GPIO23 (don't forget it's muxed with keys!)
- The JTAG connector uses GPIO 12, 13, 14 and 15 (see dip switch) but these are also used for SD-card (and GPIO13 is key2 as well)
- It's always possible to re-use GPIOO (download at boot) and GPIO1/GPIO3 which are RX/TX of UART0 but you'll lose trace
(note that some GPIO need pullups)
So a possible config would be
- set_GPIO: 21=amp,22=green:0,39=jack:0
@@ -207,16 +212,18 @@ There is also the possibility to use 'knobonly' option (exclusive with 'volume'
- double press is 'Back' (Left in LMS's terminology).
- a quick left-right movement on the encoder is 'Pause'
The speed of double click (or left-right) can be set using the optional parameter of 'knobonly'. This is not a perfect solution, and other ideas are welcome. Be aware that the longer you set double click speed, the less responsive the interface will be. The reason is that I need to wait for that delay before deciding if it's a single or double click. It can also make menu navigation "hesitations" being easoly interpreted as 'Pause'
The speed of double click (or left-right) can be set using the optional parameter of 'knobonly'. This is not a perfect solution, and other ideas are welcome. Be aware that the longer you set double click speed, the less responsive the interface will be. The reason is that I need to wait for that delay before deciding if it's a single or double click. It can also make menu navigation "hesitations" being easily interpreted as 'Pause'
Use parameter rotary_config with the following syntax:
```
A=<gpio>,B=<gpio>[,SW=gpio>[[,knobonly[=<ms>]|[,volume][,longpress]]
A=<gpio>,B=<gpio>[,SW=gpio>[[,knobonly[=<ms>]]|[[,volume][,longpress]]]]
```
HW note: all gpio used for rotary have internal pull-up so normally there is no need to provide Vcc to the encoder. Nevertheless if the encoder board you're using also has its own pull-up that are stronger than ESP32's ones (which is likely the case), then there will be crosstalk between gpio, so you must bring Vcc. Look at your board schematic and you'll understand that these board pull-up create a "winning" pull-down when any other pin is grounded.
The SW gpio is optional, you can re-affect it to a pure button if you prefer but the volume, longpress and knobonly options make little sense as the missing switch plays an important role in these modes. You could still have the "volume" mode, but you won't be able to use it for *anything* expect volume up and down. So be aware that the use of syntax [] is a bit misleading hereabove.
See also the "IMPORTANT NOTE" on the "Buttons" section and remember that when 'lms_ctrls_raw' (see below) is activated, none of these knobonly,volume,longpress options apply, raw button codes (not actions) are simply sent to LMS
### Buttons

View File

@@ -458,7 +458,6 @@ CONFIG_LWIP_SO_REUSE_RXTOALL=y
#CONFIG_LWIP_IP_REASSEMBLY is not set
CONFIG_LWIP_IP6_REASSEMBLY=Y
CONFIG_LWIP_IP4_REASSEMBLY=Y
CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
CONFIG_LWIP_GARP_TMR_INTERVAL=60
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32

View File

@@ -19,7 +19,7 @@ extern "C" {
struct alac_codec_s *alac_create_decoder(int magic_cookie_size, unsigned char *magic_cookie,
unsigned char *sample_size, unsigned *sample_rate,
unsigned char *channels);
unsigned char *channels, unsigned int *block_size);
void alac_delete_decoder(struct alac_codec_s *codec);
bool alac_to_pcm(struct alac_codec_s *codec, unsigned char* input,
unsigned char *output, char channels, unsigned *out_frames);

Binary file not shown.

View File

@@ -147,23 +147,28 @@ static bool Init( struct GDS_Device* Device ) {
Private->ReMap = 0;
Device->SetLayout( Device, false, false, false);
// set Display Enhancement
Device->WriteCommand( Device, 0xB4 );
WriteDataByte( Device, 0xA0 );
WriteDataByte( Device, 0xB5 );
// set Clocks
Device->WriteCommand( Device, 0xB3 );
WriteDataByte( Device, 0x91 );
WriteDataByte( Device, 0xB2 ); // 0x91 seems to be common but is too slow for 5.5'
// set MUX
Device->WriteCommand( Device, 0xCA );
WriteDataByte( Device, Device->Height - 1 );
// phase 1 & 2 period (needed?)
// phase 1 & 2 period
Device->WriteCommand( Device, 0xB1 );
WriteDataByte( Device, 0xE2 );
WriteDataByte( Device, 0xE3 ); // 0xE2 was recommended
// set pre-charge V (needed?°)
// set pre-charge V
Device->WriteCommand( Device, 0xBB );
WriteDataByte( Device, 0x1F );
WriteDataByte( Device, 0x0F); // 0x1F causes column interferences
// set COM deselect voltage (needed?)
// set COM deselect voltage
Device->WriteCommand( Device, 0xBE );
WriteDataByte( Device, 0x07 );

View File

@@ -168,7 +168,7 @@ static void rtp_thread_func(void *arg);
#endif
/*---------------------------------------------------------------------------*/
static struct alac_codec_s* alac_init(int fmtp[32]) {
static struct alac_codec_s* alac_init(int fmtp[32]) {
struct alac_codec_s *alac;
unsigned sample_rate, block_size;
unsigned char sample_size, channels;
@@ -196,7 +196,7 @@ static struct alac_codec_s* alac_init(int fmtp[32]) {
config.maxRun = htons(fmtp[8]);
config.maxFrameBytes = htonl(fmtp[9]);
config.avgBitRate = htonl(fmtp[10]);
config.sampleRate = htonl(fmtp[11]);
config.sampleRate = htonl(fmtp[11]);
alac = alac_create_decoder(sizeof(config), (unsigned char*) &config, &sample_size, &sample_rate, &channels, &block_size);
if (!alac) {

View File

@@ -21,7 +21,7 @@
#include "squeezelite.h"
#include <alac_wrapper.h>
#include "alac_wrapper.h"
#if BYTES_PER_FRAME == 4
#define ALIGN8(n) (n << 8)
@@ -119,8 +119,15 @@ static int read_mp4_header(void) {
// extract audio config from within alac
if (!strcmp(type, "alac") && bytes > len) {
u8_t *ptr = streambuf->readp + 36;
l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels);
l->play = l->trak;
unsigned int block_size;
l->play = l->trak;
l->decoder = alac_create_decoder(len - 36, ptr, &l->sample_size, &l->sample_rate, &l->channels, &block_size);
l->writebuf = malloc(block_size + 256);
LOG_INFO("allocated write buffer of %u bytes", block_size);
if (!l->writebuf) {
LOG_ERROR("allocation failed");
return -1;
}
}
// extract the total number of samples from stts
@@ -374,10 +381,9 @@ static decode_state alac_decode(void) {
// need to create a buffer with contiguous data
if (bytes < block_size) {
u8_t *buffer = malloc(block_size);
memcpy(buffer, streambuf->readp, bytes);
memcpy(buffer + bytes, streambuf->buf, block_size - bytes);
iptr = buffer;
iptr = malloc(block_size);
memcpy(iptr, streambuf->readp, bytes);
memcpy(iptr + bytes, streambuf->buf, block_size - bytes);
} else iptr = streambuf->readp;
if (!alac_to_pcm(l->decoder, iptr, l->writebuf, 2, &frames)) {
@@ -472,6 +478,7 @@ static decode_state alac_decode(void) {
}
} else if (l->sample_size == 16) {
u16_t *_iptr = (u16_t*) iptr;
iptr += count * 4;
while (count--) {
*optr++ = ALIGN16(*_iptr++);
*optr++ = ALIGN16(*_iptr++);
@@ -484,6 +491,7 @@ static decode_state alac_decode(void) {
}
} else if (l->sample_size == 32) {
u32_t *_iptr = (u32_t*) iptr;
iptr += count * 8;
while (count--) {
*optr++ = ALIGN32(*_iptr++);
*optr++ = ALIGN32(*_iptr++);
@@ -509,27 +517,17 @@ static decode_state alac_decode(void) {
return DECODE_RUNNING;
}
static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
if (l->decoder) alac_delete_decoder(l->decoder);
else l->writebuf = malloc(BLOCK_SIZE * 2);
if (l->chunkinfo) free(l->chunkinfo);
if (l->block_size) free(l->block_size);
if (l->stsc) free(l->stsc);
l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
l->skip = 0;
l->samples = l->sttssamples = 0;
l->empty = false;
l->pos = l->consume = l->sample = l->nextchunk = 0;
}
static void alac_close(void) {
if (l->decoder) alac_delete_decoder(l->decoder);
if (l->writebuf) free(l->writebuf);
if (l->chunkinfo) free(l->chunkinfo);
if (l->block_size) free(l->block_size);
if (l->stsc) free(l->stsc);
l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
free(l->writebuf);
memset(l, 0, sizeof(struct alac));
}
static void alac_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
alac_close();
}
struct codec *register_alac(void) {
@@ -543,13 +541,9 @@ struct codec *register_alac(void) {
alac_decode, // decode
};
l = malloc(sizeof(struct alac));
if (!l) {
return NULL;
}
l->decoder = l->chunkinfo = l->stsc = l->block_size = NULL;
l = calloc(1, sizeof(struct alac));
if (!l) return NULL;
LOG_INFO("using alac to decode alc");
return &ret;
}

View File

@@ -972,7 +972,7 @@ static void visu_update(void) {
}
}
}
} else if (displayer.width / 2 > 3 * VU_WIDTH / 4) {
} else if (displayer.width / 2 >= 3 * VU_WIDTH / 4) {
if (visu.rotate) {
draw_VU(display, vu_bitmap, visu.bars[0].current, 0, visu.row, visu.height / 2, visu.rotate);
draw_VU(display, vu_bitmap, visu.bars[1].current, 0, visu.row + visu.height / 2, visu.height / 2, visu.rotate);

View File

@@ -253,6 +253,9 @@ frames_t _output_frames(frames_t avail) {
}
out_frames = !silence ? min(size, cont_frames) : size;
if (output.channels & 0x01) gainR = MONO_MUTED;
else if (output.channels & 0x02) gainL = MONO_MUTED;
wrote = output.write_cb(out_frames, silence, gainL, gainR, cross_gain_in, cross_gain_out, &cross_ptr);

View File

@@ -90,9 +90,7 @@ static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t g
_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
}
if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
_apply_gain(outputbuf, out_frames, gainL, gainR);
}
_apply_gain(outputbuf, out_frames, gainL, gainR);
#if BYTES_PER_FRAME == 4
memcpy(btout + oframes * BYTES_PER_FRAME, outputbuf->readp, out_frames * BYTES_PER_FRAME);

View File

@@ -410,10 +410,7 @@ static int _i2s_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32
}
#if BYTES_PER_FRAME == 4
if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
_apply_gain(outputbuf, out_frames, gainL, gainR);
}
_apply_gain(outputbuf, out_frames, gainL, gainR);
memcpy(obuf + oframes * BYTES_PER_FRAME, outputbuf->readp, out_frames * BYTES_PER_FRAME);
#else
optr = (s32_t*) outputbuf->readp;

View File

@@ -356,17 +356,34 @@ void _apply_cross(struct buffer *outputbuf, frames_t out_frames, s32_t cross_gai
}
}
#if !WIN
inline
#endif
void _apply_gain(struct buffer *outputbuf, frames_t count, s32_t gainL, s32_t gainR) {
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
while (count--) {
*ptrL = gain(gainL, *ptrL);
*ptrR = gain(gainR, *ptrR);
ptrL += 2;
ptrR += 2;
}
if (gainL == FIXED_ONE && gainR == FIXED_ONE) {
return;
} else if (gainL == MONO_MUTED) {
ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
while (count--) {
*(ptr - 1) = *ptr = gain(gainR, *ptr);
ptr += 2;
}
} else if (gainR == MONO_MUTED) {
ISAMPLE_T *ptr = (ISAMPLE_T *)(void *)outputbuf->readp;
while (count--) {
*(ptr + 1) = *ptr = gain(gainL, *ptr);
ptr += 2;
}
} else {
ISAMPLE_T *ptrL = (ISAMPLE_T *)(void *)outputbuf->readp;
ISAMPLE_T *ptrR = (ISAMPLE_T *)(void *)outputbuf->readp + 1;
while (count--) {
*ptrL = gain(gainL, *ptrL);
*ptrR = gain(gainR, *ptrR);
ptrL += 2; ptrR += 2;
}
}
}

View File

@@ -204,7 +204,7 @@ static decode_state pcm_decode(void) {
out = process.max_in_frames;
);
if ((stream.state <= DISCONNECT && bytes == 0) || (limit && audio_left == 0)) {
if ((stream.state <= DISCONNECT && bytes < bytes_per_frame) || (limit && audio_left == 0)) {
UNLOCK_O_direct;
UNLOCK_S;
return DECODE_COMPLETE;

View File

@@ -397,8 +397,9 @@ static void process_strm(u8_t *pkt, int len) {
output.next_replay_gain = unpackN(&strm->replay_gain);
output.fade_mode = strm->transition_type - '0';
output.fade_secs = strm->transition_period;
output.invert = (strm->flags & 0x03) == 0x03;
LOG_DEBUG("set fade mode: %u", output.fade_mode);
output.invert = (strm->flags & 0x03) == 0x03;
output.channels = (strm->flags & 0x0c) >> 2;
LOG_DEBUG("set fade: %u, channels: %u, invert: %u", output.fade_mode, output.channels, output.invert);
UNLOCK_O;
}
break;

View File

@@ -471,7 +471,8 @@ void _wake_create(event_event*);
#define MAX_SILENCE_FRAMES 2048
#define FIXED_ONE 0x10000
#define FIXED_ONE 0x10000
#define MONO_MUTED (FIXED_ONE + 1)
#ifndef BYTES_PER_FRAME
#define BYTES_PER_FRAME 8
@@ -660,6 +661,7 @@ typedef enum { FADE_NONE = 0, FADE_CROSSFADE, FADE_IN, FADE_OUT, FADE_INOUT } fa
struct outputstate {
output_state state;
output_format format;
u8_t channels;
const char *device;
int external;
u32_t init_size;

View File

@@ -521,19 +521,16 @@ void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, un
#if USE_SSL
if (ntohs(port) == 443) {
char *server = strcasestr(header, "Host:");
char server[256], *p;
ssl = SSL_new(SSLctx);
SSL_set_fd(ssl, sock);
// add SNI
sscanf(header, "Host:%255s", server);
if (server) {
char *p, *servername = malloc(1024);
sscanf(server, "Host:%255[^:]s", servername);
for (p = servername; *p == ' '; p++);
SSL_set_tlsext_host_name(ssl, p);
free(servername);
if ((p = strchr(server, ':')) != NULL) *p = '\0';
SSL_set_tlsext_host_name(ssl, server);
}
while (1) {