diff --git a/components/codecs/lib/libmad.a b/components/codecs/lib/libmad.a index fdb17fae..fa9aced8 100644 Binary files a/components/codecs/lib/libmad.a and b/components/codecs/lib/libmad.a differ diff --git a/components/display/ST77xx.c b/components/display/ST77xx.c index 3deaee2a..78d59d87 100644 --- a/components/display/ST77xx.c +++ b/components/display/ST77xx.c @@ -90,7 +90,7 @@ static void Update16( struct GDS_Device* Device ) { for (int i = FirstRow; i <= LastRow; i++) { memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize); optr += ChunkSize; - if (optr - Private->iRAM < PAGE_BLOCK && i < LastRow) continue; + if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue; Device->WriteData(Device, Private->iRAM, optr - Private->iRAM); optr = Private->iRAM; } @@ -157,7 +157,7 @@ static void Update24( struct GDS_Device* Device ) { for (int i = FirstRow; i <= LastRow; i++) { memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize); optr += ChunkSize; - if (optr - Private->iRAM < PAGE_BLOCK && i < LastRow) continue; + if (optr - Private->iRAM <= (PAGE_BLOCK - ChunkSize) && i < LastRow) continue; Device->WriteData(Device, Private->iRAM, optr - Private->iRAM); optr = Private->iRAM; } diff --git a/components/squeezelite/display.c b/components/squeezelite/display.c index af263eab..20b8547d 100644 --- a/components/squeezelite/display.c +++ b/components/squeezelite/display.c @@ -628,8 +628,9 @@ static void grfe_handler( u8_t *data, int len) { scroller.active = false; - // visu has priority when full screen on small screens - if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) { + // full screen artwork or for small screen, full screen visu has priority + if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) || + (artwork.enable && artwork.x == 0 && artwork.y == 0)) { xSemaphoreGive(displayer.mutex); return; } @@ -751,8 +752,11 @@ static void grfg_handler(u8_t *data, int len) { LOG_DEBUG("gfrg s:%hu w:%hu (len:%u)", htons(pkt->screen), htons(pkt->width), len); - // on small screen, visu has priority when full screen - if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) return; + // full screen artwork or for small screen, visu has priority when full screen + if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) || + (artwork.enable && artwork.x == 0 && artwork.y == 0)) { + return; + } xSemaphoreTake(displayer.mutex, portMAX_DELAY); @@ -795,7 +799,7 @@ static void grfa_handler(u8_t *data, int len) { // when using full screen visualizer on small screen there is a brief overlay artwork.enable = (length != 0); - + // just a config or an actual artwork if (length < 32) { if (artwork.enable) { @@ -840,8 +844,10 @@ static void grfa_handler(u8_t *data, int len) { * Update visualization bars */ static void visu_update(void) { - // no need to protect against no woning the display as we are playing - if (pthread_mutex_trylock(&visu_export.mutex)) return; + // no update when artwork is full screen (but no need to protect against not owning the display as we are playing + if ((artwork.enable && artwork.x == 0 && artwork.y == 0) || pthread_mutex_trylock(&visu_export.mutex)) { + return; + } int mode = visu.mode & ~VISU_ESP32; diff --git a/components/squeezelite/mad.c b/components/squeezelite/mad.c index a34b5e2b..ccc6d50b 100644 --- a/components/squeezelite/mad.c +++ b/components/squeezelite/mad.c @@ -243,8 +243,6 @@ static decode_state mad_decode(void) { MAD(m, synth_frame, &m->synth, &m->frame); if (decode.new_stream) { - // seems that mad can use some help in term of sync detection - if (m->stream.next_frame[0] != 0xff || (m->stream.next_frame[1] & 0xf0) != 0xf0) continue; LOCK_O; LOG_INFO("setting track_start"); output.next_sample_rate = decode_newstream(m->synth.pcm.samplerate, output.supported_rates); diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index be32c635..f06d6e8f 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -234,6 +234,11 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch set_i2s_pin(spdif_config, &i2s_spdif_pin); set_i2s_pin(dac_config, &i2s_dac_pin); + /* BEWARE: i2s. must be patched to set tx_msb_right/rx_msb_right to 1 + * or SPDIF will not work. These settings are not accessible from + * userland and I don't know why + */ + // common I2S initialization i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX; i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; diff --git a/components/squeezelite/stream.c b/components/squeezelite/stream.c index f9247e11..73d097ce 100644 --- a/components/squeezelite/stream.c +++ b/components/squeezelite/stream.c @@ -42,8 +42,30 @@ static log_level loglevel; static struct buffer buf; struct buffer *streambuf = &buf; -#define LOCK mutex_lock(streambuf->mutex) -#define UNLOCK mutex_unlock(streambuf->mutex) +#define LOCK mutex_lock(streambuf->mutex) +#define UNLOCK mutex_unlock(streambuf->mutex) + +/* +After a lot of hesitation, I've added that "poll mutex" to prevent +socket from being allocated while we are still in poll(). The issue +happens is we have a close quickly followed by an open, we might still +be in the poll() and simple OS fail as they re-allocate the same socket +on which a thread is still waiting. +Ideally, you want to set the lock in the disconnect() but that would mean +very often we'd have to always wait for the end of the poll(), i.e. up to +100ms for nothing most of the time where if it is in the open(), it is +less elegant as closing a socket on which there is a poll() is not good +but it's more efficient as it is very rare that you'd have an open() less +then 100ms after a close() +*/ +#if EMBEDDED +static mutex_type poll_mutex; +#define LOCK_L mutex_lock(poll_mutex) +#define UNLOCK_L mutex_unlock(poll_mutex) +#else +#define LOCK_L +#define UNLOCK_L +#endif static sockfd fd; @@ -187,6 +209,7 @@ static void *stream_thread() { } else { + LOCK_L; pollinfo.fd = fd; pollinfo.events = POLLIN; if (stream.state == SEND_HEADERS) { @@ -195,9 +218,10 @@ static void *stream_thread() { } UNLOCK; - + if (_poll(ssl, &pollinfo, 100)) { + UNLOCK_L; LOCK; // check socket has not been closed while in poll @@ -350,7 +374,7 @@ static void *stream_thread() { UNLOCK; } else { - + UNLOCK_L; LOG_SDEBUG("poll timeout"); } } @@ -403,6 +427,9 @@ void stream_init(log_level level, unsigned stream_buf_size) { *stream.header = '\0'; fd = -1; +#if EMBEDDED + mutex_create_p(poll_mutex); +#endif #if LINUX || FREEBSD touch_memory(streambuf->buf, streambuf->size); @@ -432,13 +459,16 @@ void stream_close(void) { #endif free(stream.header); buf_destroy(streambuf); +#if EMBEDDED + mutex_destroy(poll_mutex); +#endif } void stream_file(const char *header, size_t header_len, unsigned threshold) { buf_flush(streambuf); LOCK; - + stream.header_len = header_len; memcpy(stream.header, header, header_len); *(stream.header+header_len) = '\0'; @@ -473,7 +503,9 @@ void stream_file(const char *header, size_t header_len, unsigned threshold) { void stream_sock(u32_t ip, u16_t port, const char *header, size_t header_len, unsigned threshold, bool cont_wait) { struct sockaddr_in addr; + LOCK_L; int sock = socket(AF_INET, SOCK_STREAM, 0); + UNLOCK_L; if (sock < 0) { LOG_ERROR("failed to create socket"); diff --git a/plugin/SqueezeESP32.zip b/plugin/SqueezeESP32.zip index 41c94a05..8a052484 100644 Binary files a/plugin/SqueezeESP32.zip and b/plugin/SqueezeESP32.zip differ diff --git a/plugin/SqueezeESP32/Graphics.pm b/plugin/SqueezeESP32/Graphics.pm index b23cf95b..6f763be7 100644 --- a/plugin/SqueezeESP32/Graphics.pm +++ b/plugin/SqueezeESP32/Graphics.pm @@ -78,7 +78,7 @@ sub displayWidth { if ($display->widthOverride) { my $artwork = $prefs->client($client)->get('artwork'); if ($artwork->{'enable'} && $artwork->{'y'} < 32 && ($client->isPlaying || $client->isPaused)) { - return $artwork->{x} + ($display->modes->[$mode || 0]{_width} || 0); + return ($artwork->{x} || $display->widthOverride) + ($display->modes->[$mode || 0]{_width} || 0); } else { return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0); } @@ -113,9 +113,9 @@ sub build_modes { my $artwork = $cprefs->get('artwork'); my $disp_width = $cprefs->get('width') || 128; - # if artwork is in main display, reduce width - my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32) ? $artwork->{'x'} : $disp_width; - my $width_low = ($artwork->{'enable'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $artwork->{'x'} : $disp_width; + # if artwork is in main display, reduce width but when artwork is (0,0) fake it + my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32 && $artwork->{'x'}) ? $artwork->{'x'} : $disp_width; + my $width_low = ($artwork->{'enable'} && $artwork->{'x'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $artwork->{'x'} : $disp_width; my $small_VU = $cprefs->get('small_VU'); my $spectrum = $cprefs->get('spectrum'); diff --git a/plugin/SqueezeESP32/Player.pm b/plugin/SqueezeESP32/Player.pm index 1e065155..78eba318 100644 --- a/plugin/SqueezeESP32/Player.pm +++ b/plugin/SqueezeESP32/Player.pm @@ -221,6 +221,11 @@ sub clear_artwork { if ($artwork && $artwork->{'enable'}) { main::INFOLOG && $log->is_info && $log->info("artwork stop/clear " . $request->getRequestString()); $client->pluginData('artwork_md5', ''); + # refresh screen and disable artwork when artwork was full screen (hack) + if (!$artwork->{'x'} && !$artwork->{'y'}) { + $client->sendFrame(grfa => \("\x00"x4)) unless $artwork->{'x'} || $artwork->{'y'}; + $client->display->update; + } } } diff --git a/plugin/SqueezeESP32/PlayerSettings.pm b/plugin/SqueezeESP32/PlayerSettings.pm index d4a4e2d6..cde4bb0c 100644 --- a/plugin/SqueezeESP32/PlayerSettings.pm +++ b/plugin/SqueezeESP32/PlayerSettings.pm @@ -31,7 +31,7 @@ sub page { sub prefs { my ($class, $client) = @_; my @prefs; - push @prefs, qw(width small_VU) if $client->displayWidth; + push @prefs, qw(width small_VU) if defined $client->displayWidth; return ($prefs->client($client), @prefs); } @@ -41,7 +41,7 @@ sub handler { my ($cprefs, @prefs) = $class->prefs($client); if ($paramRef->{'saveSettings'}) { - if ($client->displayWidth) { + if (defined $client->displayWidth) { $cprefs->set('small_VU', $paramRef->{'pref_small_VU'} || 15); my $spectrum = { scale => $paramRef->{'pref_spectrum_scale'} || 25, @@ -76,7 +76,7 @@ sub handler { $client->update_tones($equalizer); } - if ($client->displayWidth) { + if (defined $client->displayWidth) { # the Settings super class can't handle anything but scalar values # we need to populate the $paramRef for the other prefs manually $paramRef->{'pref_spectrum'} = $cprefs->get('spectrum'); diff --git a/plugin/SqueezeESP32/install.xml b/plugin/SqueezeESP32/install.xml index 6cc9ba28..ef8c3894 100644 --- a/plugin/SqueezeESP32/install.xml +++ b/plugin/SqueezeESP32/install.xml @@ -10,6 +10,6 @@ PLUGIN_SQUEEZEESP32 PLUGIN_SQUEEZEESP32_DESC Plugins::SqueezeESP32::Plugin - 0.103 + 0.104 Philippe diff --git a/plugin/repo.xml b/plugin/repo.xml index 572a6419..8a7a7cac 100644 --- a/plugin/repo.xml +++ b/plugin/repo.xml @@ -1,10 +1,10 @@ - + https://github.com/sle118/squeezelite-esp32 Philippe - d07bb3b0a283fbde50e5533dca695a4505971f03 + 79e505a30d7b6dbf43893acab176d57438e2a4a1 philippe_44@outlook.com SqueezeESP32 additional player id (100) http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip