Skip to content

Commit

Permalink
New version: now displaying librespot logs directly in the UI!
Browse files Browse the repository at this point in the history
Plus minor changes:
- Volume set to 80% by default
- Window starts fullscreen now, and different screen sizes are supported
- Constants are now defined at the top of testspriteminimal.c
  • Loading branch information
slax57 committed May 26, 2018
1 parent 2ce0a1e commit 8df3497
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 47 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#

CFLAGS := -I$(MARVELL_ROOTFS)/usr/include/SDL2
LDFLAGS := -lSDL2
LDFLAGS := -lSDL2 -lSDL2_ttf

testspriteminimal: testspriteminimal.o
$(CC) -o $@ $< $(LDFLAGS)
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ As such, note that:
## Functionalities
This code allows to build an app that you can install and run on your _steamlink_. Once it is installed, you can launch it directly from the _steamlink_ home menu.
This app starts _librespot_ as a background program, and pipes the audio to the first audio device it finds.
You juste have to use the _spotify connect_ (from your phone or a computer, using the official Spotify application) to start a playlist.
You juste have to use _spotify connect_ (from your phone or a computer, using the official Spotify application) to start a song.
Once you're done, you can exit the app by pressing any key on your keyboard or any buttons on your gamepad (should be compatible whith the Steam gamepad).

**Be aware that this is all the app does for now! There is no current track or status information displayed, it's basically just a headless player, and the only thing displayed on the TV is a static image.**
**Be aware that this is all the app does for now! Since the new version, the librespot logs are displayed, allowing you to know which track is being played. But still, there is no complex GUI with album cover or so, it's basically just a headless player with a very simple interface.**

# Instructions
## Building
Expand Down Expand Up @@ -88,7 +88,7 @@ By default the app is configured to redirect _librespot_ logs into this file:
If you have trouble using _spotify4steamlink_, you should start by having a look at this file ;).

As I said earlier, you might also encounter troubles when exiting the app. For now, the only workaround is to unplug the _steamlink_, and then plug it back again.
Still, during my tests, I noticed the problem don't seem to happen when you exit _while playing a song_.
Still, during my tests, I noticed the problem seems **not to happen** if you exit **while playing a song**.
Hopefully having this knowledge will prevent you troubles :).

# Acknowledgements
Expand Down
3 changes: 2 additions & 1 deletion build_steamlink.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ export DESTDIR="${PWD}/steamlink/apps/spotify"
# Copy the files to the app directory
mkdir -p "${DESTDIR}"
cp -v testspriteminimal "${DESTDIR}"
cp -v spotify2.bmp "${DESTDIR}"
cp -v spotify3.bmp "${DESTDIR}"
cp -v consolas.ttf "${DESTDIR}"
cp -v start_librespot.sh "${DESTDIR}"

cp -v icon2.png "${DESTDIR}/icon.png"
Expand Down
Binary file added consolas.ttf
Binary file not shown.
Binary file removed spotify2.bmp
Binary file not shown.
Binary file added spotify3.bmp
Binary file not shown.
212 changes: 170 additions & 42 deletions testspriteminimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,30 +17,59 @@
#include <emscripten/emscripten.h>
#endif

#include "SDL.h"

#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480

#define AUDIO_SAMPLES 4096
#include "SDL.h"
#include "SDL_ttf.h"

#define INITIAL_WINDOW_WIDTH 640
#define INITIAL_WINDOW_HEIGHT 480

#define AUDIO_SAMPLES 4096

#define LIBRESPOT_START_CMD "/home/steam/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot --cache /var/cache --disable-audio-cache --name steamlink --disable-discovery --bitrate 320 --initial-volume 85 --backend pipe 2>/tmp/spotify.log"
#define LIBRESPOT_KILL_CMD "pidof /home/steam/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot | xargs kill"
#define LIBRESPOT_LOG_FILE "/tmp/spotify.log"

#define BACKGROUND_BMP_FILE "spotify3.bmp"

#define FONT_FILE "consolas.ttf"
#define FONT_SIZE 18

// Disable this flag when publishing to steamlink
//#define TEST_MODE


/* -- Global variables -- */

static SDL_Texture *sprite;
static int sprite_w, sprite_h;

SDL_Renderer *renderer;
int done;

// variable declarations
static FILE *audio_buf; // global pointer to the audio buffer to be played
static FILE *audio_buf; // global pointer to the audio buffer to be played
TTF_Font *font = NULL;
static FILE *spotify_log_file;
SDL_Color text_color = {255, 255, 255}; // white
SDL_Surface *text_surf = NULL;
static int text_square_pos_x, text_square_pos_y, text_square_pos_w, text_square_pos_h;


/* -- Functions -- */

/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void
quit(int rc)
{
exit(rc);
}

void compute_text_square_dimensions(SDL_Window* window)
{
int window_w, window_h;
SDL_GetWindowSize(window, &window_w, &window_h);
// Converting dimensions from a 1920*1080 screen if necessary
text_square_pos_x = 680 * window_w / 1920;
text_square_pos_y = 126 * window_h / 1080;
text_square_pos_w = 1000 * window_w / 1920;
text_square_pos_h = 906 * window_h / 1080;
}

int
Expand Down Expand Up @@ -68,27 +97,79 @@ LoadSprite(char *file, SDL_Renderer *renderer)

/* We're ready to roll. :) */
return (0);
}

// Read the tail of the log file
char* tailLogFile()
{
long lSize;
char * buffer;
size_t result;

// obtain file size:
fseek (spotify_log_file , 0 , SEEK_END);
lSize = ftell (spotify_log_file);
rewind (spotify_log_file);

// allocate memory to contain the whole file:
buffer = (char*) malloc (sizeof(char)*lSize);
if (buffer == NULL) {quit(2);}

// copy the file into the buffer:
result = fread (buffer,1,lSize,spotify_log_file);
if (result != lSize) {quit(3);}

return buffer;
}

// Render the text surface
void
renderText(SDL_Renderer * renderer)
{
// Write our text into the surface
char* buffer = tailLogFile();
text_surf = TTF_RenderUTF8_Blended_Wrapped(font, buffer, text_color, text_square_pos_w);
free(buffer);
// Create texture from the surface
SDL_Texture *sprite = SDL_CreateTextureFromSurface(renderer, text_surf);
if (!sprite) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture from text surface: %s\n", SDL_GetError());
SDL_FreeSurface(text_surf);
quit (-1);
}
// Set the position and size of source and destination rectangles
int actual_w = text_surf->w;
int actual_h = (text_surf->h < text_square_pos_h) ? text_surf->h : text_square_pos_h;
int actual_y = (text_surf->h < text_square_pos_h) ? 0 : (text_surf->h - text_square_pos_h);
SDL_Rect *srcrect = (SDL_Rect *)malloc(sizeof(SDL_Rect));
srcrect->x = 0;
srcrect->y = actual_y;
srcrect->w = actual_w;
srcrect->h = actual_h;
SDL_Rect *dstrect = (SDL_Rect *)malloc(sizeof(SDL_Rect));
dstrect->x = text_square_pos_x;
dstrect->y = text_square_pos_y;
dstrect->w = actual_w;
dstrect->h = actual_h;
// Blit the text onto the screen
SDL_RenderCopy(renderer, sprite, srcrect, dstrect);
// Free memory
SDL_FreeSurface(text_surf);
SDL_DestroyTexture(sprite);
free(dstrect);
free(srcrect);
}

// Render a sprite in position (0, 0) on a black screen
// Render a sprite fullscreen
void
renderBackground(SDL_Renderer * renderer, SDL_Texture * sprite)
{
/* Draw a dark background */
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer);

SDL_Rect *position = malloc(sizeof(SDL_Rect));
position->x = 0;
position->y = 0;
position->w = sprite_w;
position->h = sprite_h;

/* Blit the sprite onto the screen */
SDL_RenderCopy(renderer, sprite, NULL, position);

/* Update the screen! */
SDL_RenderPresent(renderer);
SDL_RenderCopy(renderer, sprite, NULL, NULL);
}

// audio callback function
Expand Down Expand Up @@ -122,7 +203,10 @@ void loop()
}
}

renderBackground(renderer, sprite);
renderBackground(renderer, sprite);
renderText(renderer);
/* Update the screen! */
SDL_RenderPresent(renderer);

#ifdef __EMSCRIPTEN__
if (done) {
Expand All @@ -135,7 +219,7 @@ void loop()
void initAudio() {
// Initialize SDL.
if (SDL_Init(SDL_INIT_AUDIO) < 0)
return 1;
quit(1);

static SDL_AudioSpec want; // the specs of our piece of music
SDL_memset(&want, 0, sizeof(want));
Expand All @@ -150,7 +234,7 @@ void initAudio() {
/* Open the audio device */
if ( SDL_OpenAudio(&want, NULL) < 0 ){
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError());
exit(-1);
quit(-1);
}

/* Start playing */
Expand All @@ -166,12 +250,12 @@ void openAudioBuffer() {
#else
// Make sure the env variable "http_proxy" is not set
unsetenv("http_proxy");
audio_buf = popen("/home/steam/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot -v --cache /var/cache --disable-audio-cache --name steamlink --disable-discovery --bitrate 320 --initial-volume 100 --backend pipe 2>/tmp/spotify.log", "r");
audio_buf = popen(LIBRESPOT_START_CMD, "r");
#endif // TEST_MODE

if (audio_buf == NULL){
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error starting librespot: %s\n", SDL_GetError());
exit(-1);
quit(-1);
}
}

Expand All @@ -181,7 +265,7 @@ void closeAudioBuffer() {
fclose(audio_buf);
#else
// Send the SIGTERM signal to librespot
system("pidof /home/steam/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot | xargs kill");
system(LIBRESPOT_KILL_CMD);
// Close the pipe to librespot
pclose(audio_buf);
#endif // TEST_MODE
Expand All @@ -192,44 +276,88 @@ void stopAudio() {
// shut everything down
SDL_Delay(100);
SDL_CloseAudio();
}

void openSpotifyLogFile() {

#ifdef TEST_MODE
spotify_log_file = fopen("spotify.log", "r");
#else
spotify_log_file = fopen(LIBRESPOT_LOG_FILE, "r");
#endif // TEST_MODE

if (spotify_log_file == NULL){
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error opening librespot log file: %s\n", SDL_GetError());
quit(-1);
}
}

void closeSpotifyLogFile() {
fclose(spotify_log_file);
}


/* -- MAIN function -- */

int
main(int argc, char *argv[])
{
{
/* SDL Init - Graphics */
SDL_Window *window;

/* Enable standard application logging */
// Enable standard application logging
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);

if (SDL_CreateWindowAndRenderer(WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer) < 0) {
// Create window and renderer
if (SDL_CreateWindowAndRenderer(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT, SDL_WINDOW_FULLSCREEN_DESKTOP, &window, &renderer) < 0) {
quit(2);
}

}
// Compute text square dimensions
compute_text_square_dimensions(window);
// Load the background image
if (LoadSprite("spotify2.bmp", renderer) < 0) {
if (LoadSprite(BACKGROUND_BMP_FILE, renderer) < 0) {
quit(2);
}

// Init subsystem with game controller support
SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER );

/* SDL Init - Audio */
// Start librespot and open audio buffer
openAudioBuffer();
// Open audio device and start playback
initAudio();

/* SDL Init - TTF */
if(TTF_Init() == -1)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error in TTF_Init: %s\n", TTF_GetError());
quit(EXIT_FAILURE);
}
// Load Font file
font = TTF_OpenFont(FONT_FILE, FONT_SIZE);
// Load Spotify log file
openSpotifyLogFile();

openAudioBuffer();
initAudio();

/* Main render loop */
done = 0;

#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#else
while (!done) {
loop();
}
#endif

#endif


/*SDL Close - TTF */
closeSpotifyLogFile();
TTF_CloseFont(font);
TTF_Quit();

/* SDL Close - Audio */
stopAudio();
closeAudioBuffer();


/* SDL Close - Graphics */
SDL_QuitSubSystem( SDL_INIT_GAMECONTROLLER );

quit(0);
Expand Down

0 comments on commit 8df3497

Please sign in to comment.