Skip to content

Commit

Permalink
add AirPlay artwork
Browse files Browse the repository at this point in the history
  • Loading branch information
philippe44 committed Jan 9, 2022
1 parent a39c4ab commit a16a167
Show file tree
Hide file tree
Showing 13 changed files with 69 additions and 30 deletions.
11 changes: 6 additions & 5 deletions components/display/core/gds.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ); }
1 change: 1 addition & 0 deletions components/display/core/gds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand Down
18 changes: 9 additions & 9 deletions components/display/core/gds_font.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion components/display/core/gds_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
12 changes: 6 additions & 6 deletions components/display/core/gds_text.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,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 );
}
Expand All @@ -118,7 +118,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;
}

/****************************************************************************************
Expand All @@ -145,7 +145,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);
Expand All @@ -156,7 +156,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';
}
Expand Down
2 changes: 1 addition & 1 deletion components/display/core/ifaces/default_if_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand Down
6 changes: 2 additions & 4 deletions components/display/core/ifaces/default_if_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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;
Expand All @@ -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 ) {
Expand Down
30 changes: 30 additions & 0 deletions components/display/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -30,6 +31,7 @@ static const char *TAG = "display";
#define SCROLLABLE_SIZE 384
#define HEADER_SIZE 64
#define DEFAULT_SLEEP 3600
#define ARTWORK_BORDER 1

static EXT_RAM_ATTR struct {
TaskHandle_t task;
Expand All @@ -47,6 +49,10 @@ static EXT_RAM_ATTR struct {
char string[8]; // H:MM:SS
bool visible;
} duration;
struct {
bool enable, fit;
int offset;
} artwork;
TickType_t tick;
} displayer;

Expand Down Expand Up @@ -147,6 +153,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);
Expand Down Expand Up @@ -238,6 +252,19 @@ 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) GDS_DrawJPEG(display, data, x, y, GDS_IMAGE_CENTER | (displayer.artwork.fit ? GDS_IMAGE_FIT : 0));
}

/****************************************************************************************
*
*/
Expand Down Expand Up @@ -378,6 +405,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;
Expand All @@ -388,6 +416,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;
}
Expand All @@ -398,6 +427,7 @@ 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);
displayer.state = DISPLAYER_DOWN;
display_bus(&displayer, DISPLAY_BUS_GIVE);
break;
Expand Down
1 change: 1 addition & 0 deletions components/display/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
2 changes: 1 addition & 1 deletion components/driver_bt/bt_app_sink.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions components/raop/raop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 7 additions & 2 deletions components/raop/raop_sink.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "audio_controls.h"
#include "display.h"
#include "accessors.h"

#include "log_util.h"
#include "trace.h"

Expand Down Expand Up @@ -115,7 +114,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);
Expand All @@ -130,8 +129,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);
Expand Down
2 changes: 1 addition & 1 deletion components/raop/raop_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ;

Expand Down

0 comments on commit a16a167

Please sign in to comment.