/* * free a playlist's members but not the list itself */ void hgd_free_playlist(struct hgd_playlist *list) { unsigned int i; for (i = 0; i < list->n_items; i ++) { hgd_free_playlist_item(list->items[i]); free(list->items[i]); } free(list->items); }
/* * respond to client what is currently playing. * * response: * ok|0 nothing playing * ok|1|id|filename|user track is playing * err|... failure */ int hgd_cmd_now_playing(struct hgd_session *sess, char **args) { struct hgd_playlist_item playing; char *reply; int num_votes; (void) args; /* silence compiler */ memset(&playing, 0, sizeof(playing)); if (hgd_get_playing_item(&playing) == HGD_FAIL) { hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|internal"); hgd_free_playlist_item(&playing); return (HGD_FAIL); } if (playing.filename == NULL) { hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok|0"); } else { num_votes = hgd_get_num_votes(); xasprintf(&reply, "ok|1|%d|%s|%s|%s|%s|" "%s|%s|%d|%d|%d|%d|%d|%d", /* added in 0.5 */ playing.id, playing.filename + strlen(HGD_UNIQ_FILE_PFX), playing.tags.artist, playing.tags.title, playing.user, playing.tags.album, playing.tags.genre, playing.tags.duration, playing.tags.bitrate, playing.tags.samplerate, playing.tags.channels, playing.tags.year, (req_votes - num_votes)); hgd_sock_send_line(sess->sock_fd, sess->ssl, reply); free(reply); } hgd_free_playlist_item(&playing); return (HGD_OK); }
int hgd_play_loop(void) { int ret = HGD_OK; struct hgd_playlist_item track; /* forever play songs */ DPRINTF(HGD_D_INFO, "Starting play loop"); while ((!dying) && (!restarting)) { memset(&track, 0, sizeof(track)); if (hgd_get_next_track(&track) == HGD_FAIL) { ret = HGD_FAIL; break; } if (track.filename != NULL) { DPRINTF(HGD_D_DEBUG, "next track is: '%s'", track.filename); hgd_clear_votes(); if (hgd_play_track(&track, purge_finished_fs, purge_finished_db) != HGD_OK) { ret = HGD_FAIL; break; } hgd_clear_votes(); } else { DPRINTF(HGD_D_DEBUG, "no tracks to play"); #ifdef HAVE_PYTHON hgd_execute_py_hook("nothing_to_play"); #endif sleep(1); } hgd_free_playlist_item(&track); } return (ret); }
int hgd_cmd_vote_off(struct hgd_session *sess, char **args) { struct hgd_playlist_item playing; char *pid_path, pid_str[HGD_PID_STR_SZ]; char *scmd, id_str[HGD_ID_STR_SZ], *read; pid_t pid; FILE *pid_file; int tid = -1, scmd_ret; struct flock fl; fl.l_type = F_RDLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */ fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */ fl.l_start = 0; /* Offset from l_whence */ fl.l_len = 0; /* length, 0 = to EOF */ fl.l_pid = getpid(); /* our PID */ DPRINTF(HGD_D_INFO, "%s wants to kill track", sess->user->name); memset(&playing, 0, sizeof(playing)); if (hgd_get_playing_item(&playing) == HGD_FAIL) { hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|internal"); return (HGD_FAIL); } /* is *anything* playing? */ if (playing.filename == NULL) { DPRINTF(HGD_D_INFO, "No track is playing, can't vote off"); hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|not_playing"); return (HGD_FAIL); } /* is the file they are voting off playing? */ if (args != NULL) { /* null if call from hgd_cmd_vote_off_noargs */ tid = atoi(args[0]); if (playing.id != tid) { DPRINTF(HGD_D_INFO, "Track to voteoff isn't playing"); hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|wrong_track"); hgd_free_playlist_item(&playing); return (HGD_FAIL); } } hgd_free_playlist_item(&playing); /* insert vote */ switch (hgd_insert_vote(sess->user->name)) { case HGD_OK: break; /* good */ case 1: /* duplicate vote */ DPRINTF(HGD_D_INFO, "User '%s' already voted", sess->user->name); hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|duplicate_vote"); return (HGD_OK); break; case HGD_FAIL: default: hgd_sock_send_line(sess->sock_fd, sess->ssl, "err|sql"); return (HGD_FAIL); }; /* play a sound on skipping? */ if (vote_sound != NULL) { DPRINTF(HGD_D_DEBUG, "Play voteoff sound: '%s'", vote_sound); xasprintf(&scmd, "mplayer -really-quiet %s", vote_sound); scmd_ret = system(scmd); /* unreachable as mplayer doesn't return non-zero :\ */ if (scmd_ret != 0) { DPRINTF(HGD_D_WARN, "Vote-off noise failed to play (ret %d): %s", scmd_ret, vote_sound); } free(scmd); } /* are we at the vote limit yet? */ if (hgd_get_num_votes() < req_votes) { hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok"); return (HGD_OK); } DPRINTF(HGD_D_INFO, "Vote limit exceeded - kill track"); /* kill mplayer then */ /* XXX some of this needs to go in mplayer.c */ xasprintf(&pid_path, "%s/%s", state_path, HGD_MPLAYER_PID_NAME); pid_file = fopen(pid_path, "r"); if (pid_file == NULL) { DPRINTF(HGD_D_WARN, "Can't find mplayer pid file: %s: %s", pid_path, SERROR); free(pid_path); return (HGD_FAIL); } if (fcntl(fileno(pid_file), F_SETLKW, &fl) == -1) { DPRINTF(HGD_D_ERROR, "failed to get lock on pid file"); fclose(pid_file); return (HGD_FAIL); } free(pid_path); /* Read the pid from the pidfile */ read = fgets(pid_str, HGD_PID_STR_SZ, pid_file); if (read == NULL) { if (!feof(pid_file)) { DPRINTF(HGD_D_WARN, "Can't find pid in pid file"); fclose(pid_file); return (HGD_FAIL); } } /* Read the track id from the pid file */ read = fgets(id_str, HGD_ID_STR_SZ, pid_file); if (read == NULL) { if (!feof(pid_file)) { DPRINTF(HGD_D_WARN, "Can't find pid in pid file"); fclose(pid_file); return (HGD_FAIL); } } fl.l_type = F_UNLCK; fcntl(fileno(pid_file), F_SETLK, &fl); /* F_GETLK, F_SETLK, F_SETLKW */ fclose(pid_file); if (atoi(id_str) == playing.id) { pid = atoi(pid_str); DPRINTF(HGD_D_DEBUG, "Killing mplayer"); if (kill(pid, SIGINT) < 0) DPRINTF(HGD_D_WARN, "Can't kill mplayer: %s", SERROR); /* Note: player daemon will empty the votes table */ hgd_sock_send_line(sess->sock_fd, sess->ssl, "ok"); return (HGD_OK); } else { DPRINTF(HGD_D_WARN, "Hmm that was racey! wanted to kill %d but %s was playing", playing.id, id_str); return(HGD_FAIL); } }