mirror of
https://github.com/owntone/owntone-server.git
synced 2025-02-25 12:29:18 -05:00
[spotify] Use generic commands util
This commit is contained in:
parent
32944d7273
commit
dd192bd99c
513
src/spotify.c
513
src/spotify.c
@ -49,6 +49,7 @@
|
||||
#include "conffile.h"
|
||||
#include "filescanner.h"
|
||||
#include "cache.h"
|
||||
#include "commands.h"
|
||||
|
||||
|
||||
/* How long to wait for audio (in sec) before giving up */
|
||||
@ -102,30 +103,6 @@ struct artwork_get_param
|
||||
int is_loaded;
|
||||
};
|
||||
|
||||
struct spotify_command;
|
||||
|
||||
typedef int (*cmd_func)(struct spotify_command *cmd);
|
||||
|
||||
struct spotify_command
|
||||
{
|
||||
pthread_mutex_t lck;
|
||||
pthread_cond_t cond;
|
||||
|
||||
cmd_func func;
|
||||
cmd_func func_bh;
|
||||
|
||||
int nonblock;
|
||||
|
||||
union {
|
||||
void *noarg;
|
||||
sp_link *link;
|
||||
int seek_ms;
|
||||
struct audio_get_param audio;
|
||||
struct artwork_get_param artwork;
|
||||
} arg;
|
||||
|
||||
int ret;
|
||||
};
|
||||
|
||||
/* --- Globals --- */
|
||||
// Spotify thread
|
||||
@ -138,20 +115,18 @@ static pthread_cond_t login_cond;
|
||||
// Event base, pipes and events
|
||||
struct event_base *evbase_spotify;
|
||||
static int g_exit_pipe[2];
|
||||
static int g_cmd_pipe[2];
|
||||
static int g_notify_pipe[2];
|
||||
static struct event *g_exitev;
|
||||
static struct event *g_cmdev;
|
||||
static struct event *g_notifyev;
|
||||
|
||||
static struct commands_base *cmdbase;
|
||||
|
||||
// The global session handle
|
||||
static sp_session *g_sess;
|
||||
// The global library handle
|
||||
static void *g_libhandle;
|
||||
// The global state telling us what the thread is currently doing
|
||||
static enum spotify_state g_state;
|
||||
/* (not used) Tells which commmand is currently being processed */
|
||||
static struct spotify_command *g_cmd;
|
||||
// The global base playlist id (parent of all Spotify playlists in the db)
|
||||
static int g_base_plid;
|
||||
|
||||
@ -411,77 +386,6 @@ fptr_assign_all()
|
||||
|
||||
/* ---------------------------- COMMAND EXECUTION -------------------------- */
|
||||
|
||||
static void
|
||||
command_init(struct spotify_command *cmd)
|
||||
{
|
||||
memset(cmd, 0, sizeof(struct spotify_command));
|
||||
|
||||
pthread_mutex_init(&cmd->lck, NULL);
|
||||
pthread_cond_init(&cmd->cond, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
command_deinit(struct spotify_command *cmd)
|
||||
{
|
||||
pthread_cond_destroy(&cmd->cond);
|
||||
pthread_mutex_destroy(&cmd->lck);
|
||||
}
|
||||
|
||||
static int
|
||||
send_command(struct spotify_command *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!cmd->func)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "BUG: cmd->func is NULL!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = write(g_cmd_pipe[1], &cmd, sizeof(cmd));
|
||||
if (ret != sizeof(cmd))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not send command: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sync_command(struct spotify_command *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&cmd->lck);
|
||||
|
||||
ret = send_command(cmd);
|
||||
if (ret < 0)
|
||||
{
|
||||
pthread_mutex_unlock(&cmd->lck);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_cond_wait(&cmd->cond, &cmd->lck);
|
||||
pthread_mutex_unlock(&cmd->lck);
|
||||
|
||||
ret = cmd->ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nonblock_command(struct spotify_command *cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = send_command(cmd);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Thread: main and filescanner */
|
||||
static void
|
||||
thread_exit(void)
|
||||
@ -1033,47 +937,55 @@ audio_fifo_flush(void)
|
||||
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
||||
}
|
||||
|
||||
static int
|
||||
playback_setup(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
playback_setup(void *arg, int *retval)
|
||||
{
|
||||
sp_link *link;
|
||||
sp_track *track;
|
||||
sp_error err;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Setting up for playback\n");
|
||||
|
||||
link = (sp_link *) arg;
|
||||
|
||||
if (SP_CONNECTION_STATE_LOGGED_IN != fptr_sp_session_connectionstate(g_sess))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Can't play music, not connected and logged in to Spotify\n");
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
if (!cmd->arg.link)
|
||||
if (!link)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback setup failed, no Spotify link\n");
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
track = fptr_sp_link_as_track(cmd->arg.link);
|
||||
track = fptr_sp_link_as_track(link);
|
||||
if (!track)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback setup failed, invalid Spotify track\n");
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
err = fptr_sp_session_player_load(g_sess, track);
|
||||
if (SP_ERROR_OK != err)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback setup failed: %s\n", fptr_sp_error_message(err));
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
audio_fifo_flush();
|
||||
|
||||
return 0;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
playback_play(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
playback_play(void *arg, int *retval)
|
||||
{
|
||||
sp_error err;
|
||||
|
||||
@ -1083,16 +995,18 @@ playback_play(struct spotify_command *cmd)
|
||||
if (SP_ERROR_OK != err)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback failed: %s\n", fptr_sp_error_message(err));
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
g_state = SPOTIFY_STATE_PLAYING;
|
||||
|
||||
return 0;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
playback_pause(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
playback_pause(void *arg, int *retval)
|
||||
{
|
||||
sp_error err;
|
||||
|
||||
@ -1104,16 +1018,18 @@ playback_pause(struct spotify_command *cmd)
|
||||
if (SP_ERROR_OK != err)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback pause failed: %s\n", fptr_sp_error_message(err));
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
g_state = SPOTIFY_STATE_PAUSED;
|
||||
|
||||
return 0;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
playback_stop(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
playback_stop(void *arg, int *retval)
|
||||
{
|
||||
sp_error err;
|
||||
|
||||
@ -1123,35 +1039,43 @@ playback_stop(struct spotify_command *cmd)
|
||||
if (SP_ERROR_OK != err)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Playback stop failed: %s\n", fptr_sp_error_message(err));
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
g_state = SPOTIFY_STATE_STOPPED;
|
||||
|
||||
return 0;
|
||||
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
playback_seek(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
playback_seek(void *arg, int *retval)
|
||||
{
|
||||
int seek_ms;
|
||||
sp_error err;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Playback seek\n");
|
||||
|
||||
err = fptr_sp_session_player_seek(g_sess, cmd->arg.seek_ms);
|
||||
seek_ms = *((int *) arg);
|
||||
|
||||
err = fptr_sp_session_player_seek(g_sess, seek_ms);
|
||||
if (SP_ERROR_OK != err)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not seek: %s\n", fptr_sp_error_message(err));
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
audio_fifo_flush();
|
||||
|
||||
return 0;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
playback_eot(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
playback_eot(void *arg, int *retval)
|
||||
{
|
||||
sp_error err;
|
||||
|
||||
@ -1166,12 +1090,14 @@ playback_eot(struct spotify_command *cmd)
|
||||
|
||||
g_state = SPOTIFY_STATE_STOPPING;
|
||||
|
||||
return 0;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
audio_get(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
audio_get(void *arg, int *retval)
|
||||
{
|
||||
struct audio_get_param *audio;
|
||||
struct timespec ts;
|
||||
audio_fifo_data_t *afd;
|
||||
int processed;
|
||||
@ -1179,16 +1105,17 @@ audio_get(struct spotify_command *cmd)
|
||||
int ret;
|
||||
int s;
|
||||
|
||||
audio = (struct audio_get_param *) arg;
|
||||
afd = NULL;
|
||||
processed = 0;
|
||||
|
||||
// If spotify was paused begin by resuming playback
|
||||
if (g_state == SPOTIFY_STATE_PAUSED)
|
||||
playback_play(NULL);
|
||||
playback_play(NULL, retval);
|
||||
|
||||
pthread_mutex_lock(&g_audio_fifo->mutex);
|
||||
|
||||
while ((processed < cmd->arg.audio.wanted) && (g_state != SPOTIFY_STATE_STOPPED))
|
||||
while ((processed < audio->wanted) && (g_state != SPOTIFY_STATE_STOPPED))
|
||||
{
|
||||
// If track has ended and buffer is empty
|
||||
if ((g_state == SPOTIFY_STATE_STOPPING) && (g_audio_fifo->qlen <= 0))
|
||||
@ -1227,14 +1154,15 @@ audio_get(struct spotify_command *cmd)
|
||||
|
||||
s = afd->nsamples * sizeof(int16_t) * 2;
|
||||
|
||||
ret = evbuffer_add(cmd->arg.audio.evbuf, afd->samples, s);
|
||||
ret = evbuffer_add(audio->evbuf, afd->samples, s);
|
||||
free(afd);
|
||||
afd = NULL;
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for evbuffer (tried to add %d bytes)\n", s);
|
||||
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
processed += s;
|
||||
@ -1242,41 +1170,39 @@ audio_get(struct spotify_command *cmd)
|
||||
|
||||
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
||||
|
||||
return processed;
|
||||
|
||||
*retval = processed;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static void
|
||||
artwork_loaded_cb(sp_image *image, void *userdata)
|
||||
{
|
||||
struct spotify_command *cmd = userdata;
|
||||
struct artwork_get_param *artwork;
|
||||
|
||||
artwork = userdata;
|
||||
|
||||
pthread_mutex_lock(&artwork->mutex);
|
||||
|
||||
pthread_mutex_lock(&cmd->arg.artwork.mutex);
|
||||
artwork->is_loaded = 1;
|
||||
|
||||
cmd->arg.artwork.is_loaded = 1;
|
||||
|
||||
pthread_cond_signal(&cmd->arg.artwork.cond);
|
||||
pthread_mutex_unlock(&cmd->arg.artwork.mutex);
|
||||
pthread_cond_signal(&artwork->cond);
|
||||
pthread_mutex_unlock(&artwork->mutex);
|
||||
}
|
||||
|
||||
static int
|
||||
artwork_get_bh(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
artwork_get_bh(void *arg, int *retval)
|
||||
{
|
||||
struct artwork_get_param *artwork;
|
||||
sp_imageformat imageformat;
|
||||
sp_error err;
|
||||
const void *data;
|
||||
size_t data_size;
|
||||
int ret;
|
||||
|
||||
sp_image *image = cmd->arg.artwork.image;
|
||||
char *path = cmd->arg.artwork.path;
|
||||
|
||||
if (!cmd->arg.artwork.is_loaded)
|
||||
{
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Request for artwork timed out: %s\n", path);
|
||||
|
||||
fptr_sp_image_remove_load_callback(image, artwork_loaded_cb, cmd);
|
||||
goto fail;
|
||||
}
|
||||
artwork = arg;
|
||||
sp_image *image = artwork->image;
|
||||
char *path = artwork->path;
|
||||
|
||||
err = fptr_sp_image_error(image);
|
||||
if (err != SP_ERROR_OK)
|
||||
@ -1305,14 +1231,14 @@ artwork_get_bh(struct spotify_command *cmd)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = evbuffer_expand(cmd->arg.artwork.evbuf, data_size);
|
||||
ret = evbuffer_expand(artwork->evbuf, data_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for artwork\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = evbuffer_add(cmd->arg.artwork.evbuf, data, data_size);
|
||||
ret = evbuffer_add(artwork->evbuf, data, data_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not add Spotify image to event buffer\n");
|
||||
@ -1323,17 +1249,20 @@ artwork_get_bh(struct spotify_command *cmd)
|
||||
|
||||
fptr_sp_image_release(image);
|
||||
|
||||
return data_size;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
|
||||
fail:
|
||||
fptr_sp_image_release(image);
|
||||
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
static int
|
||||
artwork_get(struct spotify_command *cmd)
|
||||
static enum command_state
|
||||
artwork_get(void *arg, int *retval)
|
||||
{
|
||||
struct artwork_get_param *artwork;
|
||||
char *path;
|
||||
sp_link *link;
|
||||
sp_track *track;
|
||||
@ -1343,7 +1272,8 @@ artwork_get(struct spotify_command *cmd)
|
||||
sp_image_size image_size;
|
||||
sp_error err;
|
||||
|
||||
path = cmd->arg.artwork.path;
|
||||
artwork = arg;
|
||||
path = artwork->path;
|
||||
|
||||
// Now begins: path -> link -> track -> album -> image_id -> image -> format -> data
|
||||
link = fptr_sp_link_create_from_string(path);
|
||||
@ -1369,9 +1299,9 @@ artwork_get(struct spotify_command *cmd)
|
||||
|
||||
// Get an image at least the same size as requested
|
||||
image_size = SP_IMAGE_SIZE_SMALL; // 64x64
|
||||
if ((cmd->arg.artwork.max_w > 64) || (cmd->arg.artwork.max_h > 64))
|
||||
if ((artwork->max_w > 64) || (artwork->max_h > 64))
|
||||
image_size = SP_IMAGE_SIZE_NORMAL; // 300x300
|
||||
if ((cmd->arg.artwork.max_w > 300) || (cmd->arg.artwork.max_h > 300))
|
||||
if ((artwork->max_w > 300) || (artwork->max_h > 300))
|
||||
image_size = SP_IMAGE_SIZE_LARGE; // 640x640
|
||||
|
||||
image_id = fptr_sp_album_cover(album, image_size);
|
||||
@ -1390,31 +1320,35 @@ artwork_get(struct spotify_command *cmd)
|
||||
|
||||
fptr_sp_link_release(link);
|
||||
|
||||
cmd->arg.artwork.image = image;
|
||||
artwork->image = image;
|
||||
artwork->is_loaded = fptr_sp_image_is_loaded(image);
|
||||
|
||||
/* If the image is ready we can return it straight away, otherwise we will
|
||||
* let the calling thread wait, since the Spotify thread should not wait
|
||||
*/
|
||||
if ( (cmd->arg.artwork.is_loaded = fptr_sp_image_is_loaded(image)) )
|
||||
return artwork_get_bh(cmd);
|
||||
if (artwork->is_loaded)
|
||||
return artwork_get_bh(artwork, retval);
|
||||
|
||||
DPRINTF(E_SPAM, L_SPOTIFY, "Will wait for Spotify to call artwork_loaded_cb\n");
|
||||
|
||||
/* Async - we will return to spotify_artwork_get which will wait for callback */
|
||||
err = fptr_sp_image_add_load_callback(image, artwork_loaded_cb, cmd);
|
||||
err = fptr_sp_image_add_load_callback(image, artwork_loaded_cb, artwork);
|
||||
if (err != SP_ERROR_OK)
|
||||
{
|
||||
DPRINTF(E_WARN, L_SPOTIFY, "Adding artwork cb failed, Spotify error: %s\n", fptr_sp_error_message(err));
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
return 0;
|
||||
*retval = 0;
|
||||
return COMMAND_END;
|
||||
|
||||
level2_exit:
|
||||
fptr_sp_link_release(link);
|
||||
|
||||
level1_exit:
|
||||
return -1;
|
||||
*retval = -1;
|
||||
return COMMAND_END;
|
||||
}
|
||||
|
||||
|
||||
@ -1615,24 +1549,9 @@ static void connectionstate_updated(sp_session *session)
|
||||
*/
|
||||
static void end_of_track(sp_session *sess)
|
||||
{
|
||||
struct spotify_command *cmd;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "End of track\n");
|
||||
|
||||
cmd = (struct spotify_command *)malloc(sizeof(struct spotify_command));
|
||||
if (!cmd)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not allocate spotify_command\n");
|
||||
return;
|
||||
}
|
||||
memset(cmd, 0, sizeof(struct spotify_command));
|
||||
|
||||
cmd->nonblock = 1;
|
||||
|
||||
cmd->func = playback_eot;
|
||||
cmd->arg.noarg = NULL;
|
||||
|
||||
nonblock_command(cmd);
|
||||
commands_exec_async(cmdbase, playback_eot, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1719,41 +1638,6 @@ exit_cb(int fd, short what, void *arg)
|
||||
event_add(g_exitev, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
command_cb(int fd, short what, void *arg)
|
||||
{
|
||||
struct spotify_command *cmd;
|
||||
int ret;
|
||||
|
||||
ret = read(g_cmd_pipe[0], &cmd, sizeof(cmd));
|
||||
if (ret != sizeof(cmd))
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not read command! (read %d): %s\n", ret, (ret < 0) ? strerror(errno) : "-no error-");
|
||||
goto readd;
|
||||
}
|
||||
|
||||
if (cmd->nonblock)
|
||||
{
|
||||
cmd->func(cmd);
|
||||
|
||||
free(cmd);
|
||||
goto readd;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&cmd->lck);
|
||||
|
||||
g_cmd = cmd;
|
||||
ret = cmd->func(cmd);
|
||||
cmd->ret = ret;
|
||||
g_cmd = NULL;
|
||||
|
||||
pthread_cond_signal(&cmd->cond);
|
||||
pthread_mutex_unlock(&cmd->lck);
|
||||
|
||||
readd:
|
||||
event_add(g_cmdev, NULL);
|
||||
}
|
||||
|
||||
/* Process events when timeout expires or triggered by libspotify's notify_main_thread */
|
||||
static void
|
||||
notify_cb(int fd, short what, void *arg)
|
||||
@ -1789,9 +1673,7 @@ notify_cb(int fd, short what, void *arg)
|
||||
int
|
||||
spotify_playback_setup(struct media_file_info *mfi)
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
sp_link *link;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Playback setup request\n");
|
||||
|
||||
@ -1802,144 +1684,59 @@ spotify_playback_setup(struct media_file_info *mfi)
|
||||
return -1;
|
||||
}
|
||||
|
||||
command_init(&cmd);
|
||||
|
||||
cmd.func = playback_setup;
|
||||
cmd.arg.link = link;
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
|
||||
command_deinit(&cmd);
|
||||
|
||||
return ret;
|
||||
return commands_exec_sync(cmdbase, playback_setup, NULL, link);
|
||||
}
|
||||
|
||||
int
|
||||
spotify_playback_play()
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Playback request\n");
|
||||
|
||||
command_init(&cmd);
|
||||
|
||||
cmd.func = playback_play;
|
||||
cmd.arg.noarg = NULL;
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
|
||||
command_deinit(&cmd);
|
||||
|
||||
return ret;
|
||||
return commands_exec_sync(cmdbase, playback_play, NULL, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
spotify_playback_pause()
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Pause request\n");
|
||||
|
||||
command_init(&cmd);
|
||||
|
||||
cmd.func = playback_pause;
|
||||
cmd.arg.noarg = NULL;
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
|
||||
command_deinit(&cmd);
|
||||
|
||||
return ret;
|
||||
return commands_exec_sync(cmdbase, playback_pause, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Thread: libspotify */
|
||||
void
|
||||
spotify_playback_pause_nonblock(void)
|
||||
{
|
||||
struct spotify_command *cmd;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Nonblock pause request\n");
|
||||
|
||||
cmd = (struct spotify_command *)malloc(sizeof(struct spotify_command));
|
||||
if (!cmd)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not allocate spotify_command\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(struct spotify_command));
|
||||
|
||||
cmd->nonblock = 1;
|
||||
|
||||
cmd->func = playback_pause;
|
||||
cmd->arg.noarg = NULL;
|
||||
|
||||
nonblock_command(cmd);
|
||||
commands_exec_async(cmdbase, playback_pause, NULL);
|
||||
}
|
||||
|
||||
/* Thread: player and libspotify */
|
||||
int
|
||||
spotify_playback_stop(void)
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
int ret;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Stop request\n");
|
||||
|
||||
command_init(&cmd);
|
||||
|
||||
cmd.func = playback_stop;
|
||||
cmd.arg.noarg = NULL;
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
|
||||
command_deinit(&cmd);
|
||||
|
||||
return ret;
|
||||
return commands_exec_sync(cmdbase, playback_stop, NULL, NULL);
|
||||
}
|
||||
|
||||
/* Thread: player and libspotify */
|
||||
void
|
||||
spotify_playback_stop_nonblock(void)
|
||||
{
|
||||
struct spotify_command *cmd;
|
||||
|
||||
DPRINTF(E_DBG, L_SPOTIFY, "Nonblock stop request\n");
|
||||
|
||||
cmd = (struct spotify_command *)malloc(sizeof(struct spotify_command));
|
||||
if (!cmd)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not allocate spotify_command\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(cmd, 0, sizeof(struct spotify_command));
|
||||
|
||||
cmd->nonblock = 1;
|
||||
|
||||
cmd->func = playback_stop;
|
||||
cmd->arg.noarg = NULL;
|
||||
|
||||
nonblock_command(cmd);
|
||||
commands_exec_async(cmdbase, playback_stop, NULL);
|
||||
}
|
||||
|
||||
/* Thread: player */
|
||||
int
|
||||
spotify_playback_seek(int ms)
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
int ret;
|
||||
|
||||
command_init(&cmd);
|
||||
|
||||
cmd.func = playback_seek;
|
||||
cmd.arg.seek_ms = ms;
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
|
||||
command_deinit(&cmd);
|
||||
ret = commands_exec_sync(cmdbase, playback_seek, NULL, &ms);
|
||||
|
||||
if (ret == 0)
|
||||
return ms;
|
||||
@ -1951,58 +1748,44 @@ spotify_playback_seek(int ms)
|
||||
int
|
||||
spotify_audio_get(struct evbuffer *evbuf, int wanted)
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
int ret;
|
||||
struct audio_get_param audio;
|
||||
|
||||
command_init(&cmd);
|
||||
audio.evbuf = evbuf;
|
||||
audio.wanted = wanted;
|
||||
|
||||
cmd.func = audio_get;
|
||||
cmd.arg.audio.evbuf = evbuf;
|
||||
cmd.arg.audio.wanted = wanted;
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
|
||||
command_deinit(&cmd);
|
||||
|
||||
return ret;
|
||||
return commands_exec_sync(cmdbase, audio_get, NULL, &audio);
|
||||
}
|
||||
|
||||
/* Thread: httpd (artwork) and worker */
|
||||
int
|
||||
spotify_artwork_get(struct evbuffer *evbuf, char *path, int max_w, int max_h)
|
||||
{
|
||||
struct spotify_command cmd;
|
||||
struct artwork_get_param artwork;
|
||||
struct timespec ts;
|
||||
int ret;
|
||||
|
||||
command_init(&cmd);
|
||||
artwork.evbuf = evbuf;
|
||||
artwork.path = path;
|
||||
artwork.max_w = max_w;
|
||||
artwork.max_h = max_h;
|
||||
|
||||
cmd.func = artwork_get;
|
||||
cmd.arg.artwork.evbuf = evbuf;
|
||||
cmd.arg.artwork.path = path;
|
||||
cmd.arg.artwork.max_w = max_w;
|
||||
cmd.arg.artwork.max_h = max_h;
|
||||
|
||||
pthread_mutex_init(&cmd.arg.artwork.mutex, NULL);
|
||||
pthread_cond_init(&cmd.arg.artwork.cond, NULL);
|
||||
|
||||
ret = sync_command(&cmd);
|
||||
pthread_mutex_init(&artwork.mutex, NULL);
|
||||
pthread_cond_init(&artwork.cond, NULL);
|
||||
|
||||
ret = commands_exec_sync(cmdbase, artwork_get, NULL, &artwork);
|
||||
|
||||
// Artwork was not ready, wait for callback from libspotify
|
||||
if (ret == 0)
|
||||
{
|
||||
pthread_mutex_lock(&cmd.arg.artwork.mutex);
|
||||
pthread_mutex_lock(&artwork.mutex);
|
||||
mk_reltime(&ts, SPOTIFY_ARTWORK_TIMEOUT);
|
||||
if (!cmd.arg.artwork.is_loaded)
|
||||
pthread_cond_timedwait(&cmd.arg.artwork.cond, &cmd.arg.artwork.mutex, &ts);
|
||||
pthread_mutex_unlock(&cmd.arg.artwork.mutex);
|
||||
if (!artwork.is_loaded)
|
||||
pthread_cond_timedwait(&artwork.cond, &artwork.mutex, &ts);
|
||||
pthread_mutex_unlock(&artwork.mutex);
|
||||
|
||||
cmd.func = artwork_get_bh;
|
||||
ret = sync_command(&cmd);
|
||||
ret = commands_exec_sync(cmdbase, artwork_get_bh, NULL, &artwork);
|
||||
}
|
||||
|
||||
command_deinit(&cmd);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2204,17 +1987,6 @@ spotify_init(void)
|
||||
goto exit_fail;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
ret = pipe2(g_cmd_pipe, O_CLOEXEC);
|
||||
#else
|
||||
ret = pipe(g_cmd_pipe);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not create command pipe: %s\n", strerror(errno));
|
||||
goto cmd_fail;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
ret = pipe2(g_notify_pipe, O_CLOEXEC);
|
||||
#else
|
||||
@ -2240,13 +2012,6 @@ spotify_init(void)
|
||||
goto evnew_fail;
|
||||
}
|
||||
|
||||
g_cmdev = event_new(evbase_spotify, g_cmd_pipe[0], EV_READ, command_cb, NULL);
|
||||
if (!g_cmdev)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not create cmd event\n");
|
||||
goto evnew_fail;
|
||||
}
|
||||
|
||||
g_notifyev = event_new(evbase_spotify, g_notify_pipe[0], EV_READ | EV_TIMEOUT, notify_cb, NULL);
|
||||
if (!g_notifyev)
|
||||
{
|
||||
@ -2255,9 +2020,16 @@ spotify_init(void)
|
||||
}
|
||||
|
||||
event_add(g_exitev, NULL);
|
||||
event_add(g_cmdev, NULL);
|
||||
event_add(g_notifyev, NULL);
|
||||
|
||||
|
||||
cmdbase = commands_base_new(evbase_spotify);
|
||||
if (!cmdbase)
|
||||
{
|
||||
DPRINTF(E_LOG, L_SPOTIFY, "Could not create command base\n");
|
||||
goto cmd_fail;
|
||||
}
|
||||
|
||||
DPRINTF(E_INFO, L_SPOTIFY, "Spotify session init\n");
|
||||
|
||||
spotify_cfg = cfg_getsec(cfg, "spotify");
|
||||
@ -2333,7 +2105,9 @@ spotify_init(void)
|
||||
g_sess = NULL;
|
||||
|
||||
session_fail:
|
||||
cmd_fail:
|
||||
evnew_fail:
|
||||
commands_base_free(cmdbase);
|
||||
event_base_free(evbase_spotify);
|
||||
evbase_spotify = NULL;
|
||||
|
||||
@ -2342,10 +2116,6 @@ spotify_init(void)
|
||||
close(g_notify_pipe[1]);
|
||||
|
||||
notify_fail:
|
||||
close(g_cmd_pipe[0]);
|
||||
close(g_cmd_pipe[1]);
|
||||
|
||||
cmd_fail:
|
||||
close(g_exit_pipe[0]);
|
||||
close(g_exit_pipe[1]);
|
||||
|
||||
@ -2384,12 +2154,11 @@ spotify_deinit(void)
|
||||
|
||||
/* Free event base (should free events too) */
|
||||
event_base_free(evbase_spotify);
|
||||
commands_base_free(cmdbase);
|
||||
|
||||
/* Close pipes */
|
||||
close(g_notify_pipe[0]);
|
||||
close(g_notify_pipe[1]);
|
||||
close(g_cmd_pipe[0]);
|
||||
close(g_cmd_pipe[1]);
|
||||
close(g_exit_pipe[0]);
|
||||
close(g_exit_pipe[1]);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user