// ---------------------------------------------------------------------------- // void TextUI::run() { m_running = true; m_text_io.printf( "\n\nSpotify API Test Bench - type ? for command list\n\n" ); m_player->connect(); // Try to connect using stored credentials while ( m_running ) { // See if we need to login if ( !m_player->isLoggedIn() && !spotify_login( ) ) break; CString label; PlayingInfo playing_info; if ( m_player->getPlayingTrack( &playing_info ) ) { label.Format( "Now %s: %s", "Playing", m_player->getTrackFullName( playing_info.track_link ) ); label.AppendFormat( " | length %s remaining %s", track_time(playing_info.track_length), track_time(playing_info.time_remaining) ); if ( m_player->isTrackPaused() ) label.Append( " | PAUSED" ); m_text_io.printf( "\n%s\n", (LPCSTR)label ); } m_text_io.clear(); m_text_io.printf( "> ", (LPCSTR)label ); CString cmd; int retcode = m_text_io.getString( cmd ); m_text_io.printf( "\n" ); if ( !m_player->isLoggedIn() ) continue; if ( retcode != INPUT_SUCCESS ) continue; m_text_io.tokenize( cmd ); if ( !m_text_io.nextToken( cmd ) ) continue; cmd.MakeLower(); HandlerMap::iterator it = function_map.find( cmd ); if ( it == function_map.end() ) { m_text_io.printf( "Unrecognized command '%s' - Type ? for list of commands\n", (LPCTSTR)cmd ); } else if ( !m_running && (*it).second.m_running ) { m_text_io.printf( "UI must be running to use '%s'\n", (LPCTSTR)cmd ); } else { (this->*(*it).second.m_funcptr)(); } } }
static void gst_spot_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstSpotSrc *spot; g_return_if_fail (GST_IS_SPOT_SRC (object)); spot = GST_SPOT_SRC (object); switch (prop_id) { case ARG_USER: g_free (GST_SPOT_SRC_USER (spot)); GST_SPOT_SRC_USER (spot) = g_value_dup_string (value); /* will work for everyone excepct Sverker Olofsson */ if (g_strcmp0 (GST_SPOT_SRC_PASS (spot), DEFAULT_PASS)) { /* FIXME: Handle error */ spotify_login (spot); } break; case ARG_PASS: g_free (GST_SPOT_SRC_PASS (spot)); GST_SPOT_SRC_PASS (spot) = g_value_dup_string (value); /* will work for everyone excepct Sverker Olofsson */ if (g_strcmp0 (GST_SPOT_SRC_USER (spot), DEFAULT_USER)) { /* FIXME: Handle error */ spotify_login (spot); } break; case ARG_URI: //FIXME: how do handle error from this func? gst_spot_src_set_spotifyuri (spot, g_value_get_string (value)); break; case ARG_BUFFER_TIME: GST_SPOT_SRC_BUFFER_TIME (spot) = (g_value_get_uint64 (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
int main(int argc, char *argv[]) { spotify_t *spotify; int error; int ret; if (argc <= 2) { fprintf(stderr, "Usage: %s <username> <password>\n", argv[0]); return -1; } #if defined(EVTHREAD_USE_PTHREADS_IMPLEMENTED) if (evthread_use_pthreads()) { return -2; } #elif defined(EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED) if (evthread_use_windows_threads()) { return -3; } #else # error "The libevent threading support not available" #endif spotify = spotify_init(&error); if (!spotify) { fprintf(stderr, "Spotify failed to initialize\n"); return -4; } spotify_login(spotify, argv[1], argv[2]); ret = spotify_run(spotify); if (ret) { fprintf(stderr, "Event loop returned %d\n", ret); } spotify_logout(spotify); spotify_destroy(spotify); return 0; }
/* Thread: scan */ static void process_file(char *file, time_t mtime, off_t size, int type, int flags) { switch (file_type_get(file)) { case FILE_REGULAR: filescanner_process_media(file, mtime, size, type, NULL); counter++; /* When in bulk mode, split transaction in pieces of 200 */ if ((flags & F_SCAN_BULK) && (counter % 200 == 0)) { DPRINTF(E_LOG, L_SCAN, "Scanned %d files...\n", counter); db_transaction_end(); db_transaction_begin(); } break; case FILE_PLAYLIST: case FILE_ITUNES: if (flags & F_SCAN_BULK) defer_playlist(file, mtime); else process_playlist(file, mtime); break; case FILE_CTRL_REMOTE: remote_pairing_read_pin(file); break; #ifdef LASTFM case FILE_CTRL_LASTFM: lastfm_login(file); break; #endif #ifdef HAVE_SPOTIFY_H case FILE_CTRL_SPOTIFY: spotify_login(file); break; #endif case FILE_CTRL_INITSCAN: if (flags & F_SCAN_BULK) break; DPRINTF(E_LOG, L_SCAN, "Startup rescan triggered, found init-rescan file: %s\n", file); inofd_event_unset(); // Clears all inotify watches db_watch_clear(); inofd_event_set(); bulk_scan(F_SCAN_BULK | F_SCAN_RESCAN); break; case FILE_CTRL_FULLSCAN: if (flags & F_SCAN_BULK) break; DPRINTF(E_LOG, L_SCAN, "Full rescan triggered, found full-rescan file: %s\n", file); player_playback_stop(); player_queue_clear(); inofd_event_unset(); // Clears all inotify watches db_purge_all(); // Clears files, playlists, playlistitems, inotify and groups inofd_event_set(); bulk_scan(F_SCAN_BULK); break; default: DPRINTF(E_WARN, L_SCAN, "Ignoring file: %s\n", file); } }
/* Thread: scan */ static void * filescanner(void *arg) { int ret; #if defined(__linux__) struct sched_param param; /* Lower the priority of the thread so forked-daapd may still respond * during file scan on low power devices. Param must be 0 for the SCHED_BATCH * policy. */ memset(¶m, 0, sizeof(struct sched_param)); ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m); if (ret != 0) { DPRINTF(E_LOG, L_SCAN, "Warning: Could not set thread priority to SCHED_BATCH\n"); } #endif ret = db_perthread_init(); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error: DB init failed\n"); pthread_exit(NULL); } ret = db_watch_clear(); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error: could not clear old watches from DB\n"); pthread_exit(NULL); } ret = db_groups_clear(); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error: could not clear old groups from DB\n"); pthread_exit(NULL); } /* Recompute all songartistids and songalbumids, in case the SQLite DB got transferred * to a different host; the hash is not portable. * It will also rebuild the groups we just cleared. */ db_files_update_songartistid(); db_files_update_songalbumid(); if (cfg_getbool(cfg_getsec(cfg, "library"), "filescan_disable")) bulk_scan(F_SCAN_BULK | F_SCAN_FAST); else bulk_scan(F_SCAN_BULK); if (!scan_exit) { #ifdef HAVE_SPOTIFY_H spotify_login(NULL); #endif /* Enable inotify */ event_add(&inoev, NULL); event_base_dispatch(evbase_scan); } if (!scan_exit) DPRINTF(E_FATAL, L_SCAN, "Scan event loop terminated ahead of time!\n"); db_perthread_deinit(); pthread_exit(NULL); }
/* Thread: scan */ static void process_file(char *file, time_t mtime, off_t size, int type, int flags, int dir_id) { int is_bulkscan; int ret; is_bulkscan = (flags & F_SCAN_BULK); switch (file_type_get(file)) { case FILE_REGULAR: filescanner_process_media(file, mtime, size, type, NULL, dir_id); cache_artwork_ping(file, mtime, !is_bulkscan); // TODO [artworkcache] If entry in artwork cache exists for no artwork available, delete the entry if media file has embedded artwork counter++; /* When in bulk mode, split transaction in pieces of 200 */ if ((flags & F_SCAN_BULK) && (counter % 200 == 0)) { DPRINTF(E_LOG, L_SCAN, "Scanned %d files...\n", counter); db_transaction_end(); db_transaction_begin(); } break; case FILE_PLAYLIST: case FILE_ITUNES: if (flags & F_SCAN_BULK) defer_playlist(file, mtime, dir_id); else process_playlist(file, mtime, dir_id); break; case FILE_SMARTPL: DPRINTF(E_DBG, L_SCAN, "Smart playlist file: %s\n", file); scan_smartpl(file, mtime, dir_id); break; case FILE_ARTWORK: DPRINTF(E_DBG, L_SCAN, "Artwork file: %s\n", file); cache_artwork_ping(file, mtime, !is_bulkscan); // TODO [artworkcache] If entry in artwork cache exists for no artwork available for a album with files in the same directory, delete the entry break; case FILE_CTRL_REMOTE: remote_pairing_read_pin(file); break; case FILE_CTRL_LASTFM: #ifdef LASTFM lastfm_login(file); #else DPRINTF(E_LOG, L_SCAN, "Detected LastFM file, but this version was built without LastFM support\n"); #endif break; case FILE_CTRL_SPOTIFY: #ifdef HAVE_SPOTIFY_H spotify_login(file); #else DPRINTF(E_LOG, L_SCAN, "Detected Spotify file, but this version was built without Spotify support\n"); #endif break; case FILE_CTRL_INITSCAN: if (flags & F_SCAN_BULK) break; DPRINTF(E_LOG, L_SCAN, "Startup rescan triggered, found init-rescan file: %s\n", file); filescanner_initscan(NULL, &ret); break; case FILE_CTRL_FULLSCAN: if (flags & F_SCAN_BULK) break; DPRINTF(E_LOG, L_SCAN, "Full rescan triggered, found full-rescan file: %s\n", file); filescanner_fullrescan(NULL, &ret); break; default: DPRINTF(E_WARN, L_SCAN, "Ignoring file: %s\n", file); } }
/* only used to trigger sp_session_process_events when needed, * looks like about once a second */ static void* spotify_thread_func (void *data) { int timeout = -1; GTimeVal t; GstSpotSrc *spot = (GstSpotSrc *) data; if (!spotify_create_session (spot)) { GST_ERROR_OBJECT (spot, "Create_session error"); return FALSE; } while (spot->keep_spotify_thread) { sp_session_process_events (GST_SPOT_SRC_SPOTIFY_SESSION (spot), &timeout); g_get_current_time (&t); g_time_val_add (&t, timeout * 1000); g_cond_timed_wait (spot->process_events_cond, spot->process_events_mutex, &t); spot->spotify_thread_initiated = TRUE; while (spot->spot_works) { struct spot_work *spot_work; sp_error ret = SP_ERROR_INVALID_INDATA; spot_work = (struct spot_work *)spot->spot_works->data; g_mutex_lock (spot_work->spot_mutex); switch (spot_work->cmd) { case SPOT_CMD_START: GST_DEBUG_OBJECT (spot, "Uri = %s", GST_SPOT_SRC_URI_LOCATION (spot)); if (!spotify_login (spot)) { /* error message from within function */ break; } sp_link *link = sp_link_create_from_string (GST_SPOT_SRC_URI_LOCATION (spot)); if (!link) { GST_ERROR_OBJECT (spot, "Incorrect track ID:%s", GST_SPOT_SRC_URI_LOCATION (spot)); break; } GST_SPOT_SRC_CURRENT_TRACK (spot) = sp_link_as_track (link); if (!GST_SPOT_SRC_CURRENT_TRACK (spot)) { GST_ERROR_OBJECT (spot, "Could get track from uri=%s", GST_SPOT_SRC_URI_LOCATION (spot)); break; } #if 0 /* FIXME: why does not this work? */ if (!sp_track_is_available (GST_SPOT_SRC_CURRENT_TRACK (spot))) { /* this probably happens for tracks avaiable in other countries or something */ GST_ERROR_OBJECT (spot, "Track is not available, uri=%s", GST_SPOT_SRC_URI_LOCATION (spot)); break; } #endif sp_track_add_ref (GST_SPOT_SRC_CURRENT_TRACK (spot)); sp_link_add_ref (link); sp_session_process_events (GST_SPOT_SRC_SPOTIFY_SESSION (spot), &timeout); while (sp_track_is_loaded (GST_SPOT_SRC_CURRENT_TRACK (spot)) == 0) { sp_session_process_events (GST_SPOT_SRC_SPOTIFY_SESSION (spot), &timeout); usleep (10000); } GST_DEBUG_OBJECT (spot, "Now playing \"%s\"", sp_track_name (GST_SPOT_SRC_CURRENT_TRACK (spot))); ret = sp_session_player_load (GST_SPOT_SRC_SPOTIFY_SESSION (spot), GST_SPOT_SRC_CURRENT_TRACK (spot)); if (ret != SP_ERROR_OK) { GST_ERROR_OBJECT (spot, "Failed to load track '%s' uri=%s", sp_track_name (GST_SPOT_SRC_CURRENT_TRACK (spot)), (GST_SPOT_SRC_URI_LOCATION (spot))); break; } sp_session_process_events (GST_SPOT_SRC_SPOTIFY_SESSION (spot), &timeout); ret = sp_session_player_play (GST_SPOT_SRC_SPOTIFY_SESSION (spot), TRUE); if (ret != SP_ERROR_OK) { GST_ERROR_OBJECT (spot, "Failed to play track '%s' uri=%s", sp_track_name (GST_SPOT_SRC_CURRENT_TRACK (spot)), (GST_SPOT_SRC_URI_LOCATION (spot))); break; } break; case SPOT_CMD_PROCESS: sp_session_process_events (GST_SPOT_SRC_SPOTIFY_SESSION (spot), &timeout); break; case SPOT_CMD_PLAY: ret = sp_session_player_play (GST_SPOT_SRC_SPOTIFY_SESSION (spot), TRUE); break; case SPOT_CMD_DURATION: if (GST_SPOT_SRC_CURRENT_TRACK (spot)) { ret = sp_track_duration (GST_SPOT_SRC_CURRENT_TRACK (spot)); } break; case SPOT_CMD_STOP: if (GST_SPOT_SRC_CURRENT_TRACK (spot)) { ret = sp_session_player_play (GST_SPOT_SRC_SPOTIFY_SESSION (spot), FALSE); if (ret != SP_ERROR_OK) { break; } ret = SP_ERROR_OK; sp_session_player_unload (GST_SPOT_SRC_SPOTIFY_SESSION (spot)); } break; case SPOT_CMD_SEEK: if (GST_SPOT_SRC_CURRENT_TRACK (spot)) { ret = sp_session_player_seek (GST_SPOT_SRC_SPOTIFY_SESSION (spot), spot_work->opt); } break; default: g_assert_not_reached (); break; } /* print all errors caught and propagate to calling thread */ if (ret != SP_ERROR_OK) { GST_ERROR_OBJECT (spot, "Failed with SPOT_CMD=%d, ret=%d, error=%s", spot_work->cmd, ret, sp_error_message (ret)); } spot_work->ret = ret; spot->spot_works = g_list_remove (spot->spot_works, spot->spot_works->data); g_mutex_unlock (spot_work->spot_mutex); g_cond_broadcast (spot_work->spot_cond); } } return NULL; }
/* Thread: scan */ static void * filescanner(void *arg) { int clear_queue_on_stop_disabled; int ret; #ifdef __linux__ struct sched_param param; /* Lower the priority of the thread so forked-daapd may still respond * during file scan on low power devices. Param must be 0 for the SCHED_BATCH * policy. */ memset(¶m, 0, sizeof(struct sched_param)); ret = pthread_setschedparam(pthread_self(), SCHED_BATCH, ¶m); if (ret != 0) { DPRINTF(E_LOG, L_SCAN, "Warning: Could not set thread priority to SCHED_BATCH\n"); } #endif ret = db_perthread_init(); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error: DB init failed\n"); pthread_exit(NULL); } ret = db_watch_clear(); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error: could not clear old watches from DB\n"); pthread_exit(NULL); } // Only clear the queue if enabled (default) in config clear_queue_on_stop_disabled = cfg_getbool(cfg_getsec(cfg, "mpd"), "clear_queue_on_stop_disable"); if (!clear_queue_on_stop_disabled) { ret = db_queue_clear(); if (ret < 0) { DPRINTF(E_LOG, L_SCAN, "Error: could not clear queue from DB\n"); pthread_exit(NULL); } } if (cfg_getbool(cfg_getsec(cfg, "library"), "filescan_disable")) bulk_scan(F_SCAN_BULK | F_SCAN_FAST); else bulk_scan(F_SCAN_BULK); if (!scan_exit) { #ifdef HAVE_SPOTIFY_H spotify_login(NULL); #endif /* Enable inotify */ event_add(inoev, NULL); event_base_dispatch(evbase_scan); } if (!scan_exit) DPRINTF(E_FATAL, L_SCAN, "Scan event loop terminated ahead of time!\n"); db_perthread_deinit(); pthread_exit(NULL); }