player.c (3669B)
1#include "player.h" 2 3#include "list.h" 4#include "data.h" 5 6#include <stdlib.h> 7 8static bool player_history_contains(struct track *cmp, int depth); 9static struct track *playlist_track_next_unused(struct list_link *start); 10static struct track *player_next_from_playlist(void); 11 12bool 13player_history_contains(struct track *cmp, int depth) 14{ 15 struct list_link *link; 16 struct track *track; 17 18 link = list_back(&player.history); 19 while (LIST_INNER(link) && depth-- > 0) { 20 track = LIST_UPCAST(link, struct track, link_hs); 21 if (track == cmp) 22 return true; 23 link = link->prev; 24 } 25 26 return false; 27} 28 29struct track * 30playlist_track_next_unused(struct list_link *start) 31{ 32 struct track *track; 33 struct list_link *link; 34 bool in_history; 35 int len; 36 37 track = NULL; 38 39 len = list_len(&player.playlist); 40 if (!len) return NULL; 41 42 link = start; 43 while (LIST_INNER(link)) { 44 track = LIST_UPCAST(link, struct track, link_pl); 45 46 in_history = player_history_contains(track, len - 2); 47 if (track != player.track && !in_history) 48 break; 49 50 link = link->next; 51 if (!LIST_INNER(link)) 52 link = list_front(&player.playlist); 53 54 if (link == start) 55 return NULL; 56 } 57 58 return track; 59} 60 61struct track * 62player_next_from_playlist(void) 63{ 64 struct list_link *link; 65 int index; 66 67 if (list_empty(&player.playlist)) 68 return NULL; 69 70 if (player.shuffle) { 71 index = rand() % list_len(&player.playlist); 72 link = list_at(&player.playlist, index); 73 return playlist_track_next_unused(link); 74 } else { 75 if (player.track && list_link_inuse(&player.track->link_pl)) { 76 index = list_index(&player.playlist, 77 &player.track->link_pl); 78 ASSERT(index >= 0); 79 if (++index == list_len(&player.playlist)) 80 return NULL; 81 } else { 82 index = 0; 83 } 84 link = list_at(&player.playlist, index); 85 return LIST_UPCAST(link, struct track, link_pl); 86 } 87 88 return NULL; 89} 90 91/* implemented by backend: 92 * 93 * void player_init(void); 94 * void player_deinit(void); 95 * 96 * void player_update(void); 97 * 98 * int player_play_track(struct track *track, bool new); 99 * int player_clear_track(void); 100 */ 101 102void 103player_add_history(struct track *new) 104{ 105 if (!list_link_inuse(&new->link_hs)) { 106 list_link_pop(&new->link_hs); 107 list_insert_back(&player.history, &new->link_hs); 108 } 109} 110 111/* implemented by backend: 112 * 113 * int player_toggle_pause(void); 114 * int player_pause(void); 115 * int player_resume(void); 116 */ 117 118int 119player_prev(void) 120{ 121 struct list_link *next; 122 struct track *track; 123 124 if (list_empty(&player.history)) 125 return PLAYER_ERR; 126 127 if (!player.track || !list_link_inuse(&player.track->link_hs)) { 128 next = list_back(&player.history); 129 } else if (LIST_INNER(player.track->link_hs.prev)) { 130 next = player.track->link_hs.prev; 131 } else { 132 return PLAYER_ERR; 133 } 134 135 track = LIST_UPCAST(next, struct track, link_hs); 136 player_play_track(track, false); 137 138 return PLAYER_OK; 139} 140 141int 142player_next(void) 143{ 144 struct track *next_track; 145 struct list_link *link; 146 bool new_entry; 147 148 if (player.track && list_link_inuse(&player.track->link_hs) 149 && LIST_INNER(player.track->link_hs.next)) { 150 next_track = LIST_UPCAST(player.track->link_hs.next, 151 struct track, link_hs); 152 new_entry = false; 153 } else if (!list_empty(&player.queue)) { 154 link = list_pop_front(&player.queue); 155 next_track = LIST_UPCAST(link, struct track, link_pq); 156 new_entry = true; 157 } else { 158 next_track = player_next_from_playlist(); 159 if (!next_track) goto clear; 160 new_entry = true; 161 } 162 163 player_play_track(next_track, new_entry); 164 return PLAYER_OK; 165 166clear: 167 player_clear_track(); 168 return PLAYER_ERR; 169} 170 171/* implemented by backend: 172 * 173 * int player_seek(int sec); 174 * int player_play(void); 175 * int player_stop(void); 176 * 177 * int player_set_volume(unsigned int vol); 178 */ 179