Search code examples
c++audio-streaminglibspotify

Libspotify simple hello world


I recently started using libspotify and were writing a simple hello world, based on the sample code of jukebox.h.

My code currently looks like this:

#include <stdio.h>
#include "libspotify/api.h"
#include "Key.h"
#include "Password.h"
#include <stdlib.h>
#include <pthread.h>
#include <time.h>

#define true 1
#define false 0

sp_session *g_session;
bool g_notify_do;
static pthread_mutex_t g_notify_mutex;
static pthread_cond_t g_notify_cond;

#define DEBUG 1

__stdcall static void debug(const char *format, ...) {
    if (!DEBUG)
        return;

    va_list argptr;
    va_start(argptr, format);
    vprintf(format, argptr);
    printf("\n");
}

void assertSpotify(sp_error error, char *details) {
    if (error != SP_ERROR_OK) {
        debug("Fatal error: %s", details);
        exit(1);
    }
}

__stdcall static void notify_main_thread(sp_session *sess) {
    pthread_mutex_lock(&g_notify_mutex);
    g_notify_do = 1;
    pthread_cond_signal(&g_notify_cond);
    pthread_mutex_unlock(&g_notify_mutex);
}

__stdcall static void logged_in(sp_session *sess, sp_error error) {
    assertSpotify(error, "Could not log in.");

    sp_playlistcontainer *pc = sp_session_playlistcontainer(sess);
    printf("Looking at %d playlists\n", sp_playlistcontainer_num_playlists(pc));
}

int main(void) {
    sp_error err;
    static sp_session_callbacks session_callbacks = {};
    static sp_session_config spconfig = {};
    int next_timeout = 0;

    printf("Starting up...\n");
    session_callbacks.notify_main_thread = &notify_main_thread;
    session_callbacks.logged_in = &logged_in;

    spconfig.api_version = SPOTIFY_API_VERSION;
    spconfig.cache_location = "tmp";
    spconfig.settings_location = "tmp";
    spconfig.application_key = g_appkey;
    spconfig.application_key_size = g_appkey_size;
    spconfig.user_agent = "Hello-World";
    spconfig.callbacks = &session_callbacks;

    pthread_mutex_init(&g_notify_mutex, NULL);
    pthread_cond_init(&g_notify_cond, NULL);

    err = sp_session_create(&spconfig, &g_session);
    assertSpotify(err, "Could not create Spotify Session.");
    debug("Session created.");

    err = sp_session_login(g_session, spotify_user, spotify_pw, 0, NULL); //Defined in Password.h
    assertSpotify(err, "Could not log in.");
    debug("Username: %s", sp_session_user_name(g_session));
    err = sp_session_set_connection_type(g_session, SP_CONNECTION_TYPE_WIRED );
    assertSpotify(err, "Could not set connection type.");
    pthread_mutex_lock(&g_notify_mutex);

    while (true) {
        if (next_timeout == 0) {
            while(!g_notify_do)
                pthread_cond_wait(&g_notify_cond, &g_notify_mutex);
        } else {
            time_t now = time(NULL);
            struct timespec ts;
            ts.tv_sec = now;
            ts.tv_sec = now / 1000000;
            ts.tv_sec += next_timeout / 1000;
            ts.tv_nsec += (next_timeout % 1000) * 1000000;
            pthread_cond_timedwait(&g_notify_cond, &g_notify_mutex, &ts);
        }

        g_notify_do = false;
        pthread_mutex_unlock(&g_notify_mutex);
        do {
            sp_session_process_events(g_session, &next_timeout);
        } while (next_timeout == 0);
        pthread_mutex_lock(&g_notify_mutex);
    }

    return 0;
}

The problem is, that sp_playlistcontainer_num_playlists returns 0, even if my account has about 10 Playlists.

My System: Windows 7 x64 with MinGW.

What am I doing wrong?


Solution

  • Looking at the source of jukebox.c it seems like you should make sure that the playlist container is fully loaded before trying to query it for playlists. So if I understand it correctly you should add a callback for container_loaded.
    I also think you should setup a callback so you will be notified when the user is logged in and when logged in you should try to get the playlist container. Something like this might help:

    static sp_playlistcontainer_callbacks pc_callbacks = {
       NULL, /* playlist_added */
       NULL, /* playlist_removed */
       NULL, /* playlist_moved */
       &container_loaded,
    };
    static sp_session_callbacks session_callbacks = {
       &logged_in,
       &notify_main_thread,
       NULL, /* music_delivery */
       NULL, /* metadata_updated */
       NULL, /* play_token_lost */
       NULL, /* log_message */
       NULL  /* end_of_track */
    };
    static void container_loaded(sp_playlistcontainer *pc, void *userdata)
    {
       // container is fully loaded now it should be safe to query the container
       int num_playlists = sp_playlistcontainer_num_playlists(pc);
    }
    static void logged_in(sp_session *sess, sp_error error)
    {
        // get playlist when user is logged in
        sp_playlistcontainer *pc = sp_session_playlistcontainer(sess);
    
        // add callbacks
        sp_playlistcontainer_add_callbacks(
        pc,
        &pc_callbacks,
        NULL);
        /* rest of code */
    }