mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-07 12:07:09 +03:00
mad fix through library + ST77xx memory corruption + add full screen + poll mutex for stream - release
This commit is contained in:
Binary file not shown.
@@ -90,7 +90,7 @@ static void Update16( struct GDS_Device* Device ) {
|
|||||||
for (int i = FirstRow; i <= LastRow; i++) {
|
for (int i = FirstRow; i <= LastRow; i++) {
|
||||||
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize);
|
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 2, ChunkSize);
|
||||||
optr += 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);
|
Device->WriteData(Device, Private->iRAM, optr - 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++) {
|
for (int i = FirstRow; i <= LastRow; i++) {
|
||||||
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize);
|
memcpy(optr, Private->Shadowbuffer + (i * Device->Width + FirstCol) * 3, ChunkSize);
|
||||||
optr += 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);
|
Device->WriteData(Device, Private->iRAM, optr - Private->iRAM);
|
||||||
optr = Private->iRAM;
|
optr = Private->iRAM;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -628,8 +628,9 @@ static void grfe_handler( u8_t *data, int len) {
|
|||||||
|
|
||||||
scroller.active = false;
|
scroller.active = false;
|
||||||
|
|
||||||
// visu has priority when full screen on small screens
|
// full screen artwork or for small screen, full screen visu has priority
|
||||||
if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) {
|
if (((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) ||
|
||||||
|
(artwork.enable && artwork.x == 0 && artwork.y == 0)) {
|
||||||
xSemaphoreGive(displayer.mutex);
|
xSemaphoreGive(displayer.mutex);
|
||||||
return;
|
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);
|
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
|
// full screen artwork or for small screen, visu has priority when full screen
|
||||||
if ((visu.mode & VISU_ESP32) && !visu.col && visu.row < displayer.height) return;
|
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);
|
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
|
// when using full screen visualizer on small screen there is a brief overlay
|
||||||
artwork.enable = (length != 0);
|
artwork.enable = (length != 0);
|
||||||
|
|
||||||
// just a config or an actual artwork
|
// just a config or an actual artwork
|
||||||
if (length < 32) {
|
if (length < 32) {
|
||||||
if (artwork.enable) {
|
if (artwork.enable) {
|
||||||
@@ -840,8 +844,10 @@ static void grfa_handler(u8_t *data, int len) {
|
|||||||
* Update visualization bars
|
* Update visualization bars
|
||||||
*/
|
*/
|
||||||
static void visu_update(void) {
|
static void visu_update(void) {
|
||||||
// no need to protect against no woning the display as we are playing
|
// no update when artwork is full screen (but no need to protect against not owning the display as we are playing
|
||||||
if (pthread_mutex_trylock(&visu_export.mutex)) return;
|
if ((artwork.enable && artwork.x == 0 && artwork.y == 0) || pthread_mutex_trylock(&visu_export.mutex)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int mode = visu.mode & ~VISU_ESP32;
|
int mode = visu.mode & ~VISU_ESP32;
|
||||||
|
|
||||||
|
|||||||
@@ -243,8 +243,6 @@ static decode_state mad_decode(void) {
|
|||||||
MAD(m, synth_frame, &m->synth, &m->frame);
|
MAD(m, synth_frame, &m->synth, &m->frame);
|
||||||
|
|
||||||
if (decode.new_stream) {
|
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;
|
LOCK_O;
|
||||||
LOG_INFO("setting track_start");
|
LOG_INFO("setting track_start");
|
||||||
output.next_sample_rate = decode_newstream(m->synth.pcm.samplerate, output.supported_rates);
|
output.next_sample_rate = decode_newstream(m->synth.pcm.samplerate, output.supported_rates);
|
||||||
|
|||||||
@@ -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(spdif_config, &i2s_spdif_pin);
|
||||||
set_i2s_pin(dac_config, &i2s_dac_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
|
// common I2S initialization
|
||||||
i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX;
|
i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX;
|
||||||
i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
|
i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
|
||||||
|
|||||||
@@ -42,8 +42,30 @@ static log_level loglevel;
|
|||||||
static struct buffer buf;
|
static struct buffer buf;
|
||||||
struct buffer *streambuf = &buf;
|
struct buffer *streambuf = &buf;
|
||||||
|
|
||||||
#define LOCK mutex_lock(streambuf->mutex)
|
#define LOCK mutex_lock(streambuf->mutex)
|
||||||
#define UNLOCK mutex_unlock(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;
|
static sockfd fd;
|
||||||
|
|
||||||
@@ -187,6 +209,7 @@ static void *stream_thread() {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
LOCK_L;
|
||||||
pollinfo.fd = fd;
|
pollinfo.fd = fd;
|
||||||
pollinfo.events = POLLIN;
|
pollinfo.events = POLLIN;
|
||||||
if (stream.state == SEND_HEADERS) {
|
if (stream.state == SEND_HEADERS) {
|
||||||
@@ -195,9 +218,10 @@ static void *stream_thread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
|
||||||
if (_poll(ssl, &pollinfo, 100)) {
|
if (_poll(ssl, &pollinfo, 100)) {
|
||||||
|
|
||||||
|
UNLOCK_L;
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
// check socket has not been closed while in poll
|
// check socket has not been closed while in poll
|
||||||
@@ -350,7 +374,7 @@ static void *stream_thread() {
|
|||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
UNLOCK_L;
|
||||||
LOG_SDEBUG("poll timeout");
|
LOG_SDEBUG("poll timeout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,6 +427,9 @@ void stream_init(log_level level, unsigned stream_buf_size) {
|
|||||||
*stream.header = '\0';
|
*stream.header = '\0';
|
||||||
|
|
||||||
fd = -1;
|
fd = -1;
|
||||||
|
#if EMBEDDED
|
||||||
|
mutex_create_p(poll_mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if LINUX || FREEBSD
|
#if LINUX || FREEBSD
|
||||||
touch_memory(streambuf->buf, streambuf->size);
|
touch_memory(streambuf->buf, streambuf->size);
|
||||||
@@ -432,13 +459,16 @@ void stream_close(void) {
|
|||||||
#endif
|
#endif
|
||||||
free(stream.header);
|
free(stream.header);
|
||||||
buf_destroy(streambuf);
|
buf_destroy(streambuf);
|
||||||
|
#if EMBEDDED
|
||||||
|
mutex_destroy(poll_mutex);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_file(const char *header, size_t header_len, unsigned threshold) {
|
void stream_file(const char *header, size_t header_len, unsigned threshold) {
|
||||||
buf_flush(streambuf);
|
buf_flush(streambuf);
|
||||||
|
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
stream.header_len = header_len;
|
stream.header_len = header_len;
|
||||||
memcpy(stream.header, header, header_len);
|
memcpy(stream.header, header, header_len);
|
||||||
*(stream.header+header_len) = '\0';
|
*(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) {
|
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;
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
LOCK_L;
|
||||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
UNLOCK_L;
|
||||||
|
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
LOG_ERROR("failed to create socket");
|
LOG_ERROR("failed to create socket");
|
||||||
|
|||||||
Binary file not shown.
@@ -78,7 +78,7 @@ sub displayWidth {
|
|||||||
if ($display->widthOverride) {
|
if ($display->widthOverride) {
|
||||||
my $artwork = $prefs->client($client)->get('artwork');
|
my $artwork = $prefs->client($client)->get('artwork');
|
||||||
if ($artwork->{'enable'} && $artwork->{'y'} < 32 && ($client->isPlaying || $client->isPaused)) {
|
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 {
|
} else {
|
||||||
return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
|
return $display->widthOverride + ($display->modes->[$mode || 0]{_width} || 0);
|
||||||
}
|
}
|
||||||
@@ -113,9 +113,9 @@ sub build_modes {
|
|||||||
my $artwork = $cprefs->get('artwork');
|
my $artwork = $cprefs->get('artwork');
|
||||||
my $disp_width = $cprefs->get('width') || 128;
|
my $disp_width = $cprefs->get('width') || 128;
|
||||||
|
|
||||||
# if artwork is in main display, reduce 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'} : $disp_width;
|
my $width = ($artwork->{'enable'} && $artwork->{'y'} < 32 && $artwork->{'x'}) ? $artwork->{'x'} : $disp_width;
|
||||||
my $width_low = ($artwork->{'enable'} && ($artwork->{'y'} >= 32 || $disp_width - $artwork->{'x'} > 32)) ? $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 $small_VU = $cprefs->get('small_VU');
|
||||||
my $spectrum = $cprefs->get('spectrum');
|
my $spectrum = $cprefs->get('spectrum');
|
||||||
|
|||||||
@@ -221,6 +221,11 @@ sub clear_artwork {
|
|||||||
if ($artwork && $artwork->{'enable'}) {
|
if ($artwork && $artwork->{'enable'}) {
|
||||||
main::INFOLOG && $log->is_info && $log->info("artwork stop/clear " . $request->getRequestString());
|
main::INFOLOG && $log->is_info && $log->info("artwork stop/clear " . $request->getRequestString());
|
||||||
$client->pluginData('artwork_md5', '');
|
$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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ sub page {
|
|||||||
sub prefs {
|
sub prefs {
|
||||||
my ($class, $client) = @_;
|
my ($class, $client) = @_;
|
||||||
my @prefs;
|
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);
|
return ($prefs->client($client), @prefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ sub handler {
|
|||||||
my ($cprefs, @prefs) = $class->prefs($client);
|
my ($cprefs, @prefs) = $class->prefs($client);
|
||||||
|
|
||||||
if ($paramRef->{'saveSettings'}) {
|
if ($paramRef->{'saveSettings'}) {
|
||||||
if ($client->displayWidth) {
|
if (defined $client->displayWidth) {
|
||||||
$cprefs->set('small_VU', $paramRef->{'pref_small_VU'} || 15);
|
$cprefs->set('small_VU', $paramRef->{'pref_small_VU'} || 15);
|
||||||
my $spectrum = {
|
my $spectrum = {
|
||||||
scale => $paramRef->{'pref_spectrum_scale'} || 25,
|
scale => $paramRef->{'pref_spectrum_scale'} || 25,
|
||||||
@@ -76,7 +76,7 @@ sub handler {
|
|||||||
$client->update_tones($equalizer);
|
$client->update_tones($equalizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($client->displayWidth) {
|
if (defined $client->displayWidth) {
|
||||||
# the Settings super class can't handle anything but scalar values
|
# the Settings super class can't handle anything but scalar values
|
||||||
# we need to populate the $paramRef for the other prefs manually
|
# we need to populate the $paramRef for the other prefs manually
|
||||||
$paramRef->{'pref_spectrum'} = $cprefs->get('spectrum');
|
$paramRef->{'pref_spectrum'} = $cprefs->get('spectrum');
|
||||||
|
|||||||
@@ -10,6 +10,6 @@
|
|||||||
<name>PLUGIN_SQUEEZEESP32</name>
|
<name>PLUGIN_SQUEEZEESP32</name>
|
||||||
<description>PLUGIN_SQUEEZEESP32_DESC</description>
|
<description>PLUGIN_SQUEEZEESP32_DESC</description>
|
||||||
<module>Plugins::SqueezeESP32::Plugin</module>
|
<module>Plugins::SqueezeESP32::Plugin</module>
|
||||||
<version>0.103</version>
|
<version>0.104</version>
|
||||||
<creator>Philippe</creator>
|
<creator>Philippe</creator>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<?xml version='1.0' standalone='yes'?>
|
<?xml version='1.0' standalone='yes'?>
|
||||||
<extensions>
|
<extensions>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin version="0.103" name="SqueezeESP32" minTarget="7.9" maxTarget="*">
|
<plugin version="0.104" name="SqueezeESP32" minTarget="7.9" maxTarget="*">
|
||||||
<link>https://github.com/sle118/squeezelite-esp32</link>
|
<link>https://github.com/sle118/squeezelite-esp32</link>
|
||||||
<creator>Philippe</creator>
|
<creator>Philippe</creator>
|
||||||
<sha>d07bb3b0a283fbde50e5533dca695a4505971f03</sha>
|
<sha>79e505a30d7b6dbf43893acab176d57438e2a4a1</sha>
|
||||||
<email>philippe_44@outlook.com</email>
|
<email>philippe_44@outlook.com</email>
|
||||||
<desc lang="EN">SqueezeESP32 additional player id (100)</desc>
|
<desc lang="EN">SqueezeESP32 additional player id (100)</desc>
|
||||||
<url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>
|
<url>http://github.com/sle118/squeezelite-esp32/raw/master/plugin/SqueezeESP32.zip</url>
|
||||||
|
|||||||
Reference in New Issue
Block a user