Skip to content

Commit

Permalink
Stability fixes + Enable Discovery mode (#1)
Browse files Browse the repository at this point in the history
* Fix text surf size for long texts

* Fix SDL Windows size for testing + kill pre-existing librespot daemon

* Librespot binaries are now provided with the app

* Update Readme and librespot-org-build inclusion
  • Loading branch information
slax57 authored Jul 14, 2019
1 parent 8df3497 commit 7ec8ea3
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
librespot-org-build/arm-unknown-linux-gnueabihf
48 changes: 17 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,58 @@ What you will find on this repo is just the result of some experiments I made to

As such, note that:
* The code is really not optimised nor modular. You might have to refactor it to fit your needs.
* The app might still be buggy or unstable, especially concerning the program termination.
* I may try to improve it in the future, mainly to add some configuration variables, or maybe to add some features like displaying the current track and so... But please note that I only do this on my free time, so this might come late (if ever), and for now I do not intend to offer much support for what I posted. As I said earlier, this is just an experiment I made for myself, and I just thought it might be useful to others if I shared it here :)
* Using _librespot_ to connect to Spotify's API is probably forbidden by them. Use at your own risk.

## Prerequisite
* This example is based on the open source unofficial spotify client [librespot](https://github.com/librespot-org/librespot). You will have to get it and build it prior to using this app. Although I give some tips about the cross-compilation parameters I used, if you need support for building you need to address your issues to them directly.
* _librespot_ requires a Premium Spotify account.
* This app needs the [steamlink SDK](https://github.com/ValveSoftware/steamlink-sdk) to build. Download it and get familiar with it first.
* Since the installation process is not fully automated yet, you will need an SSH access to your _steamlink_. In order to do this, follow the instructions given [here](https://github.com/ValveSoftware/steamlink-sdk#ssh-access).

## 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 _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! 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.**
**Be aware that this is all the app does for now!** Since the latest 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
### librespot
Follow [librespot cross compiling instructions](https://github.com/librespot-org/librespot/wiki/Cross-compiling) provided on their wiki.
The target architecture `arm-unknown-linux-gnueabihf` is compatible with the _steamlink_.
I recommand building the _docker_ image as suggested:

**Before you use the docker image to build librespot**, you need to apply the patch described [here](https://github.com/librespot-org/librespot/wiki/Compile-librespot-for-kernel-prior-3.9).
This will enable the _discovery_ feature, allowing you to launch librespot without having to provide your Spotify account credentials.

Once that _mDNS_ is patched, build the _docker_ image as suggested:
```Shell
docker build -t librespot-cross -f contrib/Dockerfile .
```
And then use this line to build for the correct architecture:

Then, use this line to build for the correct architecture:
```Shell
docker run -v /tmp/librespot-build:/build librespot-cross cargo build --release --target arm-unknown-linux-gnueabihf --no-default-features --features alsa-backend
docker run -v /tmp/librespot-build:/build librespot-cross cargo build --release --target arm-unknown-linux-gnueabihf --no-default-features
```

### spotify4steamlink
The sources of this app are meant to be placed in the `examples` folder of the **steamlink sdk**.
They contain a `build_steamlink.sh` script that takes care of the cross compilation for you.
If the build succeeds, it should generate this file in your current directory:
```
steamlink/apps/spotify.tgz
```

## Installation
### librespot
First you need to transfer (via SSH) the _librespot_ binaries you juste compiled on to the _steamlink_.
I recommend placing the files so that the `librespot` executable ends up here:
```
/home/steam/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot
```
If you do not follow this convention, you will have to manually edit the file `testspriteminimal.c` to change the file location (2 occurrences!) and rebuild _spotify4steamlink_.
You need to paste the _librespot_ binaries you juste compiled in the `librespot-org-build` folder of this repo.

You also need to make the binary executable:
Then you can now launch
```Shell
cd /home/steam/librespot-org-build/arm-unknown-linux-gnueabihf/release/
chmod +x librespot
./build_steamlink.sh
```

Now you need to lauch it a first time manually. This ensures the executable works correctly, but also this enables you to input your credentials. _librespot_ uses a credential cache so you won't have to do it again later.
Run this line replacing `<your_username>` by your spotify user name:
```Shell
./librespot -v --cache /var/cache --name steamlink --disable-discovery --username <your_username>
If the build succeeds, it should generate this file in your current directory:
```
steamlink/apps/spotify4steamlink.tgz
```
You will be prompted for your password.

If the authentication succeeds, you are ready for the next step!
Just use `CTRL+C` to exit _librespot_ (do not try to play a song yet, because it won't work with ALSA..., which is why we need to use a pipe).

### spotify4steamlink
## Installation
Now we are going to install _spotify4steamlink_ on the _steamlink_.

Copy the `steamlink` folder that was created during the build step to a USB flash drive.
Expand All @@ -87,7 +73,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.
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 seems **not to happen** if you exit **while playing a song**.
Hopefully having this knowledge will prevent you troubles :).

Expand Down
22 changes: 18 additions & 4 deletions build_steamlink.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,36 @@ cd "${TOP}"

make $MAKE_J || exit 2

export DESTDIR="${PWD}/steamlink/apps/spotify"
export DESTDIR="${PWD}/steamlink/apps/spotify4steamlink"

# Check that the librespot binaries are provided
if [ ! -f ${PWD}/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot ]; then
echo "librespot binary is missing!"
echo "Please provide it in the 'librespot-org-build' folder"
echo "Exiting"
exit 10
fi

# Copy the files to the app directory
mkdir -p "${DESTDIR}"
cp -v testspriteminimal "${DESTDIR}"
cp -v spotify3.bmp "${DESTDIR}"
cp -v consolas.ttf "${DESTDIR}"
cp -v start_librespot.sh "${DESTDIR}"

cp -v spotify4steamlink.sh "${DESTDIR}"
cp -v icon2.png "${DESTDIR}/icon.png"
cp -rv ${PWD}/librespot-org-build "${DESTDIR}/librespot-org-build"

# Set spotify4steamlink.sh executable
chmod +x "${DESTDIR}/spotify4steamlink.sh"

# Set the librespot binaries executable
chmod +x "${DESTDIR}/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot"

# Create the table of contents and icon
cat >"${DESTDIR}/toc.txt" <<__EOF__
name=Spotify
icon=icon.png
run=testspriteminimal
run=spotify4steamlink.sh
__EOF__

# Pack it up
Expand Down
4 changes: 4 additions & 0 deletions librespot-org-build/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Paste in the _librespot_ binaries **here**!

The _librespot_ executable should be in the following location: `./arm-unknown-linux-gnueabihf/release/librespot`

1 change: 1 addition & 0 deletions spotify4steamlink.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./testspriteminimal > /tmp/testspriteminimal.log 2>&1
58 changes: 45 additions & 13 deletions testspriteminimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
#include "SDL.h"
#include "SDL_ttf.h"

#define INITIAL_WINDOW_WIDTH 640
#define INITIAL_WINDOW_HEIGHT 480
#define INITIAL_WINDOW_WIDTH 1280
#define INITIAL_WINDOW_HEIGHT 720

#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_START_CMD "/home/apps/spotify4steamlink/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot --cache /var/cache --disable-audio-cache --name steamlink --bitrate 320 --initial-volume 85 --backend pipe 2>/tmp/spotify.log"
#define LIBRESPOT_KILL_CMD "pidof /home/apps/spotify4steamlink/librespot-org-build/arm-unknown-linux-gnueabihf/release/librespot | xargs kill"
#define LIBRESPOT_LOG_FILE "/tmp/spotify.log"

#define BACKGROUND_BMP_FILE "spotify3.bmp"
Expand Down Expand Up @@ -65,11 +65,11 @@ 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;
// Converting dimensions from a 1280*720 screen if necessary
text_square_pos_x = 455 * window_w / 1280;
text_square_pos_y = 84 * window_h / 720;
text_square_pos_w = 700 * window_w / 1280;
text_square_pos_h = 555 * window_h / 720;
}

int
Expand Down Expand Up @@ -122,6 +122,26 @@ char* tailLogFile()
return buffer;
}

// Count the number of lines in log file
int logLinesCount()
{
rewind (spotify_log_file);

int count = 0;
char ch;

while(!feof(spotify_log_file))
{
ch = fgetc(spotify_log_file);
if(ch == '\n')
{
count++;
}
}

return count;
}

// Render the text surface
void
renderText(SDL_Renderer * renderer)
Expand All @@ -130,6 +150,10 @@ renderText(SDL_Renderer * renderer)
char* buffer = tailLogFile();
text_surf = TTF_RenderUTF8_Blended_Wrapped(font, buffer, text_color, text_square_pos_w);
free(buffer);
if (text_surf == NULL) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create text surface from char buffer: %s\n", SDL_GetError());
return;
}
// Create texture from the surface
SDL_Texture *sprite = SDL_CreateTextureFromSurface(renderer, text_surf);
if (!sprite) {
Expand All @@ -138,9 +162,10 @@ renderText(SDL_Renderer * renderer)
quit (-1);
}
// Set the position and size of source and destination rectangles
int log_lines = logLinesCount();
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);
int actual_y = ((text_surf->h - (log_lines * 2)) < text_square_pos_h) ? 0 : ((text_surf->h - (log_lines * 2)) - text_square_pos_h);
SDL_Rect *srcrect = (SDL_Rect *)malloc(sizeof(SDL_Rect));
srcrect->x = 0;
srcrect->y = actual_y;
Expand Down Expand Up @@ -247,7 +272,9 @@ void openAudioBuffer() {
/* Start librespot and gather std output stream */
#ifdef TEST_MODE
audio_buf = fopen("sample.bin", "rb");
#else
#else
// Send the SIGTERM signal to librespot, to kill any pre-existing daemon still running
system(LIBRESPOT_KILL_CMD);
// Make sure the env variable "http_proxy" is not set
unsetenv("http_proxy");
audio_buf = popen(LIBRESPOT_START_CMD, "r");
Expand Down Expand Up @@ -306,8 +333,13 @@ main(int argc, char *argv[])
SDL_Window *window;
// Enable standard application logging
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
// Create window and renderer
if (SDL_CreateWindowAndRenderer(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT, SDL_WINDOW_FULLSCREEN_DESKTOP, &window, &renderer) < 0) {
// Create window and renderer
#ifdef TEST_MODE
Uint32 flags = SDL_WINDOW_SHOWN;
#else
Uint32 flags = SDL_WINDOW_FULLSCREEN_DESKTOP;
#endif // TEST_MODE
if (SDL_CreateWindowAndRenderer(INITIAL_WINDOW_WIDTH, INITIAL_WINDOW_HEIGHT, flags, &window, &renderer) < 0) {
quit(2);
}
// Compute text square dimensions
Expand Down

0 comments on commit 7ec8ea3

Please sign in to comment.