From e9da432bfc84a8f468a53dbd23f6a75a96d2026b Mon Sep 17 00:00:00 2001 From: Philippe G Date: Fri, 7 Jan 2022 19:16:55 -0800 Subject: [PATCH 01/16] more CSpot catchup --- .../spotify/cspot/include/SpircController.h | 1 + .../spotify/cspot/src/ChunkedAudioStream.cpp | 1 - .../spotify/cspot/src/ChunkedByteStream.cpp | 17 ++++++++++------- components/spotify/cspot/src/PlayerState.cpp | 2 +- .../spotify/cspot/src/SpircController.cpp | 1 - 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/components/spotify/cspot/include/SpircController.h b/components/spotify/cspot/include/SpircController.h index 32cbd182..a681031b 100644 --- a/components/spotify/cspot/include/SpircController.h +++ b/components/spotify/cspot/include/SpircController.h @@ -37,6 +37,7 @@ class SpircController { private: std::shared_ptr manager; std::string username; + bool firstFrame = true; std::unique_ptr player; std::unique_ptr state; std::shared_ptr audioSink; diff --git a/components/spotify/cspot/src/ChunkedAudioStream.cpp b/components/spotify/cspot/src/ChunkedAudioStream.cpp index 62fe7a0d..432eb103 100644 --- a/components/spotify/cspot/src/ChunkedAudioStream.cpp +++ b/components/spotify/cspot/src/ChunkedAudioStream.cpp @@ -156,7 +156,6 @@ void ChunkedAudioStream::startPlaybackLoop() void ChunkedAudioStream::seek(size_t dpos, Whence whence) { - BELL_LOG(info, "cspot", "%d", dpos); auto seekPos = 0; switch (whence) { diff --git a/components/spotify/cspot/src/ChunkedByteStream.cpp b/components/spotify/cspot/src/ChunkedByteStream.cpp index 643544d3..00140ee6 100644 --- a/components/spotify/cspot/src/ChunkedByteStream.cpp +++ b/components/spotify/cspot/src/ChunkedByteStream.cpp @@ -31,6 +31,7 @@ void ChunkedByteStream::fetchFileInformation() { endChunk->keepInMemory = true; chunks.push_back(endChunk); + requestChunk(0); } std::shared_ptr ChunkedByteStream::getChunkForPosition(size_t position) { @@ -57,11 +58,14 @@ size_t ChunkedByteStream::read(uint8_t *buf, size_t nbytes) { std::scoped_lock lock(this->readMutex); auto chunk = getChunkForPosition(pos); uint16_t chunkIndex = this->pos / AUDIO_CHUNK_SIZE; - for (auto it = chunks.begin(); it != chunks.end();) { - if (((*it)->endPositionstartPosition>(pos + 2 * AUDIO_CHUNK_SIZE)) && !(*it)->keepInMemory) { - it = chunks.erase(it); - } else { - it++; + + if (loadAheadEnabled) { + for (auto it = chunks.begin(); it != chunks.end();) { + if (((*it)->endPositionstartPosition>(pos + 2 * AUDIO_CHUNK_SIZE)) && !(*it)->keepInMemory) { + it = chunks.erase(it); + } else { + it++; + } } } @@ -85,7 +89,7 @@ size_t ChunkedByteStream::read(uint8_t *buf, size_t nbytes) { pos += read; auto nextChunkPos = ((chunkIndex + 1) * AUDIO_CHUNK_SIZE) + 1; - if (loadAheadEnabled && nextChunkPos + AUDIO_CHUNK_SIZE < fileSize) { + if (loadAheadEnabled && nextChunkPos < fileSize) { auto nextChunk = getChunkForPosition(nextChunkPos); if (nextChunk == nullptr) { @@ -117,7 +121,6 @@ size_t ChunkedByteStream::attemptRead(uint8_t *buffer, size_t bytes, std::shared void ChunkedByteStream::seek(size_t nbytes) { std::scoped_lock lock(this->readMutex); - BELL_LOG(info, "cspot", "seeking to %d", nbytes); pos = nbytes; diff --git a/components/spotify/cspot/src/PlayerState.cpp b/components/spotify/cspot/src/PlayerState.cpp index 70e87430..2b3f9aea 100644 --- a/components/spotify/cspot/src/PlayerState.cpp +++ b/components/spotify/cspot/src/PlayerState.cpp @@ -137,7 +137,7 @@ void PlayerState::updatePositionMs(uint32_t position) void PlayerState::updateTracks() { CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count); - //innerFrame.state.context_uri = remoteFrame.state.context_uri == nullptr ? nullptr : strdup(remoteFrame.state.context_uri); + innerFrame.state.context_uri = remoteFrame.state.context_uri == nullptr ? nullptr : strdup(remoteFrame.state.context_uri); std::copy(std::begin(remoteFrame.state.track), std::end(remoteFrame.state.track), std::begin(innerFrame.state.track)); innerFrame.state.track_count = remoteFrame.state.track_count; innerFrame.state.has_playing_track_index = true; diff --git a/components/spotify/cspot/src/SpircController.cpp b/components/spotify/cspot/src/SpircController.cpp index da9586aa..4f7e0264 100644 --- a/components/spotify/cspot/src/SpircController.cpp +++ b/components/spotify/cspot/src/SpircController.cpp @@ -103,7 +103,6 @@ void SpircController::prevSong() { } void SpircController::handleFrame(std::vector &data) { - //pb_release(Frame_fields, &state->remoteFrame); pbDecode(state->remoteFrame, Frame_fields, data); switch (state->remoteFrame.typ) { From 3125a095fa0296d6bdea77214d0df553ce8d3e72 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Sun, 9 Jan 2022 19:40:18 -0800 Subject: [PATCH 02/16] airplay artwork and CSpot leak fix (temporary) --- components/display/CMakeLists.txt | 1 + components/display/SH1106.c | 2 +- components/display/core/gds.c | 11 +- components/display/core/gds.h | 1 + components/display/core/gds_font.c | 18 +- components/display/core/gds_image.c | 6 +- components/display/core/gds_private.h | 4 +- components/display/core/gds_text.c | 12 +- .../display/core/ifaces/default_if_i2c.c | 2 +- .../display/core/ifaces/default_if_spi.c | 6 +- components/display/display.c | 48 ++++- components/display/display.h | 1 + components/display/note.jpg | Bin 0 -> 11563 bytes components/driver_bt/bt_app_sink.c | 2 +- components/raop/raop.c | 3 + components/raop/raop_sink.c | 8 +- components/raop/raop_sink.h | 2 +- components/spotify/Shim.cpp | 3 +- components/spotify/cspot/CMakeLists.txt | 1 + components/spotify/cspot/bell/CMakeLists.txt | 3 +- .../spotify/cspot/bell/include/NanoPBHelper.h | 4 + .../spotify/cspot/bell/src/NanoPBHelper.cpp | 16 ++ components/spotify/cspot/include/Packet.h | 2 +- .../cspot/protobuf/authentication.options | 11 +- .../cspot/protobuf/authentication.pb.c | 2 +- .../cspot/protobuf/authentication.pb.h | 40 ++-- .../cspot/protobuf/authentication.proto | 8 +- .../spotify/cspot/protobuf/mercury.options | 4 +- .../spotify/cspot/protobuf/mercury.pb.h | 16 +- .../spotify/cspot/protobuf/metadata.options | 34 ++-- .../spotify/cspot/protobuf/metadata.pb.c | 8 +- .../spotify/cspot/protobuf/metadata.pb.h | 175 ++++++++++-------- .../spotify/cspot/protobuf/spirc.options | 17 +- components/spotify/cspot/protobuf/spirc.pb.c | 2 +- components/spotify/cspot/protobuf/spirc.pb.h | 62 ++++--- .../spotify/cspot/src/MercuryManager.cpp | 9 +- .../spotify/cspot/src/MercuryResponse.cpp | 3 +- components/spotify/cspot/src/Packet.cpp | 2 +- components/spotify/cspot/src/PlayerState.cpp | 18 +- components/spotify/cspot/src/Session.cpp | 21 ++- components/spotify/cspot/src/SpotifyTrack.cpp | 71 +++---- .../spotify/cspot/src/TrackReference.cpp | 6 +- components/spotify/cspot_sink.c | 2 +- 43 files changed, 396 insertions(+), 271 deletions(-) create mode 100644 components/display/note.jpg diff --git a/components/display/CMakeLists.txt b/components/display/CMakeLists.txt index 01886005..8a1944b9 100644 --- a/components/display/CMakeLists.txt +++ b/components/display/CMakeLists.txt @@ -2,6 +2,7 @@ idf_component_register(SRC_DIRS . core core/ifaces fonts INCLUDE_DIRS . fonts core REQUIRES platform_config tools esp_common PRIV_REQUIRES services freertos driver + EMBED_FILES note.jpg ) set_source_files_properties(display.c diff --git a/components/display/SH1106.c b/components/display/SH1106.c index 7bd28182..11e69707 100644 --- a/components/display/SH1106.c +++ b/components/display/SH1106.c @@ -86,7 +86,7 @@ static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { Device->WriteCommand( Device, Contrast ); } -static void SPIParams(int Speed, uint8_t *mode, uint8_t *CS_pre, uint8_t *CS_post) { +static void SPIParams(int Speed, uint8_t *mode, uint16_t *CS_pre, uint8_t *CS_post) { *CS_post = Speed / (8*1000*1000); } diff --git a/components/display/core/gds.c b/components/display/core/gds.c index 63e32861..fc1d8d3d 100644 --- a/components/display/core/gds.c +++ b/components/display/core/gds.c @@ -235,12 +235,13 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { ledc_update_duty( LEDC_HIGH_SPEED_MODE, Device->Backlight.Channel ); } } - + void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) { if (Device->SetLayout) Device->SetLayout( Device, HFlip, VFlip, Rotate ); } void GDS_SetDirty( struct GDS_Device* Device ) { Device->Dirty = true; } -int GDS_GetWidth( struct GDS_Device* Device ) { return Device ? Device->Width : 0; } -int GDS_GetHeight( struct GDS_Device* Device ) { return Device ? Device->Height : 0; } -int GDS_GetDepth( struct GDS_Device* Device ) { return Device ? Device->Depth : 0; } -int GDS_GetMode( struct GDS_Device* Device ) { return Device ? Device->Mode : 0; } +int GDS_GetWidth( struct GDS_Device* Device ) { return Device ? Device->Width : 0; } +void GDS_SetTextWidth( struct GDS_Device* Device, int TextWidth ) { Device->TextWidth = Device && TextWidth && TextWidth < Device->Width ? TextWidth : Device->Width; } +int GDS_GetHeight( struct GDS_Device* Device ) { return Device ? Device->Height : 0; } +int GDS_GetDepth( struct GDS_Device* Device ) { return Device ? Device->Depth : 0; } +int GDS_GetMode( struct GDS_Device* Device ) { return Device ? Device->Mode : 0; } void GDS_DisplayOn( struct GDS_Device* Device ) { if (Device->DisplayOn) Device->DisplayOn( Device ); } void GDS_DisplayOff( struct GDS_Device* Device ) { if (Device->DisplayOff) Device->DisplayOff( Device ); } \ No newline at end of file diff --git a/components/display/core/gds.h b/components/display/core/gds.h index d79ade04..fa782329 100644 --- a/components/display/core/gds.h +++ b/components/display/core/gds.h @@ -38,6 +38,7 @@ void GDS_Update( struct GDS_Device* Device ); void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ); void GDS_SetDirty( struct GDS_Device* Device ); int GDS_GetWidth( struct GDS_Device* Device ); +void GDS_SetTextWidth( struct GDS_Device* Device, int TextWidth ); int GDS_GetHeight( struct GDS_Device* Device ); int GDS_GetDepth( struct GDS_Device* Device ); int GDS_GetMode( struct GDS_Device* Device ); diff --git a/components/display/core/gds_font.c b/components/display/core/gds_font.c index 2ea38872..65c1a08e 100644 --- a/components/display/core/gds_font.c +++ b/components/display/core/gds_font.c @@ -73,13 +73,13 @@ void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y, CharStartY+= OffsetY; /* Do not attempt to draw if this character is entirely offscreen */ - if ( CharEndX < 0 || CharStartX >= Device->Width || CharEndY < 0 || CharStartY >= Device->Height ) { + if ( CharEndX < 0 || CharStartX >= Device->TextWidth || CharEndY < 0 || CharStartY >= Device->Height ) { ClipDebug( x, y ); return; } /* Do not attempt to draw past the end of the screen */ - CharEndX = ( CharEndX >= Device->Width ) ? Device->Width - 1 : CharEndX; + CharEndX = ( CharEndX >= Device->TextWidth ) ? Device->TextWidth - 1 : CharEndX; CharEndY = ( CharEndY >= Device->Height ) ? Device->Height - 1 : CharEndY; Device->Dirty = true; @@ -146,7 +146,7 @@ int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character ) { } int GDS_FontGetMaxCharsPerRow( struct GDS_Device* Display ) { - return Display->Width / Display->Font->Width; + return Display->TextWidth / Display->Font->Width; } int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display ) { @@ -210,7 +210,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int switch ( Anchor ) { case TextAnchor_East: { *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 ); - *OutX = ( Display->Width - StringWidth ); + *OutX = ( Display->TextWidth - StringWidth ); break; } @@ -221,19 +221,19 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int break; } case TextAnchor_North: { - *OutX = ( Display->Width / 2 ) - ( StringWidth / 2 ); + *OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 ); *OutY = 0; break; } case TextAnchor_South: { - *OutX = ( Display->Width / 2 ) - ( StringWidth / 2 ); + *OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 ); *OutY = ( Display->Height - StringHeight ); break; } case TextAnchor_NorthEast: { - *OutX = ( Display->Width - StringWidth ); + *OutX = ( Display->TextWidth - StringWidth ); *OutY = 0; break; @@ -246,7 +246,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int } case TextAnchor_SouthEast: { *OutY = ( Display->Height - StringHeight ); - *OutX = ( Display->Width - StringWidth ); + *OutX = ( Display->TextWidth - StringWidth ); break; } @@ -258,7 +258,7 @@ void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int } case TextAnchor_Center: { *OutY = ( Display->Height / 2 ) - ( StringHeight / 2 ); - *OutX = ( Display->Width / 2 ) - ( StringWidth / 2 ); + *OutX = ( Display->TextWidth / 2 ) - ( StringWidth / 2 ); break; } diff --git a/components/display/core/gds_image.c b/components/display/core/gds_image.c index cbb392e5..f47e3383 100644 --- a/components/display/core/gds_image.c +++ b/components/display/core/gds_image.c @@ -142,7 +142,7 @@ static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) { JpegCtx *Context = (JpegCtx*) Decoder->device; uint8_t *Pixels = (uint8_t*) Bitmap; int Shift = 8 - Context->Depth; - + // decoded image is RGB888, shift only make sense for grayscale if (Context->Mode == GDS_RGB888) { OUTHANDLERDIRECT(Scaler888, 0); @@ -167,7 +167,7 @@ static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) { static void* DecodeJPEG(uint8_t *Source, int *Width, int *Height, float Scale, bool SizeOnly, int RGB_Mode) { JDEC Decoder; JpegCtx Context; - char *Scratch = calloc(SCRATCH_SIZE, 1); + char *Scratch = malloc(SCRATCH_SIZE); if (!Scratch) { ESP_LOGE(TAG, "Cannot allocate workspace"); @@ -372,7 +372,7 @@ bool GDS_DrawJPEG(struct GDS_Device* Device, uint8_t *Source, int x, int y, int JDEC Decoder; JpegCtx Context; bool Ret = false; - char *Scratch = calloc(SCRATCH_SIZE, 1); + char *Scratch = malloc(SCRATCH_SIZE); if (!Scratch) { ESP_LOGE(TAG, "Cannot allocate workspace"); diff --git a/components/display/core/gds_private.h b/components/display/core/gds_private.h index 6b098ebe..17203083 100644 --- a/components/display/core/gds_private.h +++ b/components/display/core/gds_private.h @@ -95,7 +95,7 @@ struct GDS_Device { const struct GDS_FontDef* Font; } Lines[MAX_LINES]; - uint16_t Width; + uint16_t Width, TextWidth; uint16_t Height; uint8_t Depth, Mode; @@ -125,7 +125,7 @@ struct GDS_Device { void (*DrawRGB)( struct GDS_Device* Device, uint8_t *Image,int x, int y, int Width, int Height, int RGB_Mode ); void (*ClearWindow)( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ); // may provide for tweaking - void (*SPIParams)(int Speed, uint8_t *mode, uint8_t *CS_pre, uint8_t *CS_post); + void (*SPIParams)(int Speed, uint8_t *mode, uint16_t *CS_pre, uint8_t *CS_post); // interface-specific methods WriteCommandProc WriteCommand; diff --git a/components/display/core/gds_text.c b/components/display/core/gds_text.c index 468414ba..b2ef8903 100644 --- a/components/display/core/gds_text.c +++ b/components/display/core/gds_text.c @@ -100,13 +100,13 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex Width = GDS_FontMeasureString( Device, Text ); // adjusting position, erase only EoL for rigth-justified - if (Pos == GDS_TEXT_RIGHT) X = Device->Width - Width - 1; - else if (Pos == GDS_TEXT_CENTER) X = (Device->Width - Width) / 2; + if (Pos == GDS_TEXT_RIGHT) X = Device->TextWidth - Width - 1; + else if (Pos == GDS_TEXT_CENTER) X = (Device->TextWidth - Width) / 2; // erase if requested if (Attr & GDS_TEXT_CLEAR) { int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height); - for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++) + for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->TextWidth; c++) for (int y = Y_min; y < Y_max; y++) DrawPixelFast( Device, c, y, GDS_COLOR_BLACK ); } @@ -119,7 +119,7 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex Device->Dirty = true; if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device ); - return Width + X < Device->Width; + return Width + X < Device->TextWidth; } /**************************************************************************************** @@ -146,7 +146,7 @@ int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) { // we might already fit GDS_SetFont( Device, Device->Lines[N].Font ); - if (GDS_FontMeasureString( Device, String ) <= Device->Width) return 0; + if (GDS_FontMeasureString( Device, String ) <= Device->TextWidth) return 0; // add some space for better visual strncat(String, Space, Max-Len); @@ -157,7 +157,7 @@ int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) { Boundary = GDS_FontMeasureString( Device, String ); // add a full display width - while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->Width) { + while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->TextWidth) { String[Len++] = String[Extra++]; String[Len] = '\0'; } diff --git a/components/display/core/ifaces/default_if_i2c.c b/components/display/core/ifaces/default_if_i2c.c index 28fd2347..22f5934e 100644 --- a/components/display/core/ifaces/default_if_i2c.c +++ b/components/display/core/ifaces/default_if_i2c.c @@ -75,7 +75,7 @@ bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int Device->RSTPin = RSTPin; Device->Backlight.Pin = BacklightPin; Device->IF = GDS_IF_I2C; - Device->Width = Width; + Device->Width = Device->TextWidth = Width; Device->Height = Height; if ( RSTPin >= 0 ) { diff --git a/components/display/core/ifaces/default_if_spi.c b/components/display/core/ifaces/default_if_spi.c index 968ce51c..1f047584 100644 --- a/components/display/core/ifaces/default_if_spi.c +++ b/components/display/core/ifaces/default_if_spi.c @@ -35,7 +35,7 @@ bool GDS_SPIInit( int SPI, int DC ) { } bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed ) { - spi_device_interface_config_t SPIDeviceConfig; + spi_device_interface_config_t SPIDeviceConfig = { }; spi_device_handle_t SPIDevice; NullCheck( Device, return false ); @@ -45,8 +45,6 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int ESP_ERROR_CHECK_NONFATAL( gpio_set_level( CSPin, 0 ), return false ); } - memset( &SPIDeviceConfig, 0, sizeof( spi_device_interface_config_t ) ); - SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M; SPIDeviceConfig.spics_io_num = CSPin; SPIDeviceConfig.queue_size = 1; @@ -63,7 +61,7 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int Device->CSPin = CSPin; Device->Backlight.Pin = BackLightPin; Device->IF = GDS_IF_SPI; - Device->Width = Width; + Device->Width = Device->TextWidth = Width; Device->Height = Height; if ( RSTPin >= 0 ) { diff --git a/components/display/display.c b/components/display/display.c index 0d965a44..68d6b86a 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -20,6 +20,7 @@ #include "gds_draw.h" #include "gds_text.h" #include "gds_font.h" +#include "gds_image.h" static const char *TAG = "display"; @@ -30,6 +31,9 @@ static const char *TAG = "display"; #define SCROLLABLE_SIZE 384 #define HEADER_SIZE 64 #define DEFAULT_SLEEP 3600 +#define ARTWORK_BORDER 1 + +extern const uint8_t default_artwork[] asm("_binary_note_jpg_start"); static EXT_RAM_ATTR struct { TaskHandle_t task; @@ -47,6 +51,12 @@ static EXT_RAM_ATTR struct { char string[8]; // H:MM:SS bool visible; } duration; + struct { + bool enable, fit; + bool updated; + int tick; + int offset; + } artwork; TickType_t tick; } displayer; @@ -147,6 +157,14 @@ void display_init(char *welcome) { GDS_TextSetFontAuto(display, 2, GDS_FONT_LINE_2, -3); displayer.metadata_config = config_alloc_get(NVS_TYPE_STR, "metadata_config"); + + // leave room for artwork is display is horizontal-style + if (strcasestr(displayer.metadata_config, "artwork")) { + displayer.artwork.enable = true; + displayer.artwork.fit = true; + if (height <= 64 && width > height * 2) displayer.artwork.offset = width - height - ARTWORK_BORDER; + PARSE_PARAM(displayer.metadata_config, "artwork", ':', displayer.artwork.fit); + } } free(config); @@ -225,7 +243,12 @@ static void displayer_task(void *args) { // just re-write the whole line it's easier GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR, displayer.header); GDS_TextLine(display, 1, GDS_TEXT_RIGHT, GDS_TEXT_UPDATE, _line); - + + // if we have not received artwork after 5s, display a default icon + if (displayer.artwork.enable && !displayer.artwork.updated && tick - displayer.artwork.tick > pdMS_TO_TICKS(5000)) { + ESP_LOGI(TAG, "no artwork received, setting default"); + displayer_artwork((uint8_t*) default_artwork); + } timer_sleep = 1000; } else timer_sleep = max(1000 - elapsed, 0); } else timer_sleep = DEFAULT_SLEEP; @@ -238,6 +261,25 @@ static void displayer_task(void *args) { } } +/**************************************************************************************** + * + */ +void displayer_artwork(uint8_t *data) { + if (!displayer.artwork.enable) return; + + int x = displayer.artwork.offset ? displayer.artwork.offset + ARTWORK_BORDER : 0; + int y = x ? 0 : 32; + GDS_ClearWindow(display, x, y, -1, -1, GDS_COLOR_BLACK); + if (data) { + displayer.artwork.updated = true; + GDS_DrawJPEG(display, data, x, y, GDS_IMAGE_CENTER | (displayer.artwork.fit ? GDS_IMAGE_FIT : 0)); + } else { + displayer.artwork.updated = false; + displayer.artwork.tick = xTaskGetTickCount(); + } + +} + /**************************************************************************************** * */ @@ -378,6 +420,7 @@ void displayer_control(enum displayer_cmd_e cmd, ...) { switch(cmd) { case DISPLAYER_ACTIVATE: { char *header = va_arg(args, char*); + bool artwork = va_arg(args, int); strncpy(displayer.header, header, HEADER_SIZE); displayer.header[HEADER_SIZE] = '\0'; displayer.state = DISPLAYER_ACTIVE; @@ -388,6 +431,7 @@ void displayer_control(enum displayer_cmd_e cmd, ...) { displayer.duration.visible = false; displayer.offset = displayer.boundary = 0; display_bus(&displayer, DISPLAY_BUS_TAKE); + if (artwork) GDS_SetTextWidth(display, displayer.artwork.offset); vTaskResume(displayer.task); break; } @@ -398,6 +442,8 @@ void displayer_control(enum displayer_cmd_e cmd, ...) { break; case DISPLAYER_SHUTDOWN: // let the task self-suspend (we might be doing i2c_write) + GDS_SetTextWidth(display, 0); + GDS_Clear(display, GDS_COLOR_BLACK); displayer.state = DISPLAYER_DOWN; display_bus(&displayer, DISPLAY_BUS_GIVE); break; diff --git a/components/display/display.h b/components/display/display.h index 9c945555..ebb857e7 100644 --- a/components/display/display.h +++ b/components/display/display.h @@ -38,5 +38,6 @@ bool display_is_valid_driver(const char * driver); void displayer_scroll(char *string, int speed, int pause); void displayer_control(enum displayer_cmd_e cmd, ...); void displayer_metadata(char *artist, char *album, char *title); +void displayer_artwork(uint8_t *data); void displayer_timer(enum displayer_time_e mode, int elapsed, int duration); char * display_get_supported_drivers(void); diff --git a/components/display/note.jpg b/components/display/note.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6beb3ef7c6e5b7029d45bbf30c2e3594474c933e GIT binary patch literal 11563 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 literal 0 HcmV?d00001 diff --git a/components/driver_bt/bt_app_sink.c b/components/driver_bt/bt_app_sink.c index e741f108..7a3a866b 100644 --- a/components/driver_bt/bt_app_sink.c +++ b/components/driver_bt/bt_app_sink.c @@ -172,7 +172,7 @@ static bool cmd_handler(bt_sink_cmd_t cmd, ...) { // now handle events for display switch(cmd) { case BT_SINK_AUDIO_STARTED: - displayer_control(DISPLAYER_ACTIVATE, "BLUETOOTH"); + displayer_control(DISPLAYER_ACTIVATE, "BLUETOOTH", false); break; case BT_SINK_AUDIO_STOPPED: displayer_control(DISPLAYER_SUSPEND); diff --git a/components/raop/raop.c b/components/raop/raop.c index 53679a78..82f5e8b4 100644 --- a/components/raop/raop.c +++ b/components/raop/raop.c @@ -628,6 +628,9 @@ static bool handle_rtsp(raop_ctx_t *ctx, int sock) success = ctx->cmd_cb(RAOP_METADATA, metadata.artist, metadata.album, metadata.title); free_metadata(&metadata); } + } else if (body && ((p = kd_lookup(headers, "Content-Type")) != NULL) && strcasestr(p, "image/jpeg")) { + LOG_INFO("[%p]: received JPEG image of %d bytes", ctx, len); + ctx->cmd_cb(RAOP_ARTWORK, body, len); } else { char *dump = kd_dump(headers); LOG_INFO("Unhandled SET PARAMETER\n%s", dump); diff --git a/components/raop/raop_sink.c b/components/raop/raop_sink.c index fe66b365..ea3f02f0 100644 --- a/components/raop/raop_sink.c +++ b/components/raop/raop_sink.c @@ -112,7 +112,7 @@ static bool cmd_handler(raop_event_t event, ...) { switch(event) { case RAOP_SETUP: actrls_set(controls, false, NULL, actrls_ir_action); - displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY"); + displayer_control(DISPLAYER_ACTIVATE, "AIRPLAY", true); break; case RAOP_PLAY: displayer_control(DISPLAYER_TIMER_RUN); @@ -127,8 +127,14 @@ static bool cmd_handler(raop_event_t event, ...) { case RAOP_METADATA: { char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*); displayer_metadata(artist, album, title); + displayer_artwork(NULL); break; } + case RAOP_ARTWORK: { + uint8_t *data = va_arg(args, uint8_t*); + displayer_artwork(data); + break; + } case RAOP_PROGRESS: { int elapsed = va_arg(args, int), duration = va_arg(args, int); displayer_timer(DISPLAYER_ELAPSED, elapsed, duration); diff --git a/components/raop/raop_sink.h b/components/raop/raop_sink.h index a3cb87d4..4f6c5dea 100644 --- a/components/raop/raop_sink.h +++ b/components/raop/raop_sink.h @@ -14,7 +14,7 @@ #define RAOP_SAMPLE_RATE 44100 -typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP, +typedef enum { RAOP_SETUP, RAOP_STREAM, RAOP_PLAY, RAOP_FLUSH, RAOP_METADATA, RAOP_ARTWORK, RAOP_PROGRESS, RAOP_PAUSE, RAOP_STOP, RAOP_VOLUME, RAOP_TIMING, RAOP_PREV, RAOP_NEXT, RAOP_REW, RAOP_FWD, RAOP_VOLUME_UP, RAOP_VOLUME_DOWN, RAOP_RESUME, RAOP_TOGGLE } raop_event_t ; diff --git a/components/spotify/Shim.cpp b/components/spotify/Shim.cpp index 87020b8a..fa212257 100644 --- a/components/spotify/Shim.cpp +++ b/components/spotify/Shim.cpp @@ -120,7 +120,8 @@ static void cspotTask(void *pvParameters) { case CSpotEventType::TRACK_INFO: { TrackInfo track = std::get(event.data); // duration is in chunks of 0.5 ms - cspot.cHandler(CSPOT_TRACK, 44100, track.duration / 2, track.artist.c_str(), track.album.c_str(), track.name.c_str()); + cspot.cHandler(CSPOT_TRACK, 44100, track.duration / 2, track.artist.c_str(), + track.album.c_str(), track.name.c_str(), track.imageUrl.c_str()); break; } case CSpotEventType::PLAY_PAUSE: { diff --git a/components/spotify/cspot/CMakeLists.txt b/components/spotify/cspot/CMakeLists.txt index e91c8460..3f5f44ce 100644 --- a/components/spotify/cspot/CMakeLists.txt +++ b/components/spotify/cspot/CMakeLists.txt @@ -45,5 +45,6 @@ endif() add_library(cspot STATIC ${SOURCES} ${PROTO_SRCS}) # PUBLIC to propagate includes from bell to cspot dependents target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC) +target_compile_definitions(bell PUBLIC PB_FIELD_32BIT) target_link_libraries(cspot PUBLIC ${EXTRA_LIBS}) target_include_directories(cspot PUBLIC "include" ${GENERATED_INCLUDES} ${NANOPB_INCLUDE_DIRS}) diff --git a/components/spotify/cspot/bell/CMakeLists.txt b/components/spotify/cspot/bell/CMakeLists.txt index c900048f..2b81a0d4 100644 --- a/components/spotify/cspot/bell/CMakeLists.txt +++ b/components/spotify/cspot/bell/CMakeLists.txt @@ -7,8 +7,6 @@ option(BELL_DISABLE_CODECS "Disable libhelix AAC and MP3 codecs" OFF) #set(BELL_EXTERNAL_CJSON "" CACHE STRING "External cJSON library target name, optional") #set(BELL_EXTERNAL_TREMOR "" CACHE STRING "External tremor library target name, optional") -add_definitions(-DPB_ENABLE_MALLOC) - # Include nanoPB library set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/nanopb/extra) find_package(Nanopb REQUIRED) @@ -98,3 +96,4 @@ message(${NANOPB_INCLUDE_DIRS}) # PUBLIC to propagate esp-idf includes to bell dependents target_link_libraries(bell PUBLIC ${EXTRA_LIBS}) target_include_directories(bell PUBLIC "include" ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) +target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC) diff --git a/components/spotify/cspot/bell/include/NanoPBHelper.h b/components/spotify/cspot/bell/include/NanoPBHelper.h index d370b199..de6a26b1 100644 --- a/components/spotify/cspot/bell/include/NanoPBHelper.h +++ b/components/spotify/cspot/bell/include/NanoPBHelper.h @@ -42,6 +42,10 @@ void pbDecode(T &result, const pb_msgdesc_t *fields, std::vector &data) } } +void pbPutString(const std::string &stringToPack, char* dst); +void pbPutCharArray(const char * stringToPack, char* dst); +void pbPutBytes(const std::vector &data, pb_bytes_array_t &dst); + const char* pb_encode_to_string(const pb_msgdesc_t *fields, const void *data); pb_istream_t pb_istream_from_http(bell::HTTPClient::HTTPResponse *response, size_t length = 0); diff --git a/components/spotify/cspot/bell/src/NanoPBHelper.cpp b/components/spotify/cspot/bell/src/NanoPBHelper.cpp index c19e031d..0bd4c27d 100644 --- a/components/spotify/cspot/bell/src/NanoPBHelper.cpp +++ b/components/spotify/cspot/bell/src/NanoPBHelper.cpp @@ -47,6 +47,22 @@ pb_bytes_array_t* vectorToPbArray(const std::vector& vectorToPack) return result; } +void pbPutString(const std::string &stringToPack, char* dst) { + stringToPack.copy(dst, stringToPack.size()); + dst[stringToPack.size()] = '\0'; +} + +void pbPutCharArray(const char * stringToPack, char* dst) { + // copy stringToPack into dst + strcpy(dst, stringToPack); + //dst[sizeof(stringToPack)-1] = '\0'; +} + +void pbPutBytes(const std::vector &data, pb_bytes_array_t &dst) { + dst.size = data.size(); + std::copy(data.begin(), data.end(), dst.bytes); +} + std::vector pbArrayToVector(pb_bytes_array_t* pbArray) { return std::vector(pbArray->bytes, pbArray->bytes + pbArray->size); } diff --git a/components/spotify/cspot/include/Packet.h b/components/spotify/cspot/include/Packet.h index 7635db87..d7b828f1 100644 --- a/components/spotify/cspot/include/Packet.h +++ b/components/spotify/cspot/include/Packet.h @@ -9,7 +9,7 @@ class Packet private: public: - Packet(uint8_t command, std::vector &data); + Packet(uint8_t command, const std::vector &data); uint8_t command; std::vector data; }; diff --git a/components/spotify/cspot/protobuf/authentication.options b/components/spotify/cspot/protobuf/authentication.options index f7c08e40..33aad19f 100644 --- a/components/spotify/cspot/protobuf/authentication.options +++ b/components/spotify/cspot/protobuf/authentication.options @@ -1,6 +1,5 @@ -LoginCredentials.username type:FT_POINTER -LoginCredentials.auth_data type:FT_POINTER -LoginCredentials.auth_data type:FT_POINTER -SystemInfo.system_information_string type:FT_POINTER -SystemInfo.device_id type:FT_POINTER -ClientResponseEncrypted.version_string type:FT_POINTER \ No newline at end of file +LoginCredentials.username max_size:30, fixed_length:false +LoginCredentials.auth_data max_size:512, fixed_length:false +SystemInfo.system_information_string max_size:16, fixed_length:false +SystemInfo.device_id max_size:50, fixed_length:false +ClientResponseEncrypted.version_string max_size:32, fixed_length:false \ No newline at end of file diff --git a/components/spotify/cspot/protobuf/authentication.pb.c b/components/spotify/cspot/protobuf/authentication.pb.c index b45976af..3e9fd652 100644 --- a/components/spotify/cspot/protobuf/authentication.pb.c +++ b/components/spotify/cspot/protobuf/authentication.pb.c @@ -9,7 +9,7 @@ PB_BIND(SystemInfo, SystemInfo, 2) -PB_BIND(LoginCredentials, LoginCredentials, AUTO) +PB_BIND(LoginCredentials, LoginCredentials, 2) PB_BIND(ClientResponseEncrypted, ClientResponseEncrypted, 2) diff --git a/components/spotify/cspot/protobuf/authentication.pb.h b/components/spotify/cspot/protobuf/authentication.pb.h index a331adfb..e3eb8e91 100644 --- a/components/spotify/cspot/protobuf/authentication.pb.h +++ b/components/spotify/cspot/protobuf/authentication.pb.h @@ -58,23 +58,25 @@ typedef enum _AuthenticationType { } AuthenticationType; /* Struct definitions */ +typedef PB_BYTES_ARRAY_T(512) LoginCredentials_auth_data_t; typedef struct _LoginCredentials { - char *username; + char username[30]; AuthenticationType typ; - pb_bytes_array_t *auth_data; + LoginCredentials_auth_data_t auth_data; } LoginCredentials; typedef struct _SystemInfo { CpuFamily cpu_family; Os os; - char *system_information_string; - char *device_id; + char system_information_string[16]; + char device_id[50]; } SystemInfo; typedef struct _ClientResponseEncrypted { LoginCredentials login_credentials; SystemInfo system_info; - char *version_string; + bool has_version_string; + char version_string[32]; } ClientResponseEncrypted; @@ -97,12 +99,12 @@ extern "C" { #endif /* Initializer values for message structs */ -#define SystemInfo_init_default {_CpuFamily_MIN, _Os_MIN, NULL, NULL} -#define LoginCredentials_init_default {NULL, _AuthenticationType_MIN, NULL} -#define ClientResponseEncrypted_init_default {LoginCredentials_init_default, SystemInfo_init_default, NULL} -#define SystemInfo_init_zero {_CpuFamily_MIN, _Os_MIN, NULL, NULL} -#define LoginCredentials_init_zero {NULL, _AuthenticationType_MIN, NULL} -#define ClientResponseEncrypted_init_zero {LoginCredentials_init_zero, SystemInfo_init_zero, NULL} +#define SystemInfo_init_default {_CpuFamily_MIN, _Os_MIN, "", ""} +#define LoginCredentials_init_default {"", _AuthenticationType_MIN, {0, {0}}} +#define ClientResponseEncrypted_init_default {LoginCredentials_init_default, SystemInfo_init_default, false, ""} +#define SystemInfo_init_zero {_CpuFamily_MIN, _Os_MIN, "", ""} +#define LoginCredentials_init_zero {"", _AuthenticationType_MIN, {0, {0}}} +#define ClientResponseEncrypted_init_zero {LoginCredentials_init_zero, SystemInfo_init_zero, false, ""} /* Field tags (for use in manual encoding/decoding) */ #define LoginCredentials_username_tag 10 @@ -120,22 +122,22 @@ extern "C" { #define SystemInfo_FIELDLIST(X, a) \ X(a, STATIC, REQUIRED, UENUM, cpu_family, 10) \ X(a, STATIC, REQUIRED, UENUM, os, 60) \ -X(a, POINTER, OPTIONAL, STRING, system_information_string, 90) \ -X(a, POINTER, OPTIONAL, STRING, device_id, 100) +X(a, STATIC, REQUIRED, STRING, system_information_string, 90) \ +X(a, STATIC, REQUIRED, STRING, device_id, 100) #define SystemInfo_CALLBACK NULL #define SystemInfo_DEFAULT NULL #define LoginCredentials_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, STRING, username, 10) \ +X(a, STATIC, REQUIRED, STRING, username, 10) \ X(a, STATIC, REQUIRED, UENUM, typ, 20) \ -X(a, POINTER, OPTIONAL, BYTES, auth_data, 30) +X(a, STATIC, REQUIRED, BYTES, auth_data, 30) #define LoginCredentials_CALLBACK NULL #define LoginCredentials_DEFAULT NULL #define ClientResponseEncrypted_FIELDLIST(X, a) \ X(a, STATIC, REQUIRED, MESSAGE, login_credentials, 10) \ X(a, STATIC, REQUIRED, MESSAGE, system_info, 50) \ -X(a, POINTER, OPTIONAL, STRING, version_string, 70) +X(a, STATIC, OPTIONAL, STRING, version_string, 70) #define ClientResponseEncrypted_CALLBACK NULL #define ClientResponseEncrypted_DEFAULT NULL #define ClientResponseEncrypted_login_credentials_MSGTYPE LoginCredentials @@ -151,9 +153,9 @@ extern const pb_msgdesc_t ClientResponseEncrypted_msg; #define ClientResponseEncrypted_fields &ClientResponseEncrypted_msg /* Maximum encoded size of messages (where known) */ -/* SystemInfo_size depends on runtime parameters */ -/* LoginCredentials_size depends on runtime parameters */ -/* ClientResponseEncrypted_size depends on runtime parameters */ +#define ClientResponseEncrypted_size 665 +#define LoginCredentials_size 550 +#define SystemInfo_size 75 #ifdef __cplusplus } /* extern "C" */ diff --git a/components/spotify/cspot/protobuf/authentication.proto b/components/spotify/cspot/protobuf/authentication.proto index 84d1b2ee..d3896147 100644 --- a/components/spotify/cspot/protobuf/authentication.proto +++ b/components/spotify/cspot/protobuf/authentication.proto @@ -48,14 +48,14 @@ enum AuthenticationType { message SystemInfo { required CpuFamily cpu_family = 0xa; required Os os = 0x3c; - optional string system_information_string = 0x5a; - optional string device_id = 0x64; + required string system_information_string = 0x5a; + required string device_id = 0x64; } message LoginCredentials { - optional string username = 0xa; + required string username = 0xa; required AuthenticationType typ = 0x14; - optional bytes auth_data = 0x1e; + required bytes auth_data = 0x1e; } message ClientResponseEncrypted { diff --git a/components/spotify/cspot/protobuf/mercury.options b/components/spotify/cspot/protobuf/mercury.options index f5a10767..29da3dcb 100644 --- a/components/spotify/cspot/protobuf/mercury.options +++ b/components/spotify/cspot/protobuf/mercury.options @@ -1,2 +1,2 @@ -Header.uri type:FT_POINTER -Header.method type:FT_POINTER +Header.uri max_size:64, fixed_length:false +Header.method max_size:32, fixed_length:false diff --git a/components/spotify/cspot/protobuf/mercury.pb.h b/components/spotify/cspot/protobuf/mercury.pb.h index dabc1980..32e61d09 100644 --- a/components/spotify/cspot/protobuf/mercury.pb.h +++ b/components/spotify/cspot/protobuf/mercury.pb.h @@ -11,8 +11,10 @@ /* Struct definitions */ typedef struct _Header { - char *uri; - char *method; + bool has_uri; + char uri[64]; + bool has_method; + char method[32]; } Header; @@ -21,8 +23,8 @@ extern "C" { #endif /* Initializer values for message structs */ -#define Header_init_default {NULL, NULL} -#define Header_init_zero {NULL, NULL} +#define Header_init_default {false, "", false, ""} +#define Header_init_zero {false, "", false, ""} /* Field tags (for use in manual encoding/decoding) */ #define Header_uri_tag 1 @@ -30,8 +32,8 @@ extern "C" { /* Struct field encoding specification for nanopb */ #define Header_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, STRING, uri, 1) \ -X(a, POINTER, OPTIONAL, STRING, method, 3) +X(a, STATIC, OPTIONAL, STRING, uri, 1) \ +X(a, STATIC, OPTIONAL, STRING, method, 3) #define Header_CALLBACK NULL #define Header_DEFAULT NULL @@ -41,7 +43,7 @@ extern const pb_msgdesc_t Header_msg; #define Header_fields &Header_msg /* Maximum encoded size of messages (where known) */ -/* Header_size depends on runtime parameters */ +#define Header_size 98 #ifdef __cplusplus } /* extern "C" */ diff --git a/components/spotify/cspot/protobuf/metadata.options b/components/spotify/cspot/protobuf/metadata.options index 7504a906..3a6341c8 100644 --- a/components/spotify/cspot/protobuf/metadata.options +++ b/components/spotify/cspot/protobuf/metadata.options @@ -1,18 +1,16 @@ -Track.name type:FT_POINTER -Track.gid type:FT_POINTER -Track.restriction type:FT_POINTER -Track.alternative type:FT_POINTER -Track.file type:FT_POINTER -Track.artist type:FT_POINTER -AudioFile.file_id type:FT_POINTER -Image.file_id type:FT_POINTER -Artist.gid type:FT_POINTER -Artist.name type:FT_POINTER -Album.name type:FT_POINTER -Episode.gid type:FT_POINTER -Episode.name type:FT_POINTER -ImageGroup.image type:FT_POINTER -Episode.audio type:FT_POINTER -Episode.covers type:FT_POINTER -Restriction.countries_allowed type:FT_POINTER -Restriction.countries_forbidden type:FT_POINTER \ No newline at end of file +Track.name max_size: 512 +Track.gid max_size: 64 +Track.file max_count: 16 +Track.artist max_count: 8 +AudioFile.file_id max_size: 128 +Image.file_id max_size: 128 +Artist.gid max_size: 128 +Artist.name max_size: 512 +Album.name max_size: 512 +Episode.gid max_size: 64 +Episode.name max_size: 512 +ImageGroup.image max_count: 10 +Episode.audio max_count: 10 +Episode.covers max_count: 10 +Restriction.countries_allowed max_size: 32 +Restriction.countries_forbidden max_size: 32 \ No newline at end of file diff --git a/components/spotify/cspot/protobuf/metadata.pb.c b/components/spotify/cspot/protobuf/metadata.pb.c index 7196e0cf..78014778 100644 --- a/components/spotify/cspot/protobuf/metadata.pb.c +++ b/components/spotify/cspot/protobuf/metadata.pb.c @@ -15,16 +15,16 @@ PB_BIND(Restriction, Restriction, AUTO) PB_BIND(Image, Image, AUTO) -PB_BIND(ImageGroup, ImageGroup, AUTO) +PB_BIND(ImageGroup, ImageGroup, 2) -PB_BIND(Album, Album, AUTO) +PB_BIND(Album, Album, 2) -PB_BIND(Artist, Artist, AUTO) +PB_BIND(Artist, Artist, 2) -PB_BIND(Track, Track, AUTO) +PB_BIND(Track, Track, 4) PB_BIND(Episode, Episode, 2) diff --git a/components/spotify/cspot/protobuf/metadata.pb.h b/components/spotify/cspot/protobuf/metadata.pb.h index fa196fa8..7def594b 100644 --- a/components/spotify/cspot/protobuf/metadata.pb.h +++ b/components/spotify/cspot/protobuf/metadata.pb.h @@ -24,63 +24,78 @@ typedef enum _AudioFormat { } AudioFormat; /* Struct definitions */ +typedef PB_BYTES_ARRAY_T(128) Artist_gid_t; typedef struct _Artist { - pb_bytes_array_t *gid; - char *name; + bool has_gid; + Artist_gid_t gid; + bool has_name; + char name[512]; } Artist; -typedef struct _Image { - pb_bytes_array_t *file_id; -} Image; - -typedef struct _ImageGroup { - pb_size_t image_count; - struct _Image *image; -} ImageGroup; - -typedef struct _Restriction { - char *countries_allowed; - char *countries_forbidden; -} Restriction; - -typedef struct _Album { - pb_callback_t gid; - char *name; - bool has_cover_group; - ImageGroup cover_group; -} Album; - +typedef PB_BYTES_ARRAY_T(128) AudioFile_file_id_t; typedef struct _AudioFile { - pb_bytes_array_t *file_id; + bool has_file_id; + AudioFile_file_id_t file_id; bool has_format; AudioFormat format; } AudioFile; +typedef PB_BYTES_ARRAY_T(128) Image_file_id_t; +typedef struct _Image { + bool has_file_id; + Image_file_id_t file_id; +} Image; + +typedef struct _Restriction { + bool has_countries_allowed; + char countries_allowed[32]; + bool has_countries_forbidden; + char countries_forbidden[32]; +} Restriction; + +typedef struct _ImageGroup { + pb_size_t image_count; + Image image[10]; +} ImageGroup; + +typedef struct _Album { + pb_callback_t gid; + bool has_name; + char name[512]; + bool has_cover_group; + ImageGroup cover_group; +} Album; + +typedef PB_BYTES_ARRAY_T(64) Episode_gid_t; typedef struct _Episode { - pb_bytes_array_t *gid; - char *name; + bool has_gid; + Episode_gid_t gid; + bool has_name; + char name[512]; bool has_duration; int32_t duration; pb_size_t audio_count; - struct _AudioFile *audio; - struct _ImageGroup *covers; + AudioFile audio[10]; + bool has_covers; + ImageGroup covers; } Episode; +typedef PB_BYTES_ARRAY_T(64) Track_gid_t; typedef struct _Track { - pb_bytes_array_t *gid; - char *name; + bool has_gid; + Track_gid_t gid; + bool has_name; + char name[512]; bool has_album; Album album; pb_size_t artist_count; - struct _Artist *artist; + Artist artist[8]; bool has_duration; int32_t duration; - pb_size_t restriction_count; - struct _Restriction *restriction; + pb_callback_t restriction; pb_size_t file_count; - struct _AudioFile *file; - pb_size_t alternative_count; - struct _Track *alternative; + AudioFile file[16]; + pb_callback_t alternative; } Track; @@ -95,35 +110,35 @@ extern "C" { #endif /* Initializer values for message structs */ -#define AudioFile_init_default {NULL, false, _AudioFormat_MIN} -#define Restriction_init_default {NULL, NULL} -#define Image_init_default {NULL} -#define ImageGroup_init_default {0, NULL} -#define Album_init_default {{{NULL}, NULL}, NULL, false, ImageGroup_init_default} -#define Artist_init_default {NULL, NULL} -#define Track_init_default {NULL, NULL, false, Album_init_default, 0, NULL, false, 0, 0, NULL, 0, NULL, 0, NULL} -#define Episode_init_default {NULL, NULL, false, 0, 0, NULL, NULL} -#define AudioFile_init_zero {NULL, false, _AudioFormat_MIN} -#define Restriction_init_zero {NULL, NULL} -#define Image_init_zero {NULL} -#define ImageGroup_init_zero {0, NULL} -#define Album_init_zero {{{NULL}, NULL}, NULL, false, ImageGroup_init_zero} -#define Artist_init_zero {NULL, NULL} -#define Track_init_zero {NULL, NULL, false, Album_init_zero, 0, NULL, false, 0, 0, NULL, 0, NULL, 0, NULL} -#define Episode_init_zero {NULL, NULL, false, 0, 0, NULL, NULL} +#define AudioFile_init_default {false, {0, {0}}, false, _AudioFormat_MIN} +#define Restriction_init_default {false, "", false, ""} +#define Image_init_default {false, {0, {0}}} +#define ImageGroup_init_default {0, {Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default}} +#define Album_init_default {{{NULL}, NULL}, false, "", false, ImageGroup_init_default} +#define Artist_init_default {false, {0, {0}}, false, ""} +#define Track_init_default {false, {0, {0}}, false, "", false, Album_init_default, 0, {Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default}, false, 0, {{NULL}, NULL}, 0, {AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default}, {{NULL}, NULL}} +#define Episode_init_default {false, {0, {0}}, false, "", false, 0, 0, {AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default}, false, ImageGroup_init_default} +#define AudioFile_init_zero {false, {0, {0}}, false, _AudioFormat_MIN} +#define Restriction_init_zero {false, "", false, ""} +#define Image_init_zero {false, {0, {0}}} +#define ImageGroup_init_zero {0, {Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero}} +#define Album_init_zero {{{NULL}, NULL}, false, "", false, ImageGroup_init_zero} +#define Artist_init_zero {false, {0, {0}}, false, ""} +#define Track_init_zero {false, {0, {0}}, false, "", false, Album_init_zero, 0, {Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero}, false, 0, {{NULL}, NULL}, 0, {AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero}, {{NULL}, NULL}} +#define Episode_init_zero {false, {0, {0}}, false, "", false, 0, 0, {AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero}, false, ImageGroup_init_zero} /* Field tags (for use in manual encoding/decoding) */ #define Artist_gid_tag 1 #define Artist_name_tag 2 +#define AudioFile_file_id_tag 1 +#define AudioFile_format_tag 2 #define Image_file_id_tag 1 -#define ImageGroup_image_tag 1 #define Restriction_countries_allowed_tag 2 #define Restriction_countries_forbidden_tag 3 +#define ImageGroup_image_tag 1 #define Album_gid_tag 1 #define Album_name_tag 2 #define Album_cover_group_tag 17 -#define AudioFile_file_id_tag 1 -#define AudioFile_format_tag 2 #define Episode_gid_tag 1 #define Episode_name_tag 2 #define Episode_duration_tag 7 @@ -140,52 +155,52 @@ extern "C" { /* Struct field encoding specification for nanopb */ #define AudioFile_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, BYTES, file_id, 1) \ +X(a, STATIC, OPTIONAL, BYTES, file_id, 1) \ X(a, STATIC, OPTIONAL, UENUM, format, 2) #define AudioFile_CALLBACK NULL #define AudioFile_DEFAULT NULL #define Restriction_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, STRING, countries_allowed, 2) \ -X(a, POINTER, OPTIONAL, STRING, countries_forbidden, 3) +X(a, STATIC, OPTIONAL, STRING, countries_allowed, 2) \ +X(a, STATIC, OPTIONAL, STRING, countries_forbidden, 3) #define Restriction_CALLBACK NULL #define Restriction_DEFAULT NULL #define Image_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, BYTES, file_id, 1) +X(a, STATIC, OPTIONAL, BYTES, file_id, 1) #define Image_CALLBACK NULL #define Image_DEFAULT NULL #define ImageGroup_FIELDLIST(X, a) \ -X(a, POINTER, REPEATED, MESSAGE, image, 1) +X(a, STATIC, REPEATED, MESSAGE, image, 1) #define ImageGroup_CALLBACK NULL #define ImageGroup_DEFAULT NULL #define ImageGroup_image_MSGTYPE Image #define Album_FIELDLIST(X, a) \ X(a, CALLBACK, OPTIONAL, BYTES, gid, 1) \ -X(a, POINTER, OPTIONAL, STRING, name, 2) \ +X(a, STATIC, OPTIONAL, STRING, name, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, cover_group, 17) #define Album_CALLBACK pb_default_field_callback #define Album_DEFAULT NULL #define Album_cover_group_MSGTYPE ImageGroup #define Artist_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ -X(a, POINTER, OPTIONAL, STRING, name, 2) +X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ +X(a, STATIC, OPTIONAL, STRING, name, 2) #define Artist_CALLBACK NULL #define Artist_DEFAULT NULL #define Track_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ -X(a, POINTER, OPTIONAL, STRING, name, 2) \ +X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ +X(a, STATIC, OPTIONAL, STRING, name, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, album, 3) \ -X(a, POINTER, REPEATED, MESSAGE, artist, 4) \ +X(a, STATIC, REPEATED, MESSAGE, artist, 4) \ X(a, STATIC, OPTIONAL, SINT32, duration, 7) \ -X(a, POINTER, REPEATED, MESSAGE, restriction, 11) \ -X(a, POINTER, REPEATED, MESSAGE, file, 12) \ -X(a, POINTER, REPEATED, MESSAGE, alternative, 13) -#define Track_CALLBACK NULL +X(a, CALLBACK, REPEATED, MESSAGE, restriction, 11) \ +X(a, STATIC, REPEATED, MESSAGE, file, 12) \ +X(a, CALLBACK, REPEATED, MESSAGE, alternative, 13) +#define Track_CALLBACK pb_default_field_callback #define Track_DEFAULT NULL #define Track_album_MSGTYPE Album #define Track_artist_MSGTYPE Artist @@ -194,11 +209,11 @@ X(a, POINTER, REPEATED, MESSAGE, alternative, 13) #define Track_alternative_MSGTYPE Track #define Episode_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ -X(a, POINTER, OPTIONAL, STRING, name, 2) \ +X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ +X(a, STATIC, OPTIONAL, STRING, name, 2) \ X(a, STATIC, OPTIONAL, SINT32, duration, 7) \ -X(a, POINTER, REPEATED, MESSAGE, audio, 12) \ -X(a, POINTER, OPTIONAL, MESSAGE, covers, 68) +X(a, STATIC, REPEATED, MESSAGE, audio, 12) \ +X(a, STATIC, OPTIONAL, MESSAGE, covers, 68) #define Episode_CALLBACK NULL #define Episode_DEFAULT NULL #define Episode_audio_MSGTYPE AudioFile @@ -224,14 +239,14 @@ extern const pb_msgdesc_t Episode_msg; #define Episode_fields &Episode_msg /* Maximum encoded size of messages (where known) */ -/* AudioFile_size depends on runtime parameters */ -/* Restriction_size depends on runtime parameters */ -/* Image_size depends on runtime parameters */ -/* ImageGroup_size depends on runtime parameters */ /* Album_size depends on runtime parameters */ -/* Artist_size depends on runtime parameters */ /* Track_size depends on runtime parameters */ -/* Episode_size depends on runtime parameters */ +#define Artist_size 645 +#define AudioFile_size 133 +#define Episode_size 3290 +#define ImageGroup_size 1340 +#define Image_size 131 +#define Restriction_size 66 #ifdef __cplusplus } /* extern "C" */ diff --git a/components/spotify/cspot/protobuf/spirc.options b/components/spotify/cspot/protobuf/spirc.options index 5f853084..8684cadf 100644 --- a/components/spotify/cspot/protobuf/spirc.options +++ b/components/spotify/cspot/protobuf/spirc.options @@ -1,13 +1,12 @@ -Frame.ident type:FT_POINTER -Frame.protocol_version type:FT_POINTER -Frame.recipient type:FT_POINTER +Frame.ident max_size: 64, fixed_length:false +Frame.protocol_version max_size: 64, fixed_length:false +Frame.recipient max_count: 64, max_size: 64 Capability.stringValue max_count:50, max_size: 50 Capability.intValue max_count:50 -DeviceState.sw_version type:FT_POINTER -DeviceState.name type:FT_POINTER +DeviceState.sw_version max_size: 64, fixed_length:false +DeviceState.name max_size: 64, fixed_length:false DeviceState.capabilities max_count:17, fixed_count:false -State.context_uri type:FT_POINTER +State.context_uri max_size: 256, fixed_length:false State.track max_count:100, fixed_count:false -TrackRef.gid type:FT_POINTER -TrackRef.uri type:FT_POINTER -TrackRef.context type:FT_POINTER \ No newline at end of file +TrackRef.gid max_size: 128, fixed_length:false +TrackRef.uri max_size: 256 fixed_length:false diff --git a/components/spotify/cspot/protobuf/spirc.pb.c b/components/spotify/cspot/protobuf/spirc.pb.c index f6dfc4b1..99304244 100644 --- a/components/spotify/cspot/protobuf/spirc.pb.c +++ b/components/spotify/cspot/protobuf/spirc.pb.c @@ -6,7 +6,7 @@ #error Regenerate this file with the current version of nanopb generator. #endif -PB_BIND(TrackRef, TrackRef, AUTO) +PB_BIND(TrackRef, TrackRef, 2) PB_BIND(State, State, 4) diff --git a/components/spotify/cspot/protobuf/spirc.pb.h b/components/spotify/cspot/protobuf/spirc.pb.h index 9ebc82b6..810fc6d3 100644 --- a/components/spotify/cspot/protobuf/spirc.pb.h +++ b/components/spotify/cspot/protobuf/spirc.pb.h @@ -62,23 +62,28 @@ typedef struct _Capability { char stringValue[50][50]; } Capability; +typedef PB_BYTES_ARRAY_T(128) TrackRef_gid_t; typedef struct _TrackRef { - pb_bytes_array_t *gid; - char *uri; + bool has_gid; + TrackRef_gid_t gid; + bool has_uri; + char uri[256]; bool has_queued; bool queued; - char *context; + pb_callback_t context; } TrackRef; typedef struct _DeviceState { - char *sw_version; + bool has_sw_version; + char sw_version[64]; bool has_is_active; bool is_active; bool has_can_play; bool can_play; bool has_volume; uint32_t volume; - char *name; + bool has_name; + char name[64]; bool has_error_code; uint32_t error_code; bool has_became_active_at; @@ -90,7 +95,8 @@ typedef struct _DeviceState { } DeviceState; typedef struct _State { - char *context_uri; + bool has_context_uri; + char context_uri[256]; bool has_index; uint32_t index; bool has_position_ms; @@ -113,8 +119,10 @@ typedef struct _State { typedef struct _Frame { bool has_version; uint32_t version; - char *ident; - char *protocol_version; + bool has_ident; + char ident[64]; + bool has_protocol_version; + char protocol_version[64]; bool has_seq_nr; uint32_t seq_nr; bool has_typ; @@ -130,7 +138,7 @@ typedef struct _Frame { bool has_state_update_id; int64_t state_update_id; pb_size_t recipient_count; - char **recipient; + char recipient[64][64]; } Frame; @@ -153,16 +161,16 @@ extern "C" { #endif /* Initializer values for message structs */ -#define TrackRef_init_default {NULL, NULL, false, 0, NULL} -#define State_init_default {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default}} +#define TrackRef_init_default {false, {0, {0}}, false, "", false, 0, {{NULL}, NULL}} +#define State_init_default {false, "", false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default}} #define Capability_init_default {false, _CapabilityType_MIN, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} -#define DeviceState_init_default {NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default}, {{NULL}, NULL}} -#define Frame_init_default {false, 0, NULL, NULL, false, 0, false, _MessageType_MIN, false, DeviceState_init_default, false, State_init_default, false, 0, false, 0, false, 0, 0, NULL} -#define TrackRef_init_zero {NULL, NULL, false, 0, NULL} -#define State_init_zero {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero}} +#define DeviceState_init_default {false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default}, {{NULL}, NULL}} +#define Frame_init_default {false, 0, false, "", false, "", false, 0, false, _MessageType_MIN, false, DeviceState_init_default, false, State_init_default, false, 0, false, 0, false, 0, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} +#define TrackRef_init_zero {false, {0, {0}}, false, "", false, 0, {{NULL}, NULL}} +#define State_init_zero {false, "", false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero}} #define Capability_init_zero {false, _CapabilityType_MIN, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} -#define DeviceState_init_zero {NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero}, {{NULL}, NULL}} -#define Frame_init_zero {false, 0, NULL, NULL, false, 0, false, _MessageType_MIN, false, DeviceState_init_zero, false, State_init_zero, false, 0, false, 0, false, 0, 0, NULL} +#define DeviceState_init_zero {false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero}, {{NULL}, NULL}} +#define Frame_init_zero {false, 0, false, "", false, "", false, 0, false, _MessageType_MIN, false, DeviceState_init_zero, false, State_init_zero, false, 0, false, 0, false, 0, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} /* Field tags (for use in manual encoding/decoding) */ #define Capability_typ_tag 1 @@ -206,15 +214,15 @@ extern "C" { /* Struct field encoding specification for nanopb */ #define TrackRef_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ -X(a, POINTER, OPTIONAL, STRING, uri, 2) \ +X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ +X(a, STATIC, OPTIONAL, STRING, uri, 2) \ X(a, STATIC, OPTIONAL, BOOL, queued, 3) \ -X(a, POINTER, OPTIONAL, STRING, context, 4) -#define TrackRef_CALLBACK NULL +X(a, CALLBACK, OPTIONAL, STRING, context, 4) +#define TrackRef_CALLBACK pb_default_field_callback #define TrackRef_DEFAULT NULL #define State_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, STRING, context_uri, 2) \ +X(a, STATIC, OPTIONAL, STRING, context_uri, 2) \ X(a, STATIC, OPTIONAL, UINT32, index, 3) \ X(a, STATIC, OPTIONAL, UINT32, position_ms, 4) \ X(a, STATIC, OPTIONAL, UENUM, status, 5) \ @@ -236,11 +244,11 @@ X(a, STATIC, REPEATED, STRING, stringValue, 3) #define Capability_DEFAULT (const pb_byte_t*)"\x08\x01\x00" #define DeviceState_FIELDLIST(X, a) \ -X(a, POINTER, OPTIONAL, STRING, sw_version, 1) \ +X(a, STATIC, OPTIONAL, STRING, sw_version, 1) \ X(a, STATIC, OPTIONAL, BOOL, is_active, 10) \ X(a, STATIC, OPTIONAL, BOOL, can_play, 11) \ X(a, STATIC, OPTIONAL, UINT32, volume, 12) \ -X(a, POINTER, OPTIONAL, STRING, name, 13) \ +X(a, STATIC, OPTIONAL, STRING, name, 13) \ X(a, STATIC, OPTIONAL, UINT32, error_code, 14) \ X(a, STATIC, OPTIONAL, INT64, became_active_at, 15) \ X(a, CALLBACK, OPTIONAL, STRING, error_message, 16) \ @@ -252,8 +260,8 @@ X(a, CALLBACK, REPEATED, STRING, local_uris, 18) #define Frame_FIELDLIST(X, a) \ X(a, STATIC, OPTIONAL, UINT32, version, 1) \ -X(a, POINTER, OPTIONAL, STRING, ident, 2) \ -X(a, POINTER, OPTIONAL, STRING, protocol_version, 3) \ +X(a, STATIC, OPTIONAL, STRING, ident, 2) \ +X(a, STATIC, OPTIONAL, STRING, protocol_version, 3) \ X(a, STATIC, OPTIONAL, UINT32, seq_nr, 4) \ X(a, STATIC, OPTIONAL, UENUM, typ, 5) \ X(a, STATIC, OPTIONAL, MESSAGE, device_state, 7) \ @@ -261,7 +269,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, state, 12) \ X(a, STATIC, OPTIONAL, UINT32, position, 13) \ X(a, STATIC, OPTIONAL, UINT32, volume, 14) \ X(a, STATIC, OPTIONAL, INT64, state_update_id, 17) \ -X(a, POINTER, REPEATED, STRING, recipient, 18) +X(a, STATIC, REPEATED, STRING, recipient, 18) #define Frame_CALLBACK NULL #define Frame_DEFAULT (const pb_byte_t*)"\x28\x01\x00" #define Frame_device_state_MSGTYPE DeviceState diff --git a/components/spotify/cspot/src/MercuryManager.cpp b/components/spotify/cspot/src/MercuryManager.cpp index 62c842f3..36a3d9d3 100644 --- a/components/spotify/cspot/src/MercuryManager.cpp +++ b/components/spotify/cspot/src/MercuryManager.cpp @@ -11,7 +11,7 @@ std::map MercuryTypeMap({ MercuryManager::MercuryManager(std::unique_ptr session): bell::Task("mercuryManager", 6 * 1024, 2, 1) { - tempMercuryHeader = Header_init_default; + tempMercuryHeader = {}; this->timeProvider = std::make_shared(); this->callbacks = std::map(); this->subscriptions = std::map(); @@ -294,8 +294,11 @@ uint64_t MercuryManager::execute(MercuryType method, std::string uri, mercuryCal // Construct mercury header CSPOT_LOG(debug, "executing MercuryType %s", MercuryTypeMap[method].c_str()); - tempMercuryHeader.uri = (char *)(uri.c_str()); - tempMercuryHeader.method = (char *)(MercuryTypeMap[method].c_str()); + pbPutString(uri, tempMercuryHeader.uri); + pbPutString(MercuryTypeMap[method], tempMercuryHeader.method); + + tempMercuryHeader.has_method = true; + tempMercuryHeader.has_uri = true; // GET and SEND are actually the same. Therefore the override // The difference between them is only in header's method diff --git a/components/spotify/cspot/src/MercuryResponse.cpp b/components/spotify/cspot/src/MercuryResponse.cpp index 7026e98f..46dd8a48 100644 --- a/components/spotify/cspot/src/MercuryResponse.cpp +++ b/components/spotify/cspot/src/MercuryResponse.cpp @@ -3,13 +3,12 @@ MercuryResponse::MercuryResponse(std::vector &data) { // this->mercuryHeader = std::make_unique
(); - this->mercuryHeader = Header_init_default; + this->mercuryHeader = {}; this->parts = mercuryParts(0); this->parseResponse(data); } MercuryResponse::~MercuryResponse() { - pb_release(Header_fields, &mercuryHeader); } void MercuryResponse::parseResponse(std::vector &data) diff --git a/components/spotify/cspot/src/Packet.cpp b/components/spotify/cspot/src/Packet.cpp index 534e7cba..f7e0a503 100644 --- a/components/spotify/cspot/src/Packet.cpp +++ b/components/spotify/cspot/src/Packet.cpp @@ -1,6 +1,6 @@ #include "Packet.h" -Packet::Packet(uint8_t command, std::vector &data) { +Packet::Packet(uint8_t command, const std::vector &data) { this->command = command; this->data = data; }; \ No newline at end of file diff --git a/components/spotify/cspot/src/PlayerState.cpp b/components/spotify/cspot/src/PlayerState.cpp index 2b3f9aea..8e5066d9 100644 --- a/components/spotify/cspot/src/PlayerState.cpp +++ b/components/spotify/cspot/src/PlayerState.cpp @@ -24,7 +24,8 @@ PlayerState::PlayerState(std::shared_ptr timeProvider) innerFrame.state.repeat = false; innerFrame.state.has_repeat = true; - innerFrame.device_state.sw_version = (char*) swVersion; + innerFrame.device_state.has_sw_version = true; + pbPutCharArray(swVersion, innerFrame.device_state.sw_version); innerFrame.device_state.is_active = false; innerFrame.device_state.has_is_active = true; @@ -35,7 +36,8 @@ PlayerState::PlayerState(std::shared_ptr timeProvider) innerFrame.device_state.volume = configMan->volume; innerFrame.device_state.has_volume = true; - innerFrame.device_state.name = (char*) configMan->deviceName.c_str(); + innerFrame.device_state.has_name = true; + pbPutString(configMan->deviceName, innerFrame.device_state.name); // Prepare player's capabilities addCapability(CapabilityType_kCanBePlayer, 1); @@ -137,7 +139,8 @@ void PlayerState::updatePositionMs(uint32_t position) void PlayerState::updateTracks() { CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count); - innerFrame.state.context_uri = remoteFrame.state.context_uri == nullptr ? nullptr : strdup(remoteFrame.state.context_uri); + strcpy(innerFrame.state.context_uri, remoteFrame.state.context_uri); + std::copy(std::begin(remoteFrame.state.track), std::end(remoteFrame.state.track), std::begin(innerFrame.state.track)); innerFrame.state.track_count = remoteFrame.state.track_count; innerFrame.state.has_playing_track_index = true; @@ -198,9 +201,14 @@ std::vector PlayerState::encodeCurrentFrame(MessageType typ) { // Prepare current frame info innerFrame.version = 1; - innerFrame.ident = (char *) deviceId; + + pbPutCharArray(deviceId, innerFrame.ident); + innerFrame.has_ident = true; + innerFrame.seq_nr = this->seqNum; - innerFrame.protocol_version = (char*) protocolVersion; + pbPutCharArray(protocolVersion, innerFrame.protocol_version); + innerFrame.has_protocol_version = true; + innerFrame.typ = typ; innerFrame.state_update_id = timeProvider->getSyncedTimestamp(); innerFrame.has_version = true; diff --git a/components/spotify/cspot/src/Session.cpp b/components/spotify/cspot/src/Session.cpp index 4a51c4d9..638ef7f3 100644 --- a/components/spotify/cspot/src/Session.cpp +++ b/components/spotify/cspot/src/Session.cpp @@ -49,17 +49,26 @@ std::vector Session::authenticate(std::shared_ptr blob) authBlob = blob; // prepare authentication request proto - authRequest.login_credentials.username = (char *)(blob->username.c_str()); - authRequest.login_credentials.auth_data = vectorToPbArray(blob->authData); + pbPutString(blob->username, authRequest.login_credentials.username); + + std::copy(blob->authData.begin(), blob->authData.end(), authRequest.login_credentials.auth_data.bytes); + authRequest.login_credentials.auth_data.size = blob->authData.size(); + authRequest.login_credentials.typ = (AuthenticationType) blob->authType; authRequest.system_info.cpu_family = CpuFamily_CPU_UNKNOWN; authRequest.system_info.os = Os_OS_UNKNOWN; - authRequest.system_info.system_information_string = (char *)informationString; - authRequest.system_info.device_id = (char *)deviceId; - authRequest.version_string = (char *)versionString; + + auto infoStr = std::string(informationString); + pbPutString(infoStr, authRequest.system_info.system_information_string); + + auto deviceIdStr = std::string(deviceId); + pbPutString(deviceId, authRequest.system_info.device_id); + + auto versionStr = std::string(versionString); + pbPutString(versionStr, authRequest.version_string); + authRequest.has_version_string = true; auto data = pbEncode(ClientResponseEncrypted_fields, &authRequest); - free(authRequest.login_credentials.auth_data); // Send login request this->shanConn->sendPacket(LOGIN_REQUEST_COMMAND, data); diff --git a/components/spotify/cspot/src/SpotifyTrack.cpp b/components/spotify/cspot/src/SpotifyTrack.cpp index 6db0416c..e172bbd1 100644 --- a/components/spotify/cspot/src/SpotifyTrack.cpp +++ b/components/spotify/cspot/src/SpotifyTrack.cpp @@ -10,8 +10,8 @@ SpotifyTrack::SpotifyTrack(std::shared_ptr manager, std::shared_ { this->manager = manager; this->fileId = std::vector(); - episodeInfo = Episode_init_default; - trackInfo = Track_init_default; + episodeInfo = {}; + trackInfo = {}; mercuryCallback trackResponseLambda = [=](std::unique_ptr res) { this->trackInformationCallback(std::move(res), position_ms, isPaused); @@ -53,18 +53,18 @@ bool SpotifyTrack::countryListContains(std::string countryList, std::string coun bool SpotifyTrack::canPlayTrack() { - for (int x = 0; x < trackInfo.restriction_count; x++) - { - if (trackInfo.restriction[x].countries_allowed != nullptr) - { - return countryListContains(std::string(trackInfo.restriction[x].countries_allowed), manager->countryCode); - } - - if (trackInfo.restriction[x].countries_forbidden != nullptr) - { - return !countryListContains(std::string(trackInfo.restriction[x].countries_forbidden), manager->countryCode); - } - } +// for (int x = 0; x < trackInfo.restriction_count; x++) +// { +// if (strlen(trackInfo.restriction[x].countries_allowed) > 0) +// { +// return countryListContains(std::string(trackInfo.restriction[x].countries_allowed), manager->countryCode); +// } +// +// if (strlen(trackInfo.restriction[x].countries_forbidden) > 0) +// { +// return !countryListContains(std::string(trackInfo.restriction[x].countries_forbidden), manager->countryCode); +// } +// } return true; } @@ -77,35 +77,39 @@ void SpotifyTrack::trackInformationCallback(std::unique_ptr res pb_release(Track_fields, &trackInfo); pbDecode(trackInfo, Track_fields, response->parts[0]); +// +// CSPOT_LOG(info, "Track name: %s", trackInfo.name); +// CSPOT_LOG(info, "Track duration: %d", trackInfo.duration); +// CSPOT_LOG(debug, "trackInfo.restriction.size() = %d", trackInfo.restriction_count); +// int altIndex = 0; +// while (!canPlayTrack()) +// { +// auto src = trackInfo.alternative[altIndex].restriction; +//// std::copy(std::begin(src), std::end(src), std::begin(trackInfo.restriction)); +//// trackInfo.restriction_count = trackInfo.alternative[altIndex].restriction_count; +//// +//// free(trackInfo.gid); +// trackInfo.gid = trackInfo.alternative[altIndex].gid; +// altIndex++; +// CSPOT_LOG(info, "Trying alternative %d", altIndex); +// } - CSPOT_LOG(info, "Track name: %s", trackInfo.name); - CSPOT_LOG(info, "Track duration: %d", trackInfo.duration); - CSPOT_LOG(debug, "trackInfo.restriction.size() = %d", trackInfo.restriction_count); - int altIndex = 0; - while (!canPlayTrack()) - { - trackInfo.restriction = trackInfo.alternative[altIndex].restriction; - trackInfo.restriction_count = trackInfo.alternative[altIndex].restriction_count; - trackInfo.gid = trackInfo.alternative[altIndex].gid; - trackInfo.file = trackInfo.alternative[altIndex].file; - altIndex++; - CSPOT_LOG(info, "Trying alternative %d", altIndex); - } - auto trackId = pbArrayToVector(trackInfo.gid); + auto trackId = std::vector(trackInfo.gid.bytes, trackInfo.gid.bytes + trackInfo.gid.size); this->fileId = std::vector(); for (int x = 0; x < trackInfo.file_count; x++) { if (trackInfo.file[x].format == configMan->format) { - this->fileId = pbArrayToVector(trackInfo.file[x].file_id); + this->fileId = std::vector(trackInfo.file[x].file_id.bytes, trackInfo.file[x].file_id.bytes + trackInfo.file[x].file_id.size); break; // If file found stop searching } } if (trackInfoReceived != nullptr) { - auto imageId = pbArrayToVector(trackInfo.album.cover_group.image[0].file_id); + auto imageIdBytes = trackInfo.album.cover_group.image[0].file_id; + auto imageId = std::vector(imageIdBytes.bytes, imageIdBytes.bytes + imageIdBytes.size); TrackInfo simpleTrackInfo = { .name = std::string(trackInfo.name), .album = std::string(trackInfo.album.name), @@ -139,14 +143,15 @@ void SpotifyTrack::episodeInformationCallback(std::unique_ptr r { if (episodeInfo.audio[x].format == AudioFormat_OGG_VORBIS_96) { - this->fileId = pbArrayToVector(episodeInfo.audio[x].file_id); + this->fileId = std::vector(episodeInfo.audio[x].file_id.bytes, episodeInfo.audio[x].file_id.bytes + episodeInfo.audio[x].file_id.size); break; // If file found stop searching } } if (trackInfoReceived != nullptr) { - auto imageId = pbArrayToVector(episodeInfo.covers->image[0].file_id); + auto imageFileId = episodeInfo.covers.image[0].file_id; + auto imageId = std::vector(imageFileId.bytes, imageFileId.bytes + imageFileId.size); TrackInfo simpleTrackInfo = { .name = std::string(episodeInfo.name), .album = "", @@ -159,7 +164,7 @@ void SpotifyTrack::episodeInformationCallback(std::unique_ptr r trackInfoReceived(simpleTrackInfo); } - this->requestAudioKey(pbArrayToVector(episodeInfo.gid), this->fileId, episodeInfo.duration, position_ms, isPaused); + this->requestAudioKey(std::vector(episodeInfo.gid.bytes, episodeInfo.gid.bytes + episodeInfo.gid.size), this->fileId, episodeInfo.duration, position_ms, isPaused); } void SpotifyTrack::requestAudioKey(std::vector fileId, std::vector trackId, int32_t trackDuration, uint32_t position_ms, bool isPaused) diff --git a/components/spotify/cspot/src/TrackReference.cpp b/components/spotify/cspot/src/TrackReference.cpp index e51afb35..a165c39a 100644 --- a/components/spotify/cspot/src/TrackReference.cpp +++ b/components/spotify/cspot/src/TrackReference.cpp @@ -3,11 +3,11 @@ TrackReference::TrackReference(TrackRef *ref) { - if (ref->gid != nullptr) + if (ref->gid.size > 0) { - gid = pbArrayToVector(ref->gid); + gid = std::vector(ref->gid.bytes, ref->gid.bytes + ref->gid.size); } - else if (ref->uri != nullptr) + else if (strlen(ref->uri) > 0) { auto uri = std::string(ref->uri); auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size()); diff --git a/components/spotify/cspot_sink.c b/components/spotify/cspot_sink.c index 0df72605..bf6343dc 100644 --- a/components/spotify/cspot_sink.c +++ b/components/spotify/cspot_sink.c @@ -106,7 +106,7 @@ static bool cmd_handler(cspot_event_t event, ...) { switch(event) { case CSPOT_SETUP: actrls_set(controls, false, NULL, actrls_ir_action); - displayer_control(DISPLAYER_ACTIVATE, "SPOTIFY"); + displayer_control(DISPLAYER_ACTIVATE, "SPOTIFY", false); break; case CSPOT_PLAY: displayer_control(DISPLAYER_TIMER_RUN); From f09a95cc8bf0fb64bbbfb144a7bb377963a505cc Mon Sep 17 00:00:00 2001 From: Philippe G Date: Mon, 10 Jan 2022 00:46:56 -0800 Subject: [PATCH 03/16] artwork for Spotify --- components/display/display.c | 14 +++-- components/spotify/cspot_sink.c | 21 ++++++- components/tools/CMakeLists.txt | 1 + components/tools/tools.c | 105 ++++++++++++++++++++++++++++++++ components/tools/tools.h | 3 + 5 files changed, 137 insertions(+), 7 deletions(-) diff --git a/components/display/display.c b/components/display/display.c index 68d6b86a..4af7eec1 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -52,7 +52,8 @@ static EXT_RAM_ATTR struct { bool visible; } duration; struct { - bool enable, fit; + bool enable, active; + bool fit; bool updated; int tick; int offset; @@ -245,7 +246,7 @@ static void displayer_task(void *args) { GDS_TextLine(display, 1, GDS_TEXT_RIGHT, GDS_TEXT_UPDATE, _line); // if we have not received artwork after 5s, display a default icon - if (displayer.artwork.enable && !displayer.artwork.updated && tick - displayer.artwork.tick > pdMS_TO_TICKS(5000)) { + if (displayer.artwork.active && !displayer.artwork.updated && tick - displayer.artwork.tick > pdMS_TO_TICKS(5000)) { ESP_LOGI(TAG, "no artwork received, setting default"); displayer_artwork((uint8_t*) default_artwork); } @@ -265,7 +266,7 @@ static void displayer_task(void *args) { * */ void displayer_artwork(uint8_t *data) { - if (!displayer.artwork.enable) return; + if (!displayer.artwork.active) return; int x = displayer.artwork.offset ? displayer.artwork.offset + ARTWORK_BORDER : 0; int y = x ? 0 : 32; @@ -420,7 +421,7 @@ void displayer_control(enum displayer_cmd_e cmd, ...) { switch(cmd) { case DISPLAYER_ACTIVATE: { char *header = va_arg(args, char*); - bool artwork = va_arg(args, int); + displayer.artwork.active = displayer.artwork.enable && va_arg(args, int); strncpy(displayer.header, header, HEADER_SIZE); displayer.header[HEADER_SIZE] = '\0'; displayer.state = DISPLAYER_ACTIVE; @@ -431,19 +432,20 @@ void displayer_control(enum displayer_cmd_e cmd, ...) { displayer.duration.visible = false; displayer.offset = displayer.boundary = 0; display_bus(&displayer, DISPLAY_BUS_TAKE); - if (artwork) GDS_SetTextWidth(display, displayer.artwork.offset); + if (displayer.artwork.active) GDS_SetTextWidth(display, displayer.artwork.offset); vTaskResume(displayer.task); break; } case DISPLAYER_SUSPEND: // task will display the line 2 from beginning and suspend displayer.state = DISPLAYER_IDLE; + displayer_artwork(NULL); display_bus(&displayer, DISPLAY_BUS_GIVE); break; case DISPLAYER_SHUTDOWN: // let the task self-suspend (we might be doing i2c_write) GDS_SetTextWidth(display, 0); - GDS_Clear(display, GDS_COLOR_BLACK); + displayer_artwork(NULL); displayer.state = DISPLAYER_DOWN; display_bus(&displayer, DISPLAY_BUS_GIVE); break; diff --git a/components/spotify/cspot_sink.c b/components/spotify/cspot_sink.c index bf6343dc..67677e88 100644 --- a/components/spotify/cspot_sink.c +++ b/components/spotify/cspot_sink.c @@ -13,6 +13,7 @@ #include "display.h" #include "accessors.h" #include "network_services.h" +#include "tools.h" #include "cspot_private.h" #include "cspot_sink.h" @@ -87,6 +88,19 @@ const static actrls_t controls = { cspot_volume_down, cspot_volume_up, cspot_toggle// knob left, knob_right, knob push }; +/**************************************************************************************** + * Download callback + */ +void got_artwork(uint8_t* data, size_t len, void *context) { + if (data) { + ESP_LOGI(TAG, "got artwork of %zu bytes", len); + displayer_artwork(data); + free(data); + } else { + ESP_LOGW(TAG, "artwork error or too large %zu", len); + } +} + /**************************************************************************************** * Command handler */ @@ -106,7 +120,7 @@ static bool cmd_handler(cspot_event_t event, ...) { switch(event) { case CSPOT_SETUP: actrls_set(controls, false, NULL, actrls_ir_action); - displayer_control(DISPLAYER_ACTIVATE, "SPOTIFY", false); + displayer_control(DISPLAYER_ACTIVATE, "SPOTIFY", true); break; case CSPOT_PLAY: displayer_control(DISPLAYER_TIMER_RUN); @@ -129,6 +143,11 @@ static bool cmd_handler(cspot_event_t event, ...) { uint32_t sample_rate = va_arg(args, uint32_t); int duration = va_arg(args, int); char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*); + char *artwork = va_arg(args, char*); + if (artwork) { + ESP_LOGI(TAG, "requesting artwork %s", artwork); + http_download(artwork, 128*1024, got_artwork, NULL); + } displayer_metadata(artist, album, title); displayer_timer(DISPLAYER_ELAPSED, loaded ? -1 : 0, duration); loaded = false; diff --git a/components/tools/CMakeLists.txt b/components/tools/CMakeLists.txt index 6a36b20f..c9644f5e 100644 --- a/components/tools/CMakeLists.txt +++ b/components/tools/CMakeLists.txt @@ -1,5 +1,6 @@ idf_component_register( SRCS operator.cpp tools.c trace.c REQUIRES _override esp_common pthread + PRIV_REQUIRES esp_http_client esp-tls INCLUDE_DIRS . ) diff --git a/components/tools/tools.c b/components/tools/tools.c index 4f582b81..1c877ff2 100644 --- a/components/tools/tools.c +++ b/components/tools/tools.c @@ -11,7 +11,11 @@ #include #include #include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "tools.h" +#include "esp_tls.h" +#include "esp_http_client.h" #include "esp_heap_caps.h" #include "esp_log.h" @@ -171,3 +175,104 @@ char * strdup_psram(const char * source){ } return ptr; } + +/**************************************************************************************** + * URL download + */ + +typedef struct { + void *user_context; + http_download_cb_t callback; + size_t max, bytes; + bool abort; + uint8_t *data; + char *url; +} http_context_t; + +static void http_downloader(void *arg); +static esp_err_t http_event_handler(esp_http_client_event_t *evt); + +void http_download(char *url, size_t max, http_download_cb_t callback, void *context) { + http_context_t *http_context = (http_context_t*) heap_caps_calloc(sizeof(http_context_t), 1, MALLOC_CAP_SPIRAM); + + http_context->callback = callback; + http_context->user_context = context; + http_context->max = max; + http_context->url = strdup(url); + + xTaskCreate(http_downloader, "downloader", 4*1024, http_context, ESP_TASK_PRIO_MIN + 1, NULL); +} + +static void http_downloader(void *arg) { + http_context_t *http_context = (http_context_t*) arg; + esp_http_client_config_t config = { + .url = http_context->url, + .event_handler = http_event_handler, + .user_data = http_context, + //.cert_pem = howsmyssl_com_root_cert_pem_start, + //.skip_cert_common_name_check = true, + }; + + esp_http_client_handle_t client = esp_http_client_init(&config); + esp_http_client_perform(client); +// esp_http_client_cleanup(client); + + free(http_context->url); + free(http_context); + + vTaskDelete(NULL); +} + +static esp_err_t http_event_handler(esp_http_client_event_t *evt) { + http_context_t *http_context = (http_context_t*) evt->user_data; + + if (http_context->abort) return ESP_FAIL; + + switch(evt->event_id) { + case HTTP_EVENT_ERROR: + http_context->callback(NULL, 0, http_context->user_context); + http_context->abort = true; + break; + case HTTP_EVENT_ON_HEADER: + if (!strcasecmp(evt->header_key, "Content-Length")) { + size_t len = atoi(evt->header_value); + if (!len || len > http_context->max) { + ESP_LOGI(TAG, "content-length null or too large %zu / %zu", len, http_context->max); + http_context->abort = true; + } + } + break; + case HTTP_EVENT_ON_DATA: { + size_t len = esp_http_client_get_content_length(evt->client); + if (!http_context->data) { + if ((http_context->data = (uint8_t*) malloc(len)) == NULL) { + http_context->abort = true; + ESP_LOGE(TAG, "gailed to allocate memory for output buffer %zu", len); + return ESP_FAIL; + } + } + memcpy(http_context->data + http_context->bytes, evt->data, evt->data_len); + http_context->bytes += evt->data_len; + break; + } + case HTTP_EVENT_ON_FINISH: + http_context->callback(http_context->data, http_context->bytes, http_context->user_context); + break; + case HTTP_EVENT_DISCONNECTED: { + int mbedtls_err = 0; + esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL); + if (err != ESP_OK) { + ESP_LOGE(TAG, "HTTP download disconnect %d", err); + if (http_context->data) free(http_context->data); + http_context->callback(NULL, 0, http_context->user_context); + return ESP_FAIL; + } + break; + default: + break; + } + } + + return ESP_OK; +} + diff --git a/components/tools/tools.h b/components/tools/tools.h index 785d22e0..3b29a512 100644 --- a/components/tools/tools.h +++ b/components/tools/tools.h @@ -53,6 +53,9 @@ char* strdup_psram(const char * source); const char* str_or_unknown(const char * str); const char* str_or_null(const char * str); +typedef void (*http_download_cb_t)(uint8_t* data, size_t len, void *context); +void http_download(char *url, size_t max, http_download_cb_t callback, void *context); + extern const char unknown_string_placeholder[]; #ifdef __cplusplus From 72657d69515bf6d1d4da9e5ff814a7016e9b994e Mon Sep 17 00:00:00 2001 From: Philippe G Date: Mon, 10 Jan 2022 11:24:19 -0800 Subject: [PATCH 04/16] simplify artwork and bypass server certificate verification --- build-scripts/I2S-4MFlash-sdkconfig.defaults | 5 +-- build-scripts/SqueezeAmp-sdkconfig.defaults | 5 +-- components/tools/tools.c | 32 +++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index aaa52f80..11d9651a 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -533,7 +533,8 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set # CONFIG_ESP_TLS_SERVER is not set # CONFIG_ESP_TLS_PSK_VERIFICATION is not set -# CONFIG_ESP_TLS_INSECURE is not set +CONFIG_ESP_TLS_INSECURE=y +CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y # end of ESP-TLS # @@ -727,7 +728,7 @@ CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y # # ESP HTTP client # -# CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS is not set +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set # end of ESP HTTP client diff --git a/build-scripts/SqueezeAmp-sdkconfig.defaults b/build-scripts/SqueezeAmp-sdkconfig.defaults index 57abadb8..3c3f7ecc 100644 --- a/build-scripts/SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp-sdkconfig.defaults @@ -505,7 +505,8 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y # CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set # CONFIG_ESP_TLS_SERVER is not set # CONFIG_ESP_TLS_PSK_VERIFICATION is not set -# CONFIG_ESP_TLS_INSECURE is not set +CONFIG_ESP_TLS_INSECURE=y +CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y # end of ESP-TLS # @@ -699,7 +700,7 @@ CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y # # ESP HTTP client # -# CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS is not set +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set # end of ESP HTTP client diff --git a/components/tools/tools.c b/components/tools/tools.c index 1c877ff2..1ee41680 100644 --- a/components/tools/tools.c +++ b/components/tools/tools.c @@ -186,7 +186,7 @@ typedef struct { size_t max, bytes; bool abort; uint8_t *data; - char *url; + esp_http_client_handle_t client; } http_context_t; static void http_downloader(void *arg); @@ -194,32 +194,30 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt); void http_download(char *url, size_t max, http_download_cb_t callback, void *context) { http_context_t *http_context = (http_context_t*) heap_caps_calloc(sizeof(http_context_t), 1, MALLOC_CAP_SPIRAM); - - http_context->callback = callback; - http_context->user_context = context; - http_context->max = max; - http_context->url = strdup(url); - xTaskCreate(http_downloader, "downloader", 4*1024, http_context, ESP_TASK_PRIO_MIN + 1, NULL); -} - -static void http_downloader(void *arg) { - http_context_t *http_context = (http_context_t*) arg; esp_http_client_config_t config = { - .url = http_context->url, + .url = url, .event_handler = http_event_handler, .user_data = http_context, //.cert_pem = howsmyssl_com_root_cert_pem_start, //.skip_cert_common_name_check = true, }; - esp_http_client_handle_t client = esp_http_client_init(&config); - esp_http_client_perform(client); -// esp_http_client_cleanup(client); + http_context->callback = callback; + http_context->user_context = context; + http_context->max = max; + http_context->client = esp_http_client_init(&config); + + xTaskCreate(http_downloader, "downloader", 4*1024, http_context, ESP_TASK_PRIO_MIN + 1, NULL); +} + +static void http_downloader(void *arg) { + http_context_t *http_context = (http_context_t*) arg; + + esp_http_client_perform(http_context->client); + esp_http_client_cleanup(http_context->client); - free(http_context->url); free(http_context); - vTaskDelete(NULL); } From 8fa3906b52d2b39038afb9e9f9894fd61b9f137d Mon Sep 17 00:00:00 2001 From: Philippe G Date: Mon, 10 Jan 2022 12:11:21 -0800 Subject: [PATCH 05/16] updated CSpot --- .../spotify/cspot/protobuf/metadata.options | 34 ++-- .../spotify/cspot/protobuf/metadata.pb.c | 8 +- .../spotify/cspot/protobuf/metadata.pb.h | 159 ++++++++---------- .../spotify/cspot/protobuf/spirc.options | 19 ++- components/spotify/cspot/protobuf/spirc.pb.c | 4 +- components/spotify/cspot/protobuf/spirc.pb.h | 130 +++++++------- components/spotify/cspot/src/PlayerState.cpp | 77 ++++----- .../spotify/cspot/src/SpircController.cpp | 3 +- components/spotify/cspot/src/SpotifyTrack.cpp | 69 ++++---- .../spotify/cspot/src/TrackReference.cpp | 6 +- 10 files changed, 238 insertions(+), 271 deletions(-) diff --git a/components/spotify/cspot/protobuf/metadata.options b/components/spotify/cspot/protobuf/metadata.options index 3a6341c8..3758c5f6 100644 --- a/components/spotify/cspot/protobuf/metadata.options +++ b/components/spotify/cspot/protobuf/metadata.options @@ -1,16 +1,18 @@ -Track.name max_size: 512 -Track.gid max_size: 64 -Track.file max_count: 16 -Track.artist max_count: 8 -AudioFile.file_id max_size: 128 -Image.file_id max_size: 128 -Artist.gid max_size: 128 -Artist.name max_size: 512 -Album.name max_size: 512 -Episode.gid max_size: 64 -Episode.name max_size: 512 -ImageGroup.image max_count: 10 -Episode.audio max_count: 10 -Episode.covers max_count: 10 -Restriction.countries_allowed max_size: 32 -Restriction.countries_forbidden max_size: 32 \ No newline at end of file +Track.name type: FT_POINTER +Track.gid type: FT_POINTER +Track.file type: FT_POINTER +Track.restriction type: FT_POINTER +Track.alternative type: FT_POINTER +Track.artist type: FT_POINTER +AudioFile.file_id type: FT_POINTER +Image.file_id type: FT_POINTER +Artist.gid type: FT_POINTER +Artist.name type: FT_POINTER +Album.name type: FT_POINTER +Episode.gid type: FT_POINTER +Episode.name type: FT_POINTER +ImageGroup.image type: FT_POINTER +Episode.audio type: FT_POINTER +Episode.covers type: FT_POINTER +Restriction.countries_allowed type: FT_POINTER +Restriction.countries_forbidden type: FT_POINTER \ No newline at end of file diff --git a/components/spotify/cspot/protobuf/metadata.pb.c b/components/spotify/cspot/protobuf/metadata.pb.c index 78014778..7196e0cf 100644 --- a/components/spotify/cspot/protobuf/metadata.pb.c +++ b/components/spotify/cspot/protobuf/metadata.pb.c @@ -15,16 +15,16 @@ PB_BIND(Restriction, Restriction, AUTO) PB_BIND(Image, Image, AUTO) -PB_BIND(ImageGroup, ImageGroup, 2) +PB_BIND(ImageGroup, ImageGroup, AUTO) -PB_BIND(Album, Album, 2) +PB_BIND(Album, Album, AUTO) -PB_BIND(Artist, Artist, 2) +PB_BIND(Artist, Artist, AUTO) -PB_BIND(Track, Track, 4) +PB_BIND(Track, Track, AUTO) PB_BIND(Episode, Episode, 2) diff --git a/components/spotify/cspot/protobuf/metadata.pb.h b/components/spotify/cspot/protobuf/metadata.pb.h index 7def594b..fa196fa8 100644 --- a/components/spotify/cspot/protobuf/metadata.pb.h +++ b/components/spotify/cspot/protobuf/metadata.pb.h @@ -24,78 +24,63 @@ typedef enum _AudioFormat { } AudioFormat; /* Struct definitions */ -typedef PB_BYTES_ARRAY_T(128) Artist_gid_t; typedef struct _Artist { - bool has_gid; - Artist_gid_t gid; - bool has_name; - char name[512]; + pb_bytes_array_t *gid; + char *name; } Artist; -typedef PB_BYTES_ARRAY_T(128) AudioFile_file_id_t; -typedef struct _AudioFile { - bool has_file_id; - AudioFile_file_id_t file_id; - bool has_format; - AudioFormat format; -} AudioFile; - -typedef PB_BYTES_ARRAY_T(128) Image_file_id_t; typedef struct _Image { - bool has_file_id; - Image_file_id_t file_id; + pb_bytes_array_t *file_id; } Image; -typedef struct _Restriction { - bool has_countries_allowed; - char countries_allowed[32]; - bool has_countries_forbidden; - char countries_forbidden[32]; -} Restriction; - typedef struct _ImageGroup { pb_size_t image_count; - Image image[10]; + struct _Image *image; } ImageGroup; +typedef struct _Restriction { + char *countries_allowed; + char *countries_forbidden; +} Restriction; + typedef struct _Album { pb_callback_t gid; - bool has_name; - char name[512]; + char *name; bool has_cover_group; ImageGroup cover_group; } Album; -typedef PB_BYTES_ARRAY_T(64) Episode_gid_t; +typedef struct _AudioFile { + pb_bytes_array_t *file_id; + bool has_format; + AudioFormat format; +} AudioFile; + typedef struct _Episode { - bool has_gid; - Episode_gid_t gid; - bool has_name; - char name[512]; + pb_bytes_array_t *gid; + char *name; bool has_duration; int32_t duration; pb_size_t audio_count; - AudioFile audio[10]; - bool has_covers; - ImageGroup covers; + struct _AudioFile *audio; + struct _ImageGroup *covers; } Episode; -typedef PB_BYTES_ARRAY_T(64) Track_gid_t; typedef struct _Track { - bool has_gid; - Track_gid_t gid; - bool has_name; - char name[512]; + pb_bytes_array_t *gid; + char *name; bool has_album; Album album; pb_size_t artist_count; - Artist artist[8]; + struct _Artist *artist; bool has_duration; int32_t duration; - pb_callback_t restriction; + pb_size_t restriction_count; + struct _Restriction *restriction; pb_size_t file_count; - AudioFile file[16]; - pb_callback_t alternative; + struct _AudioFile *file; + pb_size_t alternative_count; + struct _Track *alternative; } Track; @@ -110,35 +95,35 @@ extern "C" { #endif /* Initializer values for message structs */ -#define AudioFile_init_default {false, {0, {0}}, false, _AudioFormat_MIN} -#define Restriction_init_default {false, "", false, ""} -#define Image_init_default {false, {0, {0}}} -#define ImageGroup_init_default {0, {Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default, Image_init_default}} -#define Album_init_default {{{NULL}, NULL}, false, "", false, ImageGroup_init_default} -#define Artist_init_default {false, {0, {0}}, false, ""} -#define Track_init_default {false, {0, {0}}, false, "", false, Album_init_default, 0, {Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default, Artist_init_default}, false, 0, {{NULL}, NULL}, 0, {AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default}, {{NULL}, NULL}} -#define Episode_init_default {false, {0, {0}}, false, "", false, 0, 0, {AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default, AudioFile_init_default}, false, ImageGroup_init_default} -#define AudioFile_init_zero {false, {0, {0}}, false, _AudioFormat_MIN} -#define Restriction_init_zero {false, "", false, ""} -#define Image_init_zero {false, {0, {0}}} -#define ImageGroup_init_zero {0, {Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero, Image_init_zero}} -#define Album_init_zero {{{NULL}, NULL}, false, "", false, ImageGroup_init_zero} -#define Artist_init_zero {false, {0, {0}}, false, ""} -#define Track_init_zero {false, {0, {0}}, false, "", false, Album_init_zero, 0, {Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero, Artist_init_zero}, false, 0, {{NULL}, NULL}, 0, {AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero}, {{NULL}, NULL}} -#define Episode_init_zero {false, {0, {0}}, false, "", false, 0, 0, {AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero, AudioFile_init_zero}, false, ImageGroup_init_zero} +#define AudioFile_init_default {NULL, false, _AudioFormat_MIN} +#define Restriction_init_default {NULL, NULL} +#define Image_init_default {NULL} +#define ImageGroup_init_default {0, NULL} +#define Album_init_default {{{NULL}, NULL}, NULL, false, ImageGroup_init_default} +#define Artist_init_default {NULL, NULL} +#define Track_init_default {NULL, NULL, false, Album_init_default, 0, NULL, false, 0, 0, NULL, 0, NULL, 0, NULL} +#define Episode_init_default {NULL, NULL, false, 0, 0, NULL, NULL} +#define AudioFile_init_zero {NULL, false, _AudioFormat_MIN} +#define Restriction_init_zero {NULL, NULL} +#define Image_init_zero {NULL} +#define ImageGroup_init_zero {0, NULL} +#define Album_init_zero {{{NULL}, NULL}, NULL, false, ImageGroup_init_zero} +#define Artist_init_zero {NULL, NULL} +#define Track_init_zero {NULL, NULL, false, Album_init_zero, 0, NULL, false, 0, 0, NULL, 0, NULL, 0, NULL} +#define Episode_init_zero {NULL, NULL, false, 0, 0, NULL, NULL} /* Field tags (for use in manual encoding/decoding) */ #define Artist_gid_tag 1 #define Artist_name_tag 2 -#define AudioFile_file_id_tag 1 -#define AudioFile_format_tag 2 #define Image_file_id_tag 1 +#define ImageGroup_image_tag 1 #define Restriction_countries_allowed_tag 2 #define Restriction_countries_forbidden_tag 3 -#define ImageGroup_image_tag 1 #define Album_gid_tag 1 #define Album_name_tag 2 #define Album_cover_group_tag 17 +#define AudioFile_file_id_tag 1 +#define AudioFile_format_tag 2 #define Episode_gid_tag 1 #define Episode_name_tag 2 #define Episode_duration_tag 7 @@ -155,52 +140,52 @@ extern "C" { /* Struct field encoding specification for nanopb */ #define AudioFile_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, BYTES, file_id, 1) \ +X(a, POINTER, OPTIONAL, BYTES, file_id, 1) \ X(a, STATIC, OPTIONAL, UENUM, format, 2) #define AudioFile_CALLBACK NULL #define AudioFile_DEFAULT NULL #define Restriction_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, STRING, countries_allowed, 2) \ -X(a, STATIC, OPTIONAL, STRING, countries_forbidden, 3) +X(a, POINTER, OPTIONAL, STRING, countries_allowed, 2) \ +X(a, POINTER, OPTIONAL, STRING, countries_forbidden, 3) #define Restriction_CALLBACK NULL #define Restriction_DEFAULT NULL #define Image_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, BYTES, file_id, 1) +X(a, POINTER, OPTIONAL, BYTES, file_id, 1) #define Image_CALLBACK NULL #define Image_DEFAULT NULL #define ImageGroup_FIELDLIST(X, a) \ -X(a, STATIC, REPEATED, MESSAGE, image, 1) +X(a, POINTER, REPEATED, MESSAGE, image, 1) #define ImageGroup_CALLBACK NULL #define ImageGroup_DEFAULT NULL #define ImageGroup_image_MSGTYPE Image #define Album_FIELDLIST(X, a) \ X(a, CALLBACK, OPTIONAL, BYTES, gid, 1) \ -X(a, STATIC, OPTIONAL, STRING, name, 2) \ +X(a, POINTER, OPTIONAL, STRING, name, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, cover_group, 17) #define Album_CALLBACK pb_default_field_callback #define Album_DEFAULT NULL #define Album_cover_group_MSGTYPE ImageGroup #define Artist_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ -X(a, STATIC, OPTIONAL, STRING, name, 2) +X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ +X(a, POINTER, OPTIONAL, STRING, name, 2) #define Artist_CALLBACK NULL #define Artist_DEFAULT NULL #define Track_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ -X(a, STATIC, OPTIONAL, STRING, name, 2) \ +X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ +X(a, POINTER, OPTIONAL, STRING, name, 2) \ X(a, STATIC, OPTIONAL, MESSAGE, album, 3) \ -X(a, STATIC, REPEATED, MESSAGE, artist, 4) \ +X(a, POINTER, REPEATED, MESSAGE, artist, 4) \ X(a, STATIC, OPTIONAL, SINT32, duration, 7) \ -X(a, CALLBACK, REPEATED, MESSAGE, restriction, 11) \ -X(a, STATIC, REPEATED, MESSAGE, file, 12) \ -X(a, CALLBACK, REPEATED, MESSAGE, alternative, 13) -#define Track_CALLBACK pb_default_field_callback +X(a, POINTER, REPEATED, MESSAGE, restriction, 11) \ +X(a, POINTER, REPEATED, MESSAGE, file, 12) \ +X(a, POINTER, REPEATED, MESSAGE, alternative, 13) +#define Track_CALLBACK NULL #define Track_DEFAULT NULL #define Track_album_MSGTYPE Album #define Track_artist_MSGTYPE Artist @@ -209,11 +194,11 @@ X(a, CALLBACK, REPEATED, MESSAGE, alternative, 13) #define Track_alternative_MSGTYPE Track #define Episode_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ -X(a, STATIC, OPTIONAL, STRING, name, 2) \ +X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ +X(a, POINTER, OPTIONAL, STRING, name, 2) \ X(a, STATIC, OPTIONAL, SINT32, duration, 7) \ -X(a, STATIC, REPEATED, MESSAGE, audio, 12) \ -X(a, STATIC, OPTIONAL, MESSAGE, covers, 68) +X(a, POINTER, REPEATED, MESSAGE, audio, 12) \ +X(a, POINTER, OPTIONAL, MESSAGE, covers, 68) #define Episode_CALLBACK NULL #define Episode_DEFAULT NULL #define Episode_audio_MSGTYPE AudioFile @@ -239,14 +224,14 @@ extern const pb_msgdesc_t Episode_msg; #define Episode_fields &Episode_msg /* Maximum encoded size of messages (where known) */ +/* AudioFile_size depends on runtime parameters */ +/* Restriction_size depends on runtime parameters */ +/* Image_size depends on runtime parameters */ +/* ImageGroup_size depends on runtime parameters */ /* Album_size depends on runtime parameters */ +/* Artist_size depends on runtime parameters */ /* Track_size depends on runtime parameters */ -#define Artist_size 645 -#define AudioFile_size 133 -#define Episode_size 3290 -#define ImageGroup_size 1340 -#define Image_size 131 -#define Restriction_size 66 +/* Episode_size depends on runtime parameters */ #ifdef __cplusplus } /* extern "C" */ diff --git a/components/spotify/cspot/protobuf/spirc.options b/components/spotify/cspot/protobuf/spirc.options index 8684cadf..3ed13c47 100644 --- a/components/spotify/cspot/protobuf/spirc.options +++ b/components/spotify/cspot/protobuf/spirc.options @@ -1,12 +1,13 @@ -Frame.ident max_size: 64, fixed_length:false -Frame.protocol_version max_size: 64, fixed_length:false -Frame.recipient max_count: 64, max_size: 64 +Frame.ident type:FT_POINTER +Frame.protocol_version type:FT_POINTER +Frame.recipient type:FT_POINTER Capability.stringValue max_count:50, max_size: 50 Capability.intValue max_count:50 -DeviceState.sw_version max_size: 64, fixed_length:false -DeviceState.name max_size: 64, fixed_length:false +DeviceState.sw_version type:FT_POINTER +DeviceState.name type:FT_POINTER DeviceState.capabilities max_count:17, fixed_count:false -State.context_uri max_size: 256, fixed_length:false -State.track max_count:100, fixed_count:false -TrackRef.gid max_size: 128, fixed_length:false -TrackRef.uri max_size: 256 fixed_length:false +State.context_uri type:FT_POINTER +State.track type:FT_POINTER +TrackRef.gid type:FT_POINTER +TrackRef.uri type:FT_POINTER +TrackRef.context type:FT_POINTER \ No newline at end of file diff --git a/components/spotify/cspot/protobuf/spirc.pb.c b/components/spotify/cspot/protobuf/spirc.pb.c index 99304244..fd9bffb5 100644 --- a/components/spotify/cspot/protobuf/spirc.pb.c +++ b/components/spotify/cspot/protobuf/spirc.pb.c @@ -6,10 +6,10 @@ #error Regenerate this file with the current version of nanopb generator. #endif -PB_BIND(TrackRef, TrackRef, 2) +PB_BIND(TrackRef, TrackRef, AUTO) -PB_BIND(State, State, 4) +PB_BIND(State, State, AUTO) PB_BIND(Capability, Capability, 2) diff --git a/components/spotify/cspot/protobuf/spirc.pb.h b/components/spotify/cspot/protobuf/spirc.pb.h index 810fc6d3..9b79fb63 100644 --- a/components/spotify/cspot/protobuf/spirc.pb.h +++ b/components/spotify/cspot/protobuf/spirc.pb.h @@ -62,41 +62,8 @@ typedef struct _Capability { char stringValue[50][50]; } Capability; -typedef PB_BYTES_ARRAY_T(128) TrackRef_gid_t; -typedef struct _TrackRef { - bool has_gid; - TrackRef_gid_t gid; - bool has_uri; - char uri[256]; - bool has_queued; - bool queued; - pb_callback_t context; -} TrackRef; - -typedef struct _DeviceState { - bool has_sw_version; - char sw_version[64]; - bool has_is_active; - bool is_active; - bool has_can_play; - bool can_play; - bool has_volume; - uint32_t volume; - bool has_name; - char name[64]; - bool has_error_code; - uint32_t error_code; - bool has_became_active_at; - int64_t became_active_at; - pb_callback_t error_message; - pb_size_t capabilities_count; - Capability capabilities[17]; - pb_callback_t local_uris; -} DeviceState; - typedef struct _State { - bool has_context_uri; - char context_uri[256]; + char *context_uri; bool has_index; uint32_t index; bool has_position_ms; @@ -113,16 +80,41 @@ typedef struct _State { bool has_playing_track_index; uint32_t playing_track_index; pb_size_t track_count; - TrackRef track[100]; + struct _TrackRef *track; } State; +typedef struct _TrackRef { + pb_bytes_array_t *gid; + char *uri; + bool has_queued; + bool queued; + char *context; +} TrackRef; + +typedef struct _DeviceState { + char *sw_version; + bool has_is_active; + bool is_active; + bool has_can_play; + bool can_play; + bool has_volume; + uint32_t volume; + char *name; + bool has_error_code; + uint32_t error_code; + bool has_became_active_at; + int64_t became_active_at; + pb_callback_t error_message; + pb_size_t capabilities_count; + Capability capabilities[17]; + pb_callback_t local_uris; +} DeviceState; + typedef struct _Frame { bool has_version; uint32_t version; - bool has_ident; - char ident[64]; - bool has_protocol_version; - char protocol_version[64]; + char *ident; + char *protocol_version; bool has_seq_nr; uint32_t seq_nr; bool has_typ; @@ -138,7 +130,7 @@ typedef struct _Frame { bool has_state_update_id; int64_t state_update_id; pb_size_t recipient_count; - char recipient[64][64]; + char **recipient; } Frame; @@ -161,21 +153,31 @@ extern "C" { #endif /* Initializer values for message structs */ -#define TrackRef_init_default {false, {0, {0}}, false, "", false, 0, {{NULL}, NULL}} -#define State_init_default {false, "", false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default, TrackRef_init_default}} +#define TrackRef_init_default {NULL, NULL, false, 0, NULL} +#define State_init_default {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, NULL} #define Capability_init_default {false, _CapabilityType_MIN, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} -#define DeviceState_init_default {false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default}, {{NULL}, NULL}} -#define Frame_init_default {false, 0, false, "", false, "", false, 0, false, _MessageType_MIN, false, DeviceState_init_default, false, State_init_default, false, 0, false, 0, false, 0, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} -#define TrackRef_init_zero {false, {0, {0}}, false, "", false, 0, {{NULL}, NULL}} -#define State_init_zero {false, "", false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, {TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero, TrackRef_init_zero}} +#define DeviceState_init_default {NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default, Capability_init_default}, {{NULL}, NULL}} +#define Frame_init_default {false, 0, NULL, NULL, false, 0, false, _MessageType_MIN, false, DeviceState_init_default, false, State_init_default, false, 0, false, 0, false, 0, 0, NULL} +#define TrackRef_init_zero {NULL, NULL, false, 0, NULL} +#define State_init_zero {NULL, false, 0, false, 0, false, _PlayStatus_MIN, false, 0, {{NULL}, NULL}, false, 0, false, 0, false, 0, 0, NULL} #define Capability_init_zero {false, _CapabilityType_MIN, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} -#define DeviceState_init_zero {false, "", false, 0, false, 0, false, 0, false, "", false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero}, {{NULL}, NULL}} -#define Frame_init_zero {false, 0, false, "", false, "", false, 0, false, _MessageType_MIN, false, DeviceState_init_zero, false, State_init_zero, false, 0, false, 0, false, 0, 0, {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}} +#define DeviceState_init_zero {NULL, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, {{NULL}, NULL}, 0, {Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero, Capability_init_zero}, {{NULL}, NULL}} +#define Frame_init_zero {false, 0, NULL, NULL, false, 0, false, _MessageType_MIN, false, DeviceState_init_zero, false, State_init_zero, false, 0, false, 0, false, 0, 0, NULL} /* Field tags (for use in manual encoding/decoding) */ #define Capability_typ_tag 1 #define Capability_intValue_tag 2 #define Capability_stringValue_tag 3 +#define State_context_uri_tag 2 +#define State_index_tag 3 +#define State_position_ms_tag 4 +#define State_status_tag 5 +#define State_position_measured_at_tag 7 +#define State_context_description_tag 8 +#define State_shuffle_tag 13 +#define State_repeat_tag 14 +#define State_playing_track_index_tag 26 +#define State_track_tag 27 #define TrackRef_gid_tag 1 #define TrackRef_uri_tag 2 #define TrackRef_queued_tag 3 @@ -190,16 +192,6 @@ extern "C" { #define DeviceState_error_message_tag 16 #define DeviceState_capabilities_tag 17 #define DeviceState_local_uris_tag 18 -#define State_context_uri_tag 2 -#define State_index_tag 3 -#define State_position_ms_tag 4 -#define State_status_tag 5 -#define State_position_measured_at_tag 7 -#define State_context_description_tag 8 -#define State_shuffle_tag 13 -#define State_repeat_tag 14 -#define State_playing_track_index_tag 26 -#define State_track_tag 27 #define Frame_version_tag 1 #define Frame_ident_tag 2 #define Frame_protocol_version_tag 3 @@ -214,15 +206,15 @@ extern "C" { /* Struct field encoding specification for nanopb */ #define TrackRef_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, BYTES, gid, 1) \ -X(a, STATIC, OPTIONAL, STRING, uri, 2) \ +X(a, POINTER, OPTIONAL, BYTES, gid, 1) \ +X(a, POINTER, OPTIONAL, STRING, uri, 2) \ X(a, STATIC, OPTIONAL, BOOL, queued, 3) \ -X(a, CALLBACK, OPTIONAL, STRING, context, 4) -#define TrackRef_CALLBACK pb_default_field_callback +X(a, POINTER, OPTIONAL, STRING, context, 4) +#define TrackRef_CALLBACK NULL #define TrackRef_DEFAULT NULL #define State_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, STRING, context_uri, 2) \ +X(a, POINTER, OPTIONAL, STRING, context_uri, 2) \ X(a, STATIC, OPTIONAL, UINT32, index, 3) \ X(a, STATIC, OPTIONAL, UINT32, position_ms, 4) \ X(a, STATIC, OPTIONAL, UENUM, status, 5) \ @@ -231,7 +223,7 @@ X(a, CALLBACK, OPTIONAL, STRING, context_description, 8) \ X(a, STATIC, OPTIONAL, BOOL, shuffle, 13) \ X(a, STATIC, OPTIONAL, BOOL, repeat, 14) \ X(a, STATIC, OPTIONAL, UINT32, playing_track_index, 26) \ -X(a, STATIC, REPEATED, MESSAGE, track, 27) +X(a, POINTER, REPEATED, MESSAGE, track, 27) #define State_CALLBACK pb_default_field_callback #define State_DEFAULT NULL #define State_track_MSGTYPE TrackRef @@ -244,11 +236,11 @@ X(a, STATIC, REPEATED, STRING, stringValue, 3) #define Capability_DEFAULT (const pb_byte_t*)"\x08\x01\x00" #define DeviceState_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, STRING, sw_version, 1) \ +X(a, POINTER, OPTIONAL, STRING, sw_version, 1) \ X(a, STATIC, OPTIONAL, BOOL, is_active, 10) \ X(a, STATIC, OPTIONAL, BOOL, can_play, 11) \ X(a, STATIC, OPTIONAL, UINT32, volume, 12) \ -X(a, STATIC, OPTIONAL, STRING, name, 13) \ +X(a, POINTER, OPTIONAL, STRING, name, 13) \ X(a, STATIC, OPTIONAL, UINT32, error_code, 14) \ X(a, STATIC, OPTIONAL, INT64, became_active_at, 15) \ X(a, CALLBACK, OPTIONAL, STRING, error_message, 16) \ @@ -260,8 +252,8 @@ X(a, CALLBACK, REPEATED, STRING, local_uris, 18) #define Frame_FIELDLIST(X, a) \ X(a, STATIC, OPTIONAL, UINT32, version, 1) \ -X(a, STATIC, OPTIONAL, STRING, ident, 2) \ -X(a, STATIC, OPTIONAL, STRING, protocol_version, 3) \ +X(a, POINTER, OPTIONAL, STRING, ident, 2) \ +X(a, POINTER, OPTIONAL, STRING, protocol_version, 3) \ X(a, STATIC, OPTIONAL, UINT32, seq_nr, 4) \ X(a, STATIC, OPTIONAL, UENUM, typ, 5) \ X(a, STATIC, OPTIONAL, MESSAGE, device_state, 7) \ @@ -269,7 +261,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, state, 12) \ X(a, STATIC, OPTIONAL, UINT32, position, 13) \ X(a, STATIC, OPTIONAL, UINT32, volume, 14) \ X(a, STATIC, OPTIONAL, INT64, state_update_id, 17) \ -X(a, STATIC, REPEATED, STRING, recipient, 18) +X(a, POINTER, REPEATED, STRING, recipient, 18) #define Frame_CALLBACK NULL #define Frame_DEFAULT (const pb_byte_t*)"\x28\x01\x00" #define Frame_device_state_MSGTYPE DeviceState diff --git a/components/spotify/cspot/src/PlayerState.cpp b/components/spotify/cspot/src/PlayerState.cpp index 8e5066d9..8c3ef7b4 100644 --- a/components/spotify/cspot/src/PlayerState.cpp +++ b/components/spotify/cspot/src/PlayerState.cpp @@ -24,20 +24,18 @@ PlayerState::PlayerState(std::shared_ptr timeProvider) innerFrame.state.repeat = false; innerFrame.state.has_repeat = true; - innerFrame.device_state.has_sw_version = true; - pbPutCharArray(swVersion, innerFrame.device_state.sw_version); + innerFrame.device_state.sw_version = strdup(swVersion); innerFrame.device_state.is_active = false; innerFrame.device_state.has_is_active = true; - + innerFrame.device_state.can_play = true; innerFrame.device_state.has_can_play = true; innerFrame.device_state.volume = configMan->volume; innerFrame.device_state.has_volume = true; - innerFrame.device_state.has_name = true; - pbPutString(configMan->deviceName, innerFrame.device_state.name); + innerFrame.device_state.name = strdup(configMan->deviceName.c_str()); // Prepare player's capabilities addCapability(CapabilityType_kCanBePlayer, 1); @@ -55,33 +53,32 @@ PlayerState::PlayerState(std::shared_ptr timeProvider) } PlayerState::~PlayerState() { + pb_release(Frame_fields, &innerFrame); pb_release(Frame_fields, &remoteFrame); - // do not destruct inner frame as it is never allocated -// pb_release(Frame_fields, &innerFrame); } void PlayerState::setPlaybackState(const PlaybackState state) { switch (state) { - case PlaybackState::Loading: - // Prepare the playback at position 0 - innerFrame.state.status = PlayStatus_kPlayStatusPause; - innerFrame.state.position_ms = 0; - innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp(); - break; - case PlaybackState::Playing: - innerFrame.state.status = PlayStatus_kPlayStatusPlay; - innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp(); - break; - case PlaybackState::Stopped: - break; - case PlaybackState::Paused: - // Update state and recalculate current song position - innerFrame.state.status = PlayStatus_kPlayStatusPause; - uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state.position_measured_at; - this->updatePositionMs(innerFrame.state.position_ms + diff); - break; + case PlaybackState::Loading: + // Prepare the playback at position 0 + innerFrame.state.status = PlayStatus_kPlayStatusPause; + innerFrame.state.position_ms = 0; + innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp(); + break; + case PlaybackState::Playing: + innerFrame.state.status = PlayStatus_kPlayStatusPlay; + innerFrame.state.position_measured_at = timeProvider->getSyncedTimestamp(); + break; + case PlaybackState::Stopped: + break; + case PlaybackState::Paused: + // Update state and recalculate current song position + innerFrame.state.status = PlayStatus_kPlayStatusPause; + uint32_t diff = timeProvider->getSyncedTimestamp() - innerFrame.state.position_measured_at; + this->updatePositionMs(innerFrame.state.position_ms + diff); + break; } } @@ -139,9 +136,8 @@ void PlayerState::updatePositionMs(uint32_t position) void PlayerState::updateTracks() { CSPOT_LOG(info, "---- Track count %d", remoteFrame.state.track_count); - strcpy(innerFrame.state.context_uri, remoteFrame.state.context_uri); - - std::copy(std::begin(remoteFrame.state.track), std::end(remoteFrame.state.track), std::begin(innerFrame.state.track)); + std::swap(innerFrame.state.context_uri, remoteFrame.state.context_uri); + std::swap(innerFrame.state.track, remoteFrame.state.track); innerFrame.state.track_count = remoteFrame.state.track_count; innerFrame.state.has_playing_track_index = true; innerFrame.state.playing_track_index = remoteFrame.state.playing_track_index; @@ -170,17 +166,13 @@ void PlayerState::setShuffle(bool shuffle) if (shuffle) { // Put current song at the begining - auto tmp = innerFrame.state.track[0]; - innerFrame.state.track[0] = innerFrame.state.track[innerFrame.state.playing_track_index]; - innerFrame.state.track[innerFrame.state.playing_track_index] = tmp; + std::swap(innerFrame.state.track[0], innerFrame.state.track[innerFrame.state.playing_track_index]); // Shuffle current tracks for (int x = 1; x < innerFrame.state.track_count - 1; x++) { auto j = x + (std::rand() % (innerFrame.state.track_count - x)); - tmp = innerFrame.state.track[j]; - innerFrame.state.track[j] = innerFrame.state.track[x]; - innerFrame.state.track[x] = tmp; + std::swap(innerFrame.state.track[j], innerFrame.state.track[x]); } innerFrame.state.playing_track_index = 0; } @@ -199,16 +191,14 @@ std::shared_ptr PlayerState::getCurrentTrack() std::vector PlayerState::encodeCurrentFrame(MessageType typ) { + free(innerFrame.ident); + free(innerFrame.protocol_version); + // Prepare current frame info innerFrame.version = 1; - - pbPutCharArray(deviceId, innerFrame.ident); - innerFrame.has_ident = true; - + innerFrame.ident = strdup(deviceId); innerFrame.seq_nr = this->seqNum; - pbPutCharArray(protocolVersion, innerFrame.protocol_version); - innerFrame.has_protocol_version = true; - + innerFrame.protocol_version = strdup(protocolVersion); innerFrame.typ = typ; innerFrame.state_update_id = timeProvider->getSyncedTimestamp(); innerFrame.has_version = true; @@ -241,10 +231,9 @@ void PlayerState::addCapability(CapabilityType typ, int intValue, std::vectorinnerFrame.device_state.capabilities[capabilityIndex].stringValue[x], stringValue[x].size()); - this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x][stringValue[x].size()] = '\0'; + pbPutString(stringValue[x], this->innerFrame.device_state.capabilities[capabilityIndex].stringValue[x]); } this->innerFrame.device_state.capabilities[capabilityIndex].stringValue_count = stringValue.size(); this->capabilityIndex += 1; -} +} \ No newline at end of file diff --git a/components/spotify/cspot/src/SpircController.cpp b/components/spotify/cspot/src/SpircController.cpp index 4f7e0264..7de1e737 100644 --- a/components/spotify/cspot/src/SpircController.cpp +++ b/components/spotify/cspot/src/SpircController.cpp @@ -56,7 +56,7 @@ void SpircController::disconnect(void) { state->setActive(false); notify(); // Send the event at the end at it might be a last gasp - sendEvent(CSpotEventType::DISC); + sendEvent(CSpotEventType::DISC); } void SpircController::playToggle() { @@ -103,6 +103,7 @@ void SpircController::prevSong() { } void SpircController::handleFrame(std::vector &data) { + pb_release(Frame_fields, &state->remoteFrame); pbDecode(state->remoteFrame, Frame_fields, data); switch (state->remoteFrame.typ) { diff --git a/components/spotify/cspot/src/SpotifyTrack.cpp b/components/spotify/cspot/src/SpotifyTrack.cpp index e172bbd1..ad39f122 100644 --- a/components/spotify/cspot/src/SpotifyTrack.cpp +++ b/components/spotify/cspot/src/SpotifyTrack.cpp @@ -53,18 +53,18 @@ bool SpotifyTrack::countryListContains(std::string countryList, std::string coun bool SpotifyTrack::canPlayTrack() { -// for (int x = 0; x < trackInfo.restriction_count; x++) -// { -// if (strlen(trackInfo.restriction[x].countries_allowed) > 0) -// { -// return countryListContains(std::string(trackInfo.restriction[x].countries_allowed), manager->countryCode); -// } -// -// if (strlen(trackInfo.restriction[x].countries_forbidden) > 0) -// { -// return !countryListContains(std::string(trackInfo.restriction[x].countries_forbidden), manager->countryCode); -// } -// } + for (int x = 0; x < trackInfo.restriction_count; x++) + { + if (trackInfo.restriction[x].countries_allowed != nullptr) + { + return countryListContains(std::string(trackInfo.restriction[x].countries_allowed), manager->countryCode); + } + + if (trackInfo.restriction[x].countries_forbidden != nullptr) + { + return !countryListContains(std::string(trackInfo.restriction[x].countries_forbidden), manager->countryCode); + } + } return true; } @@ -77,39 +77,37 @@ void SpotifyTrack::trackInformationCallback(std::unique_ptr res pb_release(Track_fields, &trackInfo); pbDecode(trackInfo, Track_fields, response->parts[0]); -// -// CSPOT_LOG(info, "Track name: %s", trackInfo.name); -// CSPOT_LOG(info, "Track duration: %d", trackInfo.duration); -// CSPOT_LOG(debug, "trackInfo.restriction.size() = %d", trackInfo.restriction_count); -// int altIndex = 0; -// while (!canPlayTrack()) -// { -// auto src = trackInfo.alternative[altIndex].restriction; -//// std::copy(std::begin(src), std::end(src), std::begin(trackInfo.restriction)); -//// trackInfo.restriction_count = trackInfo.alternative[altIndex].restriction_count; -//// -//// free(trackInfo.gid); -// trackInfo.gid = trackInfo.alternative[altIndex].gid; -// altIndex++; -// CSPOT_LOG(info, "Trying alternative %d", altIndex); -// } - auto trackId = std::vector(trackInfo.gid.bytes, trackInfo.gid.bytes + trackInfo.gid.size); + CSPOT_LOG(info, "Track name: %s", trackInfo.name); + CSPOT_LOG(info, "Track duration: %d", trackInfo.duration); + CSPOT_LOG(debug, "trackInfo.restriction.size() = %d", trackInfo.restriction_count); + int altIndex = 0; + while (!canPlayTrack()) + { + std::swap(trackInfo.restriction, trackInfo.alternative[altIndex].restriction); + std::swap(trackInfo.restriction_count, trackInfo.alternative[altIndex].restriction_count); + std::swap(trackInfo.file, trackInfo.alternative[altIndex].file); + std::swap(trackInfo.file_count, trackInfo.alternative[altIndex].file_count); + std::swap(trackInfo.gid, trackInfo.alternative[altIndex].gid); + + CSPOT_LOG(info, "Trying alternative %d", altIndex); + } + + auto trackId = pbArrayToVector(trackInfo.gid); this->fileId = std::vector(); for (int x = 0; x < trackInfo.file_count; x++) { if (trackInfo.file[x].format == configMan->format) { - this->fileId = std::vector(trackInfo.file[x].file_id.bytes, trackInfo.file[x].file_id.bytes + trackInfo.file[x].file_id.size); + this->fileId = pbArrayToVector(trackInfo.file[x].file_id); break; // If file found stop searching } } if (trackInfoReceived != nullptr) { - auto imageIdBytes = trackInfo.album.cover_group.image[0].file_id; - auto imageId = std::vector(imageIdBytes.bytes, imageIdBytes.bytes + imageIdBytes.size); + auto imageId = pbArrayToVector(trackInfo.album.cover_group.image[0].file_id); TrackInfo simpleTrackInfo = { .name = std::string(trackInfo.name), .album = std::string(trackInfo.album.name), @@ -143,15 +141,14 @@ void SpotifyTrack::episodeInformationCallback(std::unique_ptr r { if (episodeInfo.audio[x].format == AudioFormat_OGG_VORBIS_96) { - this->fileId = std::vector(episodeInfo.audio[x].file_id.bytes, episodeInfo.audio[x].file_id.bytes + episodeInfo.audio[x].file_id.size); + this->fileId = pbArrayToVector(episodeInfo.audio[x].file_id); break; // If file found stop searching } } if (trackInfoReceived != nullptr) { - auto imageFileId = episodeInfo.covers.image[0].file_id; - auto imageId = std::vector(imageFileId.bytes, imageFileId.bytes + imageFileId.size); + auto imageId = pbArrayToVector(episodeInfo.covers->image[0].file_id); TrackInfo simpleTrackInfo = { .name = std::string(episodeInfo.name), .album = "", @@ -164,7 +161,7 @@ void SpotifyTrack::episodeInformationCallback(std::unique_ptr r trackInfoReceived(simpleTrackInfo); } - this->requestAudioKey(std::vector(episodeInfo.gid.bytes, episodeInfo.gid.bytes + episodeInfo.gid.size), this->fileId, episodeInfo.duration, position_ms, isPaused); + this->requestAudioKey(pbArrayToVector(episodeInfo.gid), this->fileId, episodeInfo.duration, position_ms, isPaused); } void SpotifyTrack::requestAudioKey(std::vector fileId, std::vector trackId, int32_t trackDuration, uint32_t position_ms, bool isPaused) diff --git a/components/spotify/cspot/src/TrackReference.cpp b/components/spotify/cspot/src/TrackReference.cpp index a165c39a..e51afb35 100644 --- a/components/spotify/cspot/src/TrackReference.cpp +++ b/components/spotify/cspot/src/TrackReference.cpp @@ -3,11 +3,11 @@ TrackReference::TrackReference(TrackRef *ref) { - if (ref->gid.size > 0) + if (ref->gid != nullptr) { - gid = std::vector(ref->gid.bytes, ref->gid.bytes + ref->gid.size); + gid = pbArrayToVector(ref->gid); } - else if (strlen(ref->uri) > 0) + else if (ref->uri != nullptr) { auto uri = std::string(ref->uri); auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size()); From 04919f7b6edd18a3ceceea0ec22513de4fa4af71 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Tue, 11 Jan 2022 14:44:06 -0800 Subject: [PATCH 06/16] change priorities and force spdif_convert in IRAM --- components/spotify/Shim.cpp | 2 +- components/spotify/cspot/bell/include/Task.h | 2 +- components/spotify/cspot/src/AudioChunkManager.cpp | 2 +- components/spotify/cspot/src/MercuryManager.cpp | 2 +- components/spotify/cspot/src/Player.cpp | 2 +- components/squeezelite/output_i2s.c | 2 +- components/tools/tools.c | 5 ++--- 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/components/spotify/Shim.cpp b/components/spotify/Shim.cpp index fa212257..54560b9a 100644 --- a/components/spotify/Shim.cpp +++ b/components/spotify/Shim.cpp @@ -193,7 +193,7 @@ struct cspot_s* cspot_create(const char *name, cspot_cmd_cb_t cmd_cb, cspot_data cspot.cHandler = cmd_cb; cspot.dHandler = data_cb; strncpy(cspot.name, name, sizeof(cspot.name) - 1); - cspot.TaskHandle = xTaskCreateStatic(&cspotTask, "cspot", CSPOT_STACK_SIZE, NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT, xStack, &xTaskBuffer); + cspot.TaskHandle = xTaskCreateStatic(&cspotTask, "cspot", CSPOT_STACK_SIZE, NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT - 2, xStack, &xTaskBuffer); return &cspot; } diff --git a/components/spotify/cspot/bell/include/Task.h b/components/spotify/cspot/bell/include/Task.h index 72f9412b..425b2072 100644 --- a/components/spotify/cspot/bell/include/Task.h +++ b/components/spotify/cspot/bell/include/Task.h @@ -29,7 +29,7 @@ namespace bell #ifdef ESP_PLATFORM this->xStack = NULL; this->priority = CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT + priority; - if (this->priority < 0) this->priority = ESP_TASK_PRIO_MIN; + if (this->priority <= ESP_TASK_PRIO_MIN) this->priority = ESP_TASK_PRIO_MIN + 1; if (runOnPSRAM) { this->xStack = (StackType_t*) heap_caps_malloc(this->stackSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); } diff --git a/components/spotify/cspot/src/AudioChunkManager.cpp b/components/spotify/cspot/src/AudioChunkManager.cpp index 98426814..256ee13a 100644 --- a/components/spotify/cspot/src/AudioChunkManager.cpp +++ b/components/spotify/cspot/src/AudioChunkManager.cpp @@ -3,7 +3,7 @@ #include "Logger.h" AudioChunkManager::AudioChunkManager() - : bell::Task("AudioChunkManager", 4 * 1024, 2, 0) { + : bell::Task("AudioChunkManager", 4 * 1024, -1, 0) { this->chunks = std::vector>(); startTask(); } diff --git a/components/spotify/cspot/src/MercuryManager.cpp b/components/spotify/cspot/src/MercuryManager.cpp index 36a3d9d3..a02b4c15 100644 --- a/components/spotify/cspot/src/MercuryManager.cpp +++ b/components/spotify/cspot/src/MercuryManager.cpp @@ -9,7 +9,7 @@ std::map MercuryTypeMap({ {MercuryType::UNSUB, "UNSUB"}, }); -MercuryManager::MercuryManager(std::unique_ptr session): bell::Task("mercuryManager", 6 * 1024, 2, 1) +MercuryManager::MercuryManager(std::unique_ptr session): bell::Task("mercuryManager", 6 * 1024, -2, 1) { tempMercuryHeader = {}; this->timeProvider = std::make_shared(); diff --git a/components/spotify/cspot/src/Player.cpp b/components/spotify/cspot/src/Player.cpp index 0fb32b6d..3bccc0b0 100644 --- a/components/spotify/cspot/src/Player.cpp +++ b/components/spotify/cspot/src/Player.cpp @@ -3,7 +3,7 @@ // #include -Player::Player(std::shared_ptr manager, std::shared_ptr audioSink): bell::Task("player", 10 * 1024, +0, 1) +Player::Player(std::shared_ptr manager, std::shared_ptr audioSink): bell::Task("player", 10 * 1024, -2, 1) { this->audioSink = audioSink; this->manager = manager; diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index 2da4d583..af77cd4a 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -672,7 +672,7 @@ static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least audio is transmitted first (not the MSB) and that ESP32 libray sends R then L, contrary to what seems to be usually done, so (dst) order had to be changed */ -void spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) { +static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) { register u16_t hi, lo, aux; size_t cnt = *count; diff --git a/components/tools/tools.c b/components/tools/tools.c index 1ee41680..9a6af79a 100644 --- a/components/tools/tools.c +++ b/components/tools/tools.c @@ -13,11 +13,12 @@ #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "tools.h" +#include "esp_task.h" #include "esp_tls.h" #include "esp_http_client.h" #include "esp_heap_caps.h" #include "esp_log.h" +#include "tools.h" const static char TAG[] = "tools"; @@ -199,8 +200,6 @@ void http_download(char *url, size_t max, http_download_cb_t callback, void *con .url = url, .event_handler = http_event_handler, .user_data = http_context, - //.cert_pem = howsmyssl_com_root_cert_pem_start, - //.skip_cert_common_name_check = true, }; http_context->callback = callback; From b2741b5bef7c7676df2f4ce68704e61c87dbf3f1 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Tue, 11 Jan 2022 20:15:16 -0800 Subject: [PATCH 07/16] duration is now 1ms units & don't get cspot artwork when display disabled --- build-scripts/I2S-4MFlash-sdkconfig.defaults | 2 +- build-scripts/SqueezeAmp-sdkconfig.defaults | 2 +- components/display/display.c | 7 +++++++ components/display/display.h | 1 + components/spotify/Shim.cpp | 3 +-- components/spotify/cspot_sink.c | 2 +- 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 11d9651a..40110fd2 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -728,7 +728,7 @@ CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y # # ESP HTTP client # -CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set # end of ESP HTTP client diff --git a/build-scripts/SqueezeAmp-sdkconfig.defaults b/build-scripts/SqueezeAmp-sdkconfig.defaults index 3c3f7ecc..fb63230a 100644 --- a/build-scripts/SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp-sdkconfig.defaults @@ -700,7 +700,7 @@ CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y # # ESP HTTP client # -CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS +CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set # end of ESP HTTP client diff --git a/components/display/display.c b/components/display/display.c index 4af7eec1..94414dac 100644 --- a/components/display/display.c +++ b/components/display/display.c @@ -281,6 +281,13 @@ void displayer_artwork(uint8_t *data) { } +/**************************************************************************************** + * + */ +bool displayer_can_artwork(void) { + return displayer.artwork.active; +} + /**************************************************************************************** * */ diff --git a/components/display/display.h b/components/display/display.h index ebb857e7..278bc077 100644 --- a/components/display/display.h +++ b/components/display/display.h @@ -40,4 +40,5 @@ void displayer_control(enum displayer_cmd_e cmd, ...); void displayer_metadata(char *artist, char *album, char *title); void displayer_artwork(uint8_t *data); void displayer_timer(enum displayer_time_e mode, int elapsed, int duration); +bool displayer_can_artwork(void); char * display_get_supported_drivers(void); diff --git a/components/spotify/Shim.cpp b/components/spotify/Shim.cpp index 54560b9a..577143e3 100644 --- a/components/spotify/Shim.cpp +++ b/components/spotify/Shim.cpp @@ -119,8 +119,7 @@ static void cspotTask(void *pvParameters) { switch (event.eventType) { case CSpotEventType::TRACK_INFO: { TrackInfo track = std::get(event.data); - // duration is in chunks of 0.5 ms - cspot.cHandler(CSPOT_TRACK, 44100, track.duration / 2, track.artist.c_str(), + cspot.cHandler(CSPOT_TRACK, 44100, track.duration, track.artist.c_str(), track.album.c_str(), track.name.c_str(), track.imageUrl.c_str()); break; } diff --git a/components/spotify/cspot_sink.c b/components/spotify/cspot_sink.c index 67677e88..c98634cd 100644 --- a/components/spotify/cspot_sink.c +++ b/components/spotify/cspot_sink.c @@ -144,7 +144,7 @@ static bool cmd_handler(cspot_event_t event, ...) { int duration = va_arg(args, int); char *artist = va_arg(args, char*), *album = va_arg(args, char*), *title = va_arg(args, char*); char *artwork = va_arg(args, char*); - if (artwork) { + if (artwork && displayer_can_artwork()) { ESP_LOGI(TAG, "requesting artwork %s", artwork); http_download(artwork, 128*1024, got_artwork, NULL); } From 1b83d0eb5f14583a9d03bc62879ec8b08ad16278 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Wed, 12 Jan 2022 18:10:46 -0800 Subject: [PATCH 08/16] fix prio --- components/spotify/cspot/src/MercuryManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/spotify/cspot/src/MercuryManager.cpp b/components/spotify/cspot/src/MercuryManager.cpp index a02b4c15..87fd2ff9 100644 --- a/components/spotify/cspot/src/MercuryManager.cpp +++ b/components/spotify/cspot/src/MercuryManager.cpp @@ -9,7 +9,7 @@ std::map MercuryTypeMap({ {MercuryType::UNSUB, "UNSUB"}, }); -MercuryManager::MercuryManager(std::unique_ptr session): bell::Task("mercuryManager", 6 * 1024, -2, 1) +MercuryManager::MercuryManager(std::unique_ptr session): bell::Task("mercuryManager", 6 * 1024, 0, 1) { tempMercuryHeader = {}; this->timeProvider = std::make_shared(); From 4420f7da4d8d691c3c0905ae5c7836b581399747 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Wed, 12 Jan 2022 18:29:03 -0800 Subject: [PATCH 09/16] remove warnings (except CSpot ones) --- components/platform_console/CMakeLists.txt | 6 ++++++ components/platform_console/platform_console.c | 4 ++-- components/squeezelite/CMakeLists.txt | 5 +++++ components/squeezelite/output_i2s.c | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/components/platform_console/CMakeLists.txt b/components/platform_console/CMakeLists.txt index 2c41c179..9c99d841 100644 --- a/components/platform_console/CMakeLists.txt +++ b/components/platform_console/CMakeLists.txt @@ -12,3 +12,9 @@ idf_component_register( SRCS target_link_libraries(${COMPONENT_LIB} "-Wl,--undefined=GDS_DrawPixelFast") target_link_libraries(${COMPONENT_LIB} ${build_dir}/esp-idf/$/lib$.a ) target_add_binary_data( __idf_platform_console presets.json BINARY) + +set_source_files_properties(cmd_config.c + PROPERTIES COMPILE_FLAGS + -Wno-unused-function +) + diff --git a/components/platform_console/platform_console.c b/components/platform_console/platform_console.c index a0d1f506..11104a0a 100644 --- a/components/platform_console/platform_console.c +++ b/components/platform_console/platform_console.c @@ -283,9 +283,9 @@ static int stdin_dummy(const char * path, int flags, int mode) { return 0; } void initialize_console() { /* Minicom, screen, idf_monitor send CR when ENTER key is pressed (unused if we redirect stdin) */ - esp_vfs_dev_uart_set_rx_line_endings(ESP_LINE_ENDINGS_CR); + esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); /* Move the caret to the beginning of the next line on '\n' */ - esp_vfs_dev_uart_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF); + esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); /* Configure UART. Note that REF_TICK is used so that the baud rate remains * correct while APB frequency is changing in light sleep mode. diff --git a/components/squeezelite/CMakeLists.txt b/components/squeezelite/CMakeLists.txt index d7422b48..5c1f0375 100644 --- a/components/squeezelite/CMakeLists.txt +++ b/components/squeezelite/CMakeLists.txt @@ -21,6 +21,11 @@ set_source_files_properties(mad.c pcm.c flac.c alac.c helix-aac.c vorbis.c opus. -Wno-maybe-uninitialized ) +set_source_files_properties(wm8978/wm8978.c + PROPERTIES COMPILE_FLAGS + -Wno-unused-function +) + add_definitions(-DLINKALL -DLOOPBACK -DNO_FAAD -DEMBEDDED -DTREMOR_ONLY -DCUSTOM_VERSION=${BUILD_NUMBER}) if (${DEPTH} EQUAL "32") diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index af77cd4a..76ce69cb 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -247,7 +247,7 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch // common I2S initialization i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX; i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; - i2s_config.communication_format = I2S_COMM_FORMAT_I2S| I2S_COMM_FORMAT_I2S_MSB; + i2s_config.communication_format = I2S_COMM_FORMAT_STAND_I2S; // in case of overflow, do not replay old buffer i2s_config.tx_desc_auto_clear = true; i2s_config.use_apll = true; From 3fb1c16f56d683028b553b064ce0e5f206d53be3 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Thu, 13 Jan 2022 13:08:45 -0800 Subject: [PATCH 10/16] get ready for 4.4 --- components/platform_console/platform_console.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/platform_console/platform_console.c b/components/platform_console/platform_console.c index 11104a0a..999d63b7 100644 --- a/components/platform_console/platform_console.c +++ b/components/platform_console/platform_console.c @@ -290,10 +290,10 @@ void initialize_console() { /* Configure UART. Note that REF_TICK is used so that the baud rate remains * correct while APB frequency is changing in light sleep mode. */ - const uart_config_t uart_config = { .baud_rate = - CONFIG_ESP_CONSOLE_UART_BAUDRATE, .data_bits = UART_DATA_8_BITS, + const uart_config_t uart_config = { .baud_rate = CONFIG_ESP_CONSOLE_UART_BAUDRATE, + .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .use_ref_tick = true }; + }; ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); /* Install UART driver for interrupt-driven reads and writes */ From 60584ae2073dfeb93e10201fa9e504a7eaef500f Mon Sep 17 00:00:00 2001 From: Philippe G Date: Thu, 13 Jan 2022 18:21:36 -0800 Subject: [PATCH 11/16] no more clicks on SPDIF & CSpot --- .../cspot/bell/include/CryptoMbedTLS.h | 2 +- .../cspot/bell/include/CryptoOpenSSL.h | 2 +- .../spotify/cspot/bell/src/CryptoMBedTLS.cpp | 10 +++---- .../spotify/cspot/bell/src/CryptoOpenSSL.cpp | 8 +++--- .../spotify/cspot/bell/src/HTTPClient.cpp | 2 +- components/spotify/cspot/include/AudioChunk.h | 26 ++++++++++++------ components/spotify/cspot/include/Shannon.h | 2 +- components/spotify/cspot/src/AudioChunk.cpp | 27 ++++++++++++++----- .../spotify/cspot/src/AudioChunkManager.cpp | 6 ++--- .../spotify/cspot/src/ChunkedByteStream.cpp | 4 +-- components/spotify/cspot/src/LoginBlob.cpp | 2 +- 11 files changed, 57 insertions(+), 34 deletions(-) diff --git a/components/spotify/cspot/bell/include/CryptoMbedTLS.h b/components/spotify/cspot/bell/include/CryptoMbedTLS.h index 089a3bad..27a4ff42 100644 --- a/components/spotify/cspot/bell/include/CryptoMbedTLS.h +++ b/components/spotify/cspot/bell/include/CryptoMbedTLS.h @@ -56,7 +56,7 @@ public: std::vector sha1HMAC(const std::vector& inputKey, const std::vector& message); // AES CTR - void aesCTRXcrypt(const std::vector& key, std::vector& iv, std::vector& data); + void aesCTRXcrypt(const std::vector& key, std::vector& iv, uint8_t* data, size_t nbytes); // AES ECB void aesECBdecrypt(const std::vector& key, std::vector& data); diff --git a/components/spotify/cspot/bell/include/CryptoOpenSSL.h b/components/spotify/cspot/bell/include/CryptoOpenSSL.h index abc8d01c..56310fd3 100644 --- a/components/spotify/cspot/bell/include/CryptoOpenSSL.h +++ b/components/spotify/cspot/bell/include/CryptoOpenSSL.h @@ -63,7 +63,7 @@ public: std::vector sha1HMAC(const std::vector& inputKey, const std::vector& message); // AES CTR - void aesCTRXcrypt(const std::vector& key, std::vector& iv, std::vector& data); + void aesCTRXcrypt(const std::vector& key, std::vector& iv, uint8_t* buffer, size_t nbytes); // AES ECB void aesECBdecrypt(const std::vector& key, std::vector& data); diff --git a/components/spotify/cspot/bell/src/CryptoMBedTLS.cpp b/components/spotify/cspot/bell/src/CryptoMBedTLS.cpp index 7fbe5c72..fc596762 100644 --- a/components/spotify/cspot/bell/src/CryptoMBedTLS.cpp +++ b/components/spotify/cspot/bell/src/CryptoMBedTLS.cpp @@ -88,7 +88,7 @@ std::vector CryptoMbedTLS::sha1HMAC(const std::vector &inputKe } // AES CTR -void CryptoMbedTLS::aesCTRXcrypt(const std::vector &key, std::vector &iv, std::vector &data) +void CryptoMbedTLS::aesCTRXcrypt(const std::vector &key, std::vector &iv, uint8_t* buffer, size_t nbytes) { // needed for internal cache size_t off = 0; @@ -99,12 +99,12 @@ void CryptoMbedTLS::aesCTRXcrypt(const std::vector &key, std::vector &key, std::vector &data) @@ -115,7 +115,7 @@ void CryptoMbedTLS::aesECBdecrypt(const std::vector &key, std::vector CryptoOpenSSL::sha1HMAC(const std::vector& inputKe } // AES CTR -void CryptoOpenSSL::aesCTRXcrypt(const std::vector& key, std::vector& iv, std::vector &data) +void CryptoOpenSSL::aesCTRXcrypt(const std::vector& key, std::vector& iv, uint8_t* buffer, size_t nbytes) { // Prepare AES_KEY auto cryptoKey = AES_KEY(); @@ -110,9 +110,9 @@ void CryptoOpenSSL::aesCTRXcrypt(const std::vector& key, std::vectorread(buffer, BUF_SIZE); diff --git a/components/spotify/cspot/include/AudioChunk.h b/components/spotify/cspot/include/AudioChunk.h index 3aa46878..3b75e789 100644 --- a/components/spotify/cspot/include/AudioChunk.h +++ b/components/spotify/cspot/include/AudioChunk.h @@ -14,12 +14,15 @@ class AudioChunk { private: /** * @brief Calculates a correct IV by performing bignum addition. - * + * * @param num Number to add to IV. - * @return std::vector + * @return std::vector */ std::vector getIVSum(uint32_t num); + size_t decryptedCount = 0; + size_t oldStartPos; + public: std::unique_ptr crypto; std::vector decryptedData; @@ -41,14 +44,21 @@ public: std::unique_ptr isLoadedSemaphore; /** - * @brief + * @brief */ std::unique_ptr isHeaderFileSizeLoadedSemaphore; + /** + * Decrypts data and writes it to the target buffer + * @param target data buffer to write to + * @param offset data offset + * @param nbytes number of bytes to read + */ + void readData(uint8_t *target, size_t offset, size_t nbytes); /** * @brief AudioChunk handles all audiochunk related operations. - * + * * @param seqId Sequence id of requested chunk * @param audioKey Audio key used for decryption of audio data * @param startPosition Start position of current chunk in audio file @@ -59,16 +69,16 @@ public: /** * @brief Appends incoming chunked data to local cache. - * + * * @param data encrypted binary audio data. */ void appendData(const std::vector &data); /** - * @brief Performs AES CTR decryption of received data. - * + * @brief Sets loaded status on the chunk + * */ - void decrypt(); + void finalize(); }; #endif diff --git a/components/spotify/cspot/include/Shannon.h b/components/spotify/cspot/include/Shannon.h index df9a5eb2..34107bf2 100644 --- a/components/spotify/cspot/include/Shannon.h +++ b/components/spotify/cspot/include/Shannon.h @@ -13,7 +13,7 @@ public: void stream(std::vector &buf); /* stream cipher */ void maconly(std::vector &buf); /* accumulate MAC */ void encrypt(std::vector &buf); /* encrypt + MAC */ - void decrypt(std::vector &buf); /* decrypt + MAC */ + void decrypt(std::vector &buf); /* finalize + MAC */ void finish(std::vector &buf); /* finalise MAC */ private: diff --git a/components/spotify/cspot/src/AudioChunk.cpp b/components/spotify/cspot/src/AudioChunk.cpp index 17ff25b7..407fc425 100644 --- a/components/spotify/cspot/src/AudioChunk.cpp +++ b/components/spotify/cspot/src/AudioChunk.cpp @@ -24,13 +24,28 @@ void AudioChunk::appendData(const std::vector &data) this->decryptedData.insert(this->decryptedData.end(), data.begin(), data.end()); } -void AudioChunk::decrypt() +void AudioChunk::readData(uint8_t *target, size_t offset, size_t nbytes) { + auto readPos = offset + nbytes; + auto modulo = (readPos % 16); + auto ivReadPos = readPos; + if (modulo != 0) { + ivReadPos += (16 - modulo); + } + if (ivReadPos > decryptedCount) { + // calculate the IV for right position + auto calculatedIV = this->getIVSum((oldStartPos + decryptedCount) / 16); + + crypto->aesCTRXcrypt(this->audioKey, calculatedIV, decryptedData.data() + decryptedCount, ivReadPos - decryptedCount); + + decryptedCount = ivReadPos; + } + memcpy(target, this->decryptedData.data() + offset, nbytes); + +} + +void AudioChunk::finalize() { - // calculate the IV for right position - auto calculatedIV = this->getIVSum(startPosition / 16); - - crypto->aesCTRXcrypt(this->audioKey, calculatedIV, decryptedData); - + this->oldStartPos = this->startPosition; this->startPosition = this->endPosition - this->decryptedData.size(); this->isLoaded = true; } diff --git a/components/spotify/cspot/src/AudioChunkManager.cpp b/components/spotify/cspot/src/AudioChunkManager.cpp index 256ee13a..827d2a32 100644 --- a/components/spotify/cspot/src/AudioChunkManager.cpp +++ b/components/spotify/cspot/src/AudioChunkManager.cpp @@ -80,7 +80,7 @@ void AudioChunkManager::runTask() { switch (data.size()) { case DATA_SIZE_HEADER: { - CSPOT_LOG(debug, "ID: %d: header decrypt!", seqId); + CSPOT_LOG(debug, "ID: %d: header finalize!", seqId); auto headerSize = ntohs(extract(data, 2)); // Got file size! chunk->headerFileSize = @@ -92,9 +92,9 @@ void AudioChunkManager::runTask() { if (chunk->endPosition > chunk->headerFileSize) { chunk->endPosition = chunk->headerFileSize; } - CSPOT_LOG(debug, "ID: %d: Starting decrypt!", + CSPOT_LOG(debug, "ID: %d: finalize chunk!", seqId); - chunk->decrypt(); + chunk->finalize(); chunk->isLoadedSemaphore->give(); break; diff --git a/components/spotify/cspot/src/ChunkedByteStream.cpp b/components/spotify/cspot/src/ChunkedByteStream.cpp index 00140ee6..0c92aa84 100644 --- a/components/spotify/cspot/src/ChunkedByteStream.cpp +++ b/components/spotify/cspot/src/ChunkedByteStream.cpp @@ -113,9 +113,7 @@ size_t ChunkedByteStream::attemptRead(uint8_t *buffer, size_t bytes, std::shared toRead = chunk->decryptedData.size() - offset; } - // Copy data - memcpy(buffer, chunk->decryptedData.data() + offset, toRead); - + chunk->readData(buffer, offset, toRead); return toRead; } diff --git a/components/spotify/cspot/src/LoginBlob.cpp b/components/spotify/cspot/src/LoginBlob.cpp index 36143e9f..477b9b94 100644 --- a/components/spotify/cspot/src/LoginBlob.cpp +++ b/components/spotify/cspot/src/LoginBlob.cpp @@ -35,7 +35,7 @@ std::vector LoginBlob::decodeBlob(const std::vector &blob, con } encryptionKey = std::vector(encryptionKey.begin(), encryptionKey.begin() + 16); - crypto->aesCTRXcrypt(encryptionKey, iv, encrypted); + crypto->aesCTRXcrypt(encryptionKey, iv, encrypted.data(), encrypted.size()); return encrypted; } From 396366b50997ff9245d5db9b59e3527cb910cd55 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Thu, 13 Jan 2022 18:48:29 -0800 Subject: [PATCH 12/16] CSpot copyright --- components/wifi-manager/webapp/src/index.ejs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/wifi-manager/webapp/src/index.ejs b/components/wifi-manager/webapp/src/index.ejs index f6f244d0..86c35911 100644 --- a/components/wifi-manager/webapp/src/index.ejs +++ b/components/wifi-manager/webapp/src/index.ejs @@ -470,6 +470,7 @@ GPL License.
  • tarablessd1306, © 2017-2018, Tara Keeling. Licensed under the MIT license.
  • +
  • CSpot, © 2020 feelfreelinux & alufers. Licensed under the GPL License
  • From de025602ace2dacea6396a9d69647f244a0e3747 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Sat, 15 Jan 2022 00:54:11 -0800 Subject: [PATCH 13/16] fix equalizer in NVS --- components/squeezelite/equalizer.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/components/squeezelite/equalizer.c b/components/squeezelite/equalizer.c index ca74b92e..9b083560 100644 --- a/components/squeezelite/equalizer.c +++ b/components/squeezelite/equalizer.c @@ -89,16 +89,14 @@ void equalizer_close(void) { */ void equalizer_update(s8_t *gain) { char config[EQ_BANDS * 4 + 1] = { }; - char *p = config; + int n = 0; for (int i = 0; i < EQ_BANDS; i++) { equalizer.gain[i] = gain[i]; - if (gain[i] < 0) *p++ = '-'; - *p++ = (gain[i] / 10) + 0x30; - *p++ = (gain[i] % 10) + 0x30; - if (i < EQ_BANDS - 1) *p++ = ','; + n += sprintf(config + n, "%d,", gain[i]); } + config[n-1] = '\0'; config_set_value(NVS_TYPE_STR, "equalizer", config); equalizer.update = true; } From 533ee5e4089ef6fd439f0c5207f016d8749bdda6 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Wed, 19 Jan 2022 00:51:35 -0800 Subject: [PATCH 14/16] backend for Muse --- build-scripts/I2S-4MFlash-sdkconfig.defaults | 13 ++ build-scripts/SqueezeAmp-sdkconfig.defaults | 12 ++ components/services/battery.c | 3 + components/services/monitor.h | 1 + components/squeezelite/output_i2s.c | 26 ++-- components/targets/CMakeLists.txt | 13 ++ components/targets/init.c | 3 + components/targets/muse/muse.c | 137 +++++++++++++++++++ main/Kconfig.projbuild | 84 +++++++++--- main/esp_app_main.c | 2 + 10 files changed, 265 insertions(+), 29 deletions(-) create mode 100644 components/targets/CMakeLists.txt create mode 100644 components/targets/init.c create mode 100644 components/targets/muse/muse.c diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 40110fd2..3b5a281b 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -281,6 +281,19 @@ CONFIG_LED_GREEN_GPIO=-1 CONFIG_LED_RED_GPIO=-1 # end of LED configuration + +# +# Audio controls +# +CONFIG_AUDIO_CONTROLS="" +# end of Audio Contorls configuration + +# +# AMP configuration +# +CONFIG_AMP_GPIO=-1 +# end of AMP configuration + # # Audio JACK # diff --git a/build-scripts/SqueezeAmp-sdkconfig.defaults b/build-scripts/SqueezeAmp-sdkconfig.defaults index fb63230a..f3fc23f1 100644 --- a/build-scripts/SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp-sdkconfig.defaults @@ -274,6 +274,18 @@ CONFIG_BAT_SCALE="20.24" CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" # end of Squeezelite-ESP32 +# +# Audio controls +# +CONFIG_AUDIO_CONTROLS="" +# end of Audio Contorls configuration + +# +# AMP configuration +# +CONFIG_AMP_GPIO=-1 +# end of AMP configuration + # # Compiler options # diff --git a/components/services/battery.c b/components/services/battery.c index a0134c8c..2b356106 100644 --- a/components/services/battery.c +++ b/components/services/battery.c @@ -41,6 +41,8 @@ static struct { .attenuation = ADC_ATTEN_DB_0, }; +void (*battery_handler_svc)(float value); + /**************************************************************************************** * */ @@ -65,6 +67,7 @@ static void battery_callback(TimerHandle_t xTimer) { if (++battery.count == 30) { battery.avg = battery.sum / battery.count; battery.sum = battery.count = 0; + if (battery_handler_svc) (battery_handler_svc)(battery.avg); ESP_LOGI(TAG, "Voltage %.2fV", battery.avg); } } diff --git a/components/services/monitor.h b/components/services/monitor.h index 3f441ff9..b0710153 100644 --- a/components/services/monitor.h +++ b/components/services/monitor.h @@ -20,6 +20,7 @@ extern bool jack_inserted_svc(void); extern void (*spkfault_handler_svc)(bool inserted); extern bool spkfault_svc(void); +extern void (*battery_handler_svc)(float value); extern float battery_value_svc(void); extern uint16_t battery_level_svc(void); diff --git a/components/squeezelite/output_i2s.c b/components/squeezelite/output_i2s.c index 76ce69cb..5f3a4a2c 100644 --- a/components/squeezelite/output_i2s.c +++ b/components/squeezelite/output_i2s.c @@ -75,6 +75,10 @@ sure that using rate_delay would fix that #define STATS_PERIOD_MS 5000 #define STAT_STACK_SIZE (3*1024) +#ifndef CONFIG_AMP_GPIO_LEVEL +#define CONFIG_AMP_GPIO_LEVEL 1 +#endif + extern struct outputstate output; extern struct buffer *streambuf; extern struct buffer *outputbuf; @@ -101,7 +105,7 @@ static TaskHandle_t stats_task, output_i2s_task; static bool stats; static struct { int gpio, active; -} amp_control = { -1, 1 }, +} amp_control = { CONFIG_AMP_GPIO, CONFIG_AMP_GPIO_LEVEL }, mute_control = { CONFIG_MUTE_GPIO, CONFIG_MUTE_GPIO_LEVEL }; DECLARE_ALL_MIN_MAX; @@ -171,20 +175,16 @@ static void jack_handler(bool inserted) { /**************************************************************************************** * amp GPIO */ +#ifndef AMP_GPIO_LOCKED static void set_amp_gpio(int gpio, char *value) { char *p; if (strcasestr(value, "amp")) { amp_control.gpio = gpio; if ((p = strchr(value, ':')) != NULL) amp_control.active = atoi(p + 1); - - gpio_pad_select_gpio_x(amp_control.gpio); - gpio_set_direction_x(amp_control.gpio, GPIO_MODE_OUTPUT); - gpio_set_level_x(amp_control.gpio, !amp_control.active); - - LOG_INFO("setting amplifier GPIO %d (active:%d)", amp_control.gpio, amp_control.active); } } +#endif /**************************************************************************************** * Set pin from config string @@ -347,13 +347,21 @@ 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; +#ifndef AMP_GPIO_LOCKED parse_set_GPIO(set_amp_gpio); +#endif + + if (amp_control.gpio != -1) { + gpio_pad_select_gpio_x(amp_control.gpio); + gpio_set_direction_x(amp_control.gpio, GPIO_MODE_OUTPUT); + gpio_set_level_x(amp_control.gpio, !amp_control.active); + LOG_INFO("setting amplifier GPIO %d (active:%d)", amp_control.gpio, amp_control.active); + } if (jack_mutes_amp && jack_inserted_svc()) adac->speaker(false); else adac->speaker(true); - adac->headset(jack_inserted_svc()); - + adac->headset(jack_inserted_svc()); // create task as a FreeRTOS task but uses stack in internal RAM { diff --git a/components/targets/CMakeLists.txt b/components/targets/CMakeLists.txt new file mode 100644 index 00000000..f8a5b188 --- /dev/null +++ b/components/targets/CMakeLists.txt @@ -0,0 +1,13 @@ +# This should be made a pure CMake component but as CMake is even +# more shitty under Windows, backslash in path screws it all + +if(CONFIG_MUSE) + message("Compiling for MUSE") + set(src_dirs "muse") +else() + set(src_dirs ".") +endif() + +idf_component_register( SRC_DIRS ${src_dirs} + PRIV_REQUIRES services +) diff --git a/components/targets/init.c b/components/targets/init.c new file mode 100644 index 00000000..f6e42cb8 --- /dev/null +++ b/components/targets/init.c @@ -0,0 +1,3 @@ +// weak should do the job but it does not... + __attribute__((weak)) void target_init(void) { +} diff --git a/components/targets/muse/muse.c b/components/targets/muse/muse.c new file mode 100644 index 00000000..d09fa402 --- /dev/null +++ b/components/targets/muse/muse.c @@ -0,0 +1,137 @@ +/* + YOUR LICENSE + */ +#include +#include +#include +#include +#include +#include +#include +#include "driver/rmt.h" +#include "monitor.h" + +///////////////////////////////////////////////////////////////// +//*********************** NeoPixels *************************** +//////////////////////////////////////////////////////////////// +#define NUM_LEDS 1 +#define LED_RMT_TX_CHANNEL 0 +#define LED_RMT_TX_GPIO 22 + +#define BITS_PER_LED_CMD 24 +#define LED_BUFFER_ITEMS ((NUM_LEDS * BITS_PER_LED_CMD)) + +// These values are determined by measuring pulse timing with logic analyzer and adjusting to match datasheet. +#define T0H 14 // 0 bit high time +#define T1H 52 // 1 bit high time +#define TL 52 // low time for either bit + +#define GREEN 0xFF0000 +#define RED 0x00FF00 +#define BLUE 0x0000FF +#define WHITE 0xFFFFFF +#define YELLOW 0xE0F060 +struct led_state { + uint32_t leds[NUM_LEDS]; +}; + +void ws2812_control_init(void); +void ws2812_write_leds(struct led_state new_state); + +/////////////////////////////////////////////////////////////////// + +static const char TAG[] = "muse"; + +static void (*battery_handler_chain)(float value); + +static void battery(void *data); +static void battery_svc(float value); + +void target_init(void) { + battery_handler_chain = battery_handler_svc; + battery_handler_svc = battery_svc; + ESP_LOGI(TAG, "Initializing for Muse"); +} + +static void battery_svc(float value) { + ESP_LOGI(TAG, "Called for battery service with %f", value); + if (battery_handler_chain) battery_handler_chain(value); +} + +// Battery monitoring +static void battery(void *data) +{ +#define VGREEN 2300 +#define VRED 2000 +#define NM 10 + static int val; + static int V[NM]; + static int I=0; + int S; + for(int i=0;i= NM)I = 0; + S = 0; + for(int i=0;i VGREEN) new_state.leds[0] = GREEN; + if(val < VRED) new_state.leds[0] = RED; + printf("====> %d %6x\n", val, new_state.leds[0]); + ws2812_write_leds(new_state); + + } +} + +// This is the buffer which the hw peripheral will access while pulsing the output pin +rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS]; + +void setup_rmt_data_buffer(struct led_state new_state); + +void ws2812_control_init(void) +{ + rmt_config_t config; + config.rmt_mode = RMT_MODE_TX; + config.channel = LED_RMT_TX_CHANNEL; + config.gpio_num = LED_RMT_TX_GPIO; + config.mem_block_num = 3; + config.tx_config.loop_en = false; + config.tx_config.carrier_en = false; + config.tx_config.idle_output_en = true; + config.tx_config.idle_level = 0; + config.clk_div = 2; + + ESP_ERROR_CHECK(rmt_config(&config)); + ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0)); +} + +void ws2812_write_leds(struct led_state new_state) { + setup_rmt_data_buffer(new_state); + ESP_ERROR_CHECK(rmt_write_items(LED_RMT_TX_CHANNEL, led_data_buffer, LED_BUFFER_ITEMS, false)); + ESP_ERROR_CHECK(rmt_wait_tx_done(LED_RMT_TX_CHANNEL, portMAX_DELAY)); +} + +void setup_rmt_data_buffer(struct led_state new_state) +{ + for (uint32_t led = 0; led < NUM_LEDS; led++) { + uint32_t bits_to_send = new_state.leds[led]; + uint32_t mask = 1 << (BITS_PER_LED_CMD - 1); + for (uint32_t bit = 0; bit < BITS_PER_LED_CMD; bit++) { + uint32_t bit_is_set = bits_to_send & mask; + led_data_buffer[led * BITS_PER_LED_CMD + bit] = bit_is_set ? + (rmt_item32_t){{{T1H, 1, TL, 0}}} : + (rmt_item32_t){{{T0H, 1, TL, 0}}}; + mask >>= 1; + } + } + } + diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index ed29407b..d2947f14 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -26,6 +26,8 @@ menu "Squeezelite-ESP32" help Set logging level info|debug|sdebug endmenu + config AMP_LOCKED + bool config JACK_LOCKED bool config BAT_LOCKED @@ -55,11 +57,17 @@ menu "Squeezelite-ESP32" select LED_LOCKED select SPKFAULT_LOCKED config BASIC_I2C_BT - bool "Generic I2S & Bluetooth" - config TWATCH2020 - bool "T-WATCH2020 by LilyGo" + bool "Generic I2S & Bluetooth" + config TWATCH2020 + bool "T-WATCH2020 by LilyGo" + select I2C_LOCKED + config MUSE + bool "Muse" + select JACK_LOCKED + select BAT_LOCKED select I2C_LOCKED - endchoice + select AMP_LOCKED + endchoice config RELEASE_API string "Software update URL" default "https://api.github.com/repos/sle118/squeezelite-esp32/releases" @@ -76,11 +84,13 @@ menu "Squeezelite-ESP32" string default "SqueezeAMP" if SQUEEZEAMP default "Squeezelite-TWATCH" if TWATCH2020 + default "Muse" if MUSE default "Squeezelite-ESP32" config FW_PLATFORM_NAME string default "SqueezeAmp" if SQUEEZEAMP default "TWATCH" if TWATCH2020 + default "Muse" if MUSE default "ESP32" # AGGREGATES - begin # these parameters are "aggregates" that take precedence. They must have a default value @@ -88,6 +98,7 @@ menu "Squeezelite-ESP32" string default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP default "model=I2S,bck=26,ws=25,do=33,i2c=53,sda=21,scl=22" if TWATCH2020 + default "model=I2S,bck=5,ws=25,do=26,di=35,i2c=16,sda=18,scl=23,mck" if MUSE default "" config SPDIF_CONFIG string @@ -98,7 +109,8 @@ menu "Squeezelite-ESP32" default "" config SPI_CONFIG string - default "dc=27,data=19,clk=18" if TWATCH2020 + default "dc=27,data=19,clk=18" if TWATCH2020 + default "mosi=15,miso=2,clk=14" if MUSE default "" config DISPLAY_CONFIG string @@ -107,17 +119,25 @@ menu "Squeezelite-ESP32" config ETH_CONFIG string default "" + # AGGREGATES - end config DAC_CONTROLSET string - default '{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and" } ] }' if TWATCH2020 + default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020 + default "{\"init\":[ {\"reg\":0,\"val\":128}, {\"reg\":0,\"val\":0}, {\"reg\":25,\"val\":4}, {\"reg\":1,\"val\":80}, {\"reg\":2,\"val\":0}, {\"reg\":8,\"val\":0}, {\"reg\":4,\"val\":192}, {\"reg\":0,\"val\":18}, {\"reg\":1,\"val\":0}, {\"reg\":23,\"val\":24}, {\"reg\":24,\"val\":2}, {\"reg\":38,\"val\":9}, {\"reg\":39,\"val\":144}, {\"reg\":42,\"val\":144}, {\"reg\":43,\"val\":128}, {\"reg\":45,\"val\":128}, {\"reg\":27,\"val\":0}, {\"reg\":26,\"val\":0}, {\"reg\":2,\"val\":240}, {\"reg\":2,\"val\":0}, {\"reg\":29,\"val\":28}, {\"reg\":4,\"val\":48}, {\"reg\":25,\"val\":0} ]}" if MUSE + default "" + config AUDIO_CONTROLS + string + default "[{\"gpio\":32, \"pull\":true, \"debounce\":10, \"normal\":{\"pressed\":\"ACTRLS_VOLDOWN\"}}, {\"gpio\":19, \"pull\":true, \"debounce\":40, \"normal\":{\"pressed\":\"ACTRLS_VOLUP\"}}, {\"gpio\":12, \"pull\":true, \"debounce\":40, \"longpress\":1000, \"normal\":{\"pressed\":\"ACTRLS_TOGGLE\"},\"longpress\":{\"pressed\":\"ACTRLS_POWER\"}}]" if MUSE default "" - # AGGREGATES - end - - # VARs that must be reset when changign target + default -1 + config AMP_GPIO + int + default 21 if MUSE + default -1 config JACK_GPIO int - default 34 if SQUEEZEAMP - default -1 + default 34 if SQUEEZEAMP || MUSE + default -1 config SPKFAULT_GPIO int default 2 if SQUEEZEAMP @@ -129,6 +149,7 @@ menu "Squeezelite-ESP32" config LED_GREEN_GPIO int default 12 if SQUEEZEAMP + default 22 if MUSE default -1 config LED_RED_GPIO int @@ -274,6 +295,14 @@ menu "Squeezelite-ESP32" help Enable Spotify connect using CSpot endmenu + + menu "Controls" + depends on !MUSE + config AUDIO_CONTROLS + string "Audio buttons set (JSON)" + help + Configuration of buttons (see README for syntax) + endmenu menu "Display Screen" depends on !TWATCH2020 @@ -320,8 +349,9 @@ menu "Squeezelite-ESP32" Set parameters of GPIO extender model=[,addr=][,base=<100..N>][,count=<0..32>][,intr=][,port=dac|system] endmenu + menu "LED configuration" - visible if !SQUEEZEAMP && !TWATCH2020 + visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE config LED_GREEN_GPIO int "Green led GPIO" help @@ -329,7 +359,7 @@ menu "Squeezelite-ESP32" config LED_GREEN_GPIO_LEVEL int "Green led ON level" depends on LED_GREEN_GPIO != -1 - config LED_RED_GPIO + config LED_RED_GPIO int "Red led GPIO" help Set to -1 for no LED @@ -339,9 +369,10 @@ menu "Squeezelite-ESP32" default 0 if SQUEEZEAMP default 1 endmenu - menu "Audio JACK" - visible if !SQUEEZEAMP && !TWATCH2020 - config JACK_GPIO + + menu "Audio JACK" + visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE + config JACK_GPIO int "Jack insertion GPIO" help GPIO to detect speaker jack insertion. Set to -1 for no detection. @@ -349,10 +380,23 @@ menu "Squeezelite-ESP32" depends on JACK_GPIO != -1 int "Level when inserted (0/1)" default 0 - endmenu - menu "Speaker Fault" - visible if !SQUEEZEAMP && !TWATCH2020 - config SPKFAULT_GPIO + endmenu + + menu "Amplifier" + visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE + config AMP_GPIO + int "Amplifier GPIO" + help + GPIO to switch on/off amplifier. Set to -1 for no amplifier. + config AMP_GPIO_LEVEL + depends on AMP_GPIO != -1 + int "Active level(0/1)" + default 1 + endmenu + + menu "Speaker Fault" + visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE + config SPKFAULT_GPIO int "Speaker fault GPIO" help GPIO to detect speaker fault condition. Set to -1 for no detection. diff --git a/main/esp_app_main.c b/main/esp_app_main.c index b2e9178f..b70c6099 100644 --- a/main/esp_app_main.c +++ b/main/esp_app_main.c @@ -71,6 +71,7 @@ extern const uint8_t server_cert_pem_end[] asm("_binary_github_pem_end"); // as an exception _init function don't need include extern void services_init(void); extern void display_init(char *welcome); +extern void target_init(void); const char * str_or_unknown(const char * str) { return (str?str:unknown_string_placeholder); } const char * str_or_null(const char * str) { return (str?str:null_string_placeholder); } bool is_recovery_running; @@ -446,6 +447,7 @@ void app_main() ESP_LOGI(TAG,"Initializing display"); display_init("SqueezeESP32"); MEMTRACE_PRINT_DELTA(); + target_init(); if(is_recovery_running && display){ GDS_ClearExt(display, true); GDS_SetFont(display, &Font_line_2 ); From 750e455b0dfee1f43a9ca95f7a163939576ad59e Mon Sep 17 00:00:00 2001 From: Philippe G Date: Wed, 19 Jan 2022 01:16:49 -0800 Subject: [PATCH 15/16] targets --- main/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 11d1029f..e0509541 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register(SRC_DIRS . - PRIV_REQUIRES esp_common wifi-manager pthread squeezelite-ota platform_console telnet display + PRIV_REQUIRES esp_common wifi-manager pthread squeezelite-ota platform_console telnet display targets EMBED_FILES ../server_certs/github.pem LDFRAGMENTS "linker.lf" ) From d1dd27b7cb14387743df61cb7abef66ee6252e09 Mon Sep 17 00:00:00 2001 From: Philippe G Date: Wed, 19 Jan 2022 13:40:03 -0800 Subject: [PATCH 16/16] add Muse support --- build-scripts/I2S-4MFlash-sdkconfig.defaults | 2 +- build-scripts/SqueezeAmp-sdkconfig.defaults | 3 +- components/platform_config/platform_config.h | 5 +++ components/services/accessors.c | 6 --- components/services/battery.c | 28 ++++++------ components/targets/muse/muse.c | 7 +-- main/Kconfig.projbuild | 47 +++++++++++--------- 7 files changed, 51 insertions(+), 47 deletions(-) diff --git a/build-scripts/I2S-4MFlash-sdkconfig.defaults b/build-scripts/I2S-4MFlash-sdkconfig.defaults index 3b5a281b..d3914d3f 100644 --- a/build-scripts/I2S-4MFlash-sdkconfig.defaults +++ b/build-scripts/I2S-4MFlash-sdkconfig.defaults @@ -309,7 +309,7 @@ CONFIG_SPKFAULT_GPIO=-1 # # Battery measure # -CONFIG_BAT_CHANNEL=-1 +CONFIG_BAT_CONFIG="" # end of Battery measure CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" diff --git a/build-scripts/SqueezeAmp-sdkconfig.defaults b/build-scripts/SqueezeAmp-sdkconfig.defaults index f3fc23f1..326bbbd7 100644 --- a/build-scripts/SqueezeAmp-sdkconfig.defaults +++ b/build-scripts/SqueezeAmp-sdkconfig.defaults @@ -269,8 +269,7 @@ CONFIG_JACK_GPIO=34 CONFIG_JACK_GPIO_LEVEL=0 CONFIG_SPKFAULT_GPIO=2 CONFIG_SPKFAULT_GPIO_LEVEL=0 -CONFIG_BAT_CHANNEL=7 -CONFIG_BAT_SCALE="20.24" +CONFIG_BAT_CONFIG="channel=7,scale=20.24,atten=0" CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30 -W" # end of Squeezelite-ESP32 diff --git a/components/platform_config/platform_config.h b/components/platform_config/platform_config.h index cda90644..2df78a36 100644 --- a/components/platform_config/platform_config.h +++ b/components/platform_config/platform_config.h @@ -14,6 +14,11 @@ extern "C" { if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atoi(__p+1); \ } while (0) +#define PARSE_PARAM_FLOAT(S,P,C,V) do { \ + char *__p; \ + if ((__p = strcasestr(S, P)) && (__p = strchr(__p, C))) V = atof(__p+1); \ +} while (0) + #define PARSE_PARAM_STR(S,P,C,V,I) do { \ char *__p; \ if ((__p = strstr(S, P)) && (__p = strchr(__p, C))) { \ diff --git a/components/services/accessors.c b/components/services/accessors.c index 312e0e75..683870d3 100644 --- a/components/services/accessors.c +++ b/components/services/accessors.c @@ -1109,7 +1109,6 @@ cJSON * get_gpio_list(bool refresh) { } gpio_list= cJSON_CreateArray(); -#ifndef CONFIG_BAT_LOCKED char *bat_config = config_alloc_get_default(NVS_TYPE_STR, "bat_config", NULL, 0); if (bat_config) { int channel = -1; @@ -1121,11 +1120,6 @@ cJSON * get_gpio_list(bool refresh) { } free(bat_config); } -#else - if(adc1_pad_get_io_num(CONFIG_BAT_CHANNEL,&gpio_num )==ESP_OK){ - cJSON_AddItemToArray(gpio_list,get_gpio_entry("bat","other",gpio_num,true)); - } -#endif gpio_list=get_GPIO_nvs_list(gpio_list); gpio_list=get_SPDIF_GPIO(gpio_list,is_spdif_config_locked()); gpio_list=get_Rotary_GPIO(gpio_list); diff --git a/components/services/battery.c b/components/services/battery.c index 2b356106..09efe79e 100644 --- a/components/services/battery.c +++ b/components/services/battery.c @@ -35,10 +35,9 @@ static struct { int count; int cells, attenuation; TimerHandle_t timer; -} battery = { - .channel = CONFIG_BAT_CHANNEL, +} battery = { + .channel = -1, .cells = 2, - .attenuation = ADC_ATTEN_DB_0, }; void (*battery_handler_svc)(float value); @@ -76,17 +75,18 @@ static void battery_callback(TimerHandle_t xTimer) { * */ void battery_svc_init(void) { -#ifdef CONFIG_BAT_SCALE - battery.scale = atof(CONFIG_BAT_SCALE); -#endif - - char *nvs_item = config_alloc_get_default(NVS_TYPE_STR, "bat_config", "n", 0); - if (nvs_item) { -#ifndef CONFIG_BAT_LOCKED - PARSE_PARAM(nvs_item, "channel", '=', battery.channel); - PARSE_PARAM(nvs_item, "scale", '=', battery.scale); - PARSE_PARAM(nvs_item, "atten", '=', battery.attenuation); + char *nvs_item = config_alloc_get_default(NVS_TYPE_STR, "bat_config", "", 0); + +#ifdef CONFIG_BAT_LOCKED + char *p = nvs_item; + asprintf(&nvs_item, CONFIG_BAT_CONFIG ",%s", p); + free(p); #endif + + if (nvs_item) { + PARSE_PARAM(nvs_item, "channel", '=', battery.channel); + PARSE_PARAM_FLOAT(nvs_item, "scale", '=', battery.scale); + PARSE_PARAM(nvs_item, "atten", '=', battery.attenuation); PARSE_PARAM(nvs_item, "cells", '=', battery.cells); free(nvs_item); } @@ -99,7 +99,7 @@ void battery_svc_init(void) { battery.timer = xTimerCreate("battery", BATTERY_TIMER / portTICK_RATE_MS, pdTRUE, NULL, battery_callback); xTimerStart(battery.timer, portMAX_DELAY); - ESP_LOGI(TAG, "Battery measure channel: %u, scale %f, cells %u, avg %.2fV", battery.channel, battery.scale, battery.cells, battery.avg); + ESP_LOGI(TAG, "Battery measure channel: %u, scale %f, atten %d, cells %u, avg %.2fV", battery.channel, battery.scale, battery.attenuation, battery.cells, battery.avg); } else { ESP_LOGI(TAG, "No battery"); } diff --git a/components/targets/muse/muse.c b/components/targets/muse/muse.c index d09fa402..1601d64c 100644 --- a/components/targets/muse/muse.c +++ b/components/targets/muse/muse.c @@ -7,7 +7,7 @@ #include #include #include -#include +//#include #include "driver/rmt.h" #include "monitor.h" @@ -43,8 +43,6 @@ void ws2812_write_leds(struct led_state new_state); static const char TAG[] = "muse"; static void (*battery_handler_chain)(float value); - -static void battery(void *data); static void battery_svc(float value); void target_init(void) { @@ -55,10 +53,12 @@ void target_init(void) { static void battery_svc(float value) { ESP_LOGI(TAG, "Called for battery service with %f", value); + // put here your code for LED according to value if (battery_handler_chain) battery_handler_chain(value); } // Battery monitoring +/* static void battery(void *data) { #define VGREEN 2300 @@ -91,6 +91,7 @@ static void battery(void *data) } } +*/ // This is the buffer which the hw peripheral will access while pulsing the output pin rmt_item32_t led_data_buffer[LED_BUFFER_ITEMS]; diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index d2947f14..153ceb51 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -43,6 +43,9 @@ menu "Squeezelite-ESP32" config MUTE_GPIO_LEVEL int default 0 + config WELL_KNOWN + bool + default n menu "Target" choice OUTPUT_TYPE prompt "Main system" @@ -56,17 +59,20 @@ menu "Squeezelite-ESP32" select I2C_LOCKED select LED_LOCKED select SPKFAULT_LOCKED - config BASIC_I2C_BT - bool "Generic I2S & Bluetooth" - config TWATCH2020 - bool "T-WATCH2020 by LilyGo" - select I2C_LOCKED + select WELL_KNOWN config MUSE bool "Muse" select JACK_LOCKED select BAT_LOCKED select I2C_LOCKED - select AMP_LOCKED + select AMP_LOCKED + select WELL_KNOWN + config BASIC_I2C_BT + bool "Generic I2S & Bluetooth" + config TWATCH2020 + bool "T-WATCH2020 by LilyGo" + select I2C_LOCKED + select WELL_KNOWN endchoice config RELEASE_API string "Software update URL" @@ -129,7 +135,10 @@ menu "Squeezelite-ESP32" string default "[{\"gpio\":32, \"pull\":true, \"debounce\":10, \"normal\":{\"pressed\":\"ACTRLS_VOLDOWN\"}}, {\"gpio\":19, \"pull\":true, \"debounce\":40, \"normal\":{\"pressed\":\"ACTRLS_VOLUP\"}}, {\"gpio\":12, \"pull\":true, \"debounce\":40, \"longpress\":1000, \"normal\":{\"pressed\":\"ACTRLS_TOGGLE\"},\"longpress\":{\"pressed\":\"ACTRLS_POWER\"}}]" if MUSE default "" - default -1 + config BAT_CONFIG + default "channel=7,scale=20.24,atten=0" if SQUEEZEAMP + default "channel=5,scale=1,atten=3,cells=1" if MUSE + default "" config AMP_GPIO int default 21 if MUSE @@ -371,7 +380,7 @@ menu "Squeezelite-ESP32" endmenu menu "Audio JACK" - visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE + visible if !WELL_KNOWN config JACK_GPIO int "Jack insertion GPIO" help @@ -383,7 +392,7 @@ menu "Squeezelite-ESP32" endmenu menu "Amplifier" - visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE + visible if !WELL_KNOWN config AMP_GPIO int "Amplifier GPIO" help @@ -395,7 +404,7 @@ menu "Squeezelite-ESP32" endmenu menu "Speaker Fault" - visible if !SQUEEZEAMP && !TWATCH2020 && !MUSE + visible if !WELL_KNOWN config SPKFAULT_GPIO int "Speaker fault GPIO" help @@ -405,20 +414,16 @@ menu "Squeezelite-ESP32" int "Level when fault (0/1)" default 0 endmenu + menu "Battery measure" - visible if !SQUEEZEAMP && !TWATCH2020 - config BAT_CHANNEL - int "Set channel (0..7)" + visible if !WELL_KNOWN + config BAT_CONFIG + string "Battery acquisition configuration" help - Read a value every 10s on ADC1 on set Channel - config BAT_SCALE - string "Set scaling factor" - depends on BAT_CHANNEL != -1 - default "20.24" if SQUEEZEAMP - default "" - help - Set the scaling factor for this 12 bits ADC + Sets parameters for battery voltage measure + channel=<0..7>,scale=,atten=,cells=<1..3> endmenu + config DEFAULT_COMMAND_LINE string "Default command line to execute" default "squeezelite -o I2S -b 500:2000 -d all=info -C 30"