00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00031 #include "stdinc.h"
00032
00033 #include "audio_file.h"
00034 #include "audio_output.h"
00035 #include "config.h"
00036 #include "gui.h"
00037 #include "playq.h"
00038 #include "playq_modules.h"
00039 #include "vfs.h"
00040
00044 struct playq_funcs {
00048 struct vfsref *(*give)(void);
00052 void (*idle)(void);
00056 int (*select)(struct vfsref *vr);
00060 int (*next)(void);
00064 int (*prev)(void);
00068 void (*notify_pre_removal)(struct vfsref *vr);
00069 };
00070
00074 static struct playq_funcs party_funcs = {
00075 playq_party_give,
00076 playq_party_idle,
00077 playq_party_select,
00078 playq_party_next,
00079 playq_party_prev,
00080 playq_party_notify_pre_removal,
00081 };
00085 static struct playq_funcs xmms_funcs = {
00086 playq_xmms_give,
00087 playq_xmms_idle,
00088 playq_xmms_select,
00089 playq_xmms_next,
00090 playq_xmms_prev,
00091 playq_xmms_notify_pre_removal,
00092 };
00096 static struct playq_funcs *funcs = &party_funcs;
00097
00098 struct vfslist playq_list = VFSLIST_INITIALIZER;
00099 GMutex *playq_mtx;
00105 static GCond *playq_wakeup;
00109 static GThread *playq_runner;
00113 static GRand *playq_rand;
00117 #define PF_QUIT 0x01
00118
00121 #define PF_PAUSE 0x02
00122
00125 #define PF_SEEK_ABS 0x08
00126
00129 #define PF_SEEK_REL 0x10
00130
00133 #define PF_SEEK (PF_SEEK_ABS|PF_SEEK_REL)
00134
00137 #define PF_SKIP 0x20
00138
00141 #define PF_STOP 0x40
00142
00146 static volatile int playq_flags = PF_STOP;
00147 int playq_repeat = 0;
00151 static volatile int playq_seek_time;
00152
00157 static void *
00158 playq_runner_thread(void *unused)
00159 {
00160 struct vfsref *nvr;
00161 struct audio_file *cur;
00162 char *errmsg;
00163
00164 gui_input_sigmask();
00165
00166 do {
00167
00168 playq_lock();
00169 for (;;) {
00170
00171 if (playq_flags & PF_QUIT) {
00172 playq_unlock();
00173 goto done;
00174 }
00175
00176
00177 if (!(playq_flags & PF_STOP) &&
00178 (nvr = funcs->give()) != NULL) {
00179
00180 break;
00181 }
00182
00183
00184 playq_flags |= PF_STOP;
00185 funcs->idle();
00186 gui_playq_song_update(NULL, 0, 0);
00187 g_cond_wait(playq_wakeup, playq_mtx);
00188 }
00189 playq_unlock();
00190
00191 cur = audio_file_open(nvr);
00192 if (cur == NULL) {
00193
00194 errmsg = g_strdup_printf(
00195 _("Failed to open \"%s\" for playback."),
00196 vfs_name(nvr));
00197 gui_msgbar_warn(errmsg);
00198 g_free(errmsg);
00199 vfs_close(nvr);
00200
00201 g_usleep(500000);
00202 continue;
00203 }
00204
00205
00206 vfs_close(nvr);
00207 gui_playq_song_update(cur, 0, 0);
00208
00209 playq_lock();
00210 playq_flags &= ~(PF_PAUSE|PF_SKIP|PF_SEEK);
00211 playq_unlock();
00212
00213 do {
00214 if (playq_flags & PF_PAUSE && !cur->stream) {
00215 gui_playq_song_update(cur, 1, 1);
00216
00217
00218 playq_lock();
00219 g_cond_wait(playq_wakeup, playq_mtx);
00220 playq_unlock();
00221 } else {
00222 gui_playq_song_update(cur, 0, 1);
00223
00224
00225 if (audio_output_play(cur) != 0)
00226 break;
00227 }
00228
00229 if (playq_flags & PF_SEEK) {
00230 audio_file_seek(cur, playq_seek_time,
00231 playq_flags & PF_SEEK_REL);
00232 playq_lock();
00233 playq_flags &= ~PF_SEEK;
00234 playq_unlock();
00235 }
00236 } while (!(playq_flags & (PF_QUIT|PF_SKIP)));
00237
00238 audio_file_close(cur);
00239 } while (!(playq_flags & PF_QUIT));
00240 done:
00241 return (NULL);
00242 }
00243
00244 void
00245 playq_init(int autoplay, int xmms, int load_dumpfile)
00246 {
00247 const char *filename;
00248 struct vfsref *vr;
00249
00250 playq_mtx = g_mutex_new();
00251 playq_wakeup = g_cond_new();
00252 playq_rand = g_rand_new();
00253
00254 if (autoplay || config_getopt_bool("playq.autoplay"))
00255 playq_flags &= ~PF_STOP;
00256
00257 if (xmms || config_getopt_bool("playq.xmms")) {
00258 funcs = &xmms_funcs;
00259 playq_repeat = 1;
00260 }
00261
00262 filename = config_getopt("playq.dumpfile");
00263 if (load_dumpfile && filename[0] != '\0') {
00264
00265 vr = vfs_lookup(filename, NULL, NULL, 0);
00266 if (vr != NULL) {
00267 vfs_unfold(&playq_list, vr);
00268 vfs_close(vr);
00269 }
00270 }
00271 }
00272
00273 void
00274 playq_spawn(void)
00275 {
00276 playq_runner = g_thread_create_full(playq_runner_thread, NULL,
00277 0, 1, TRUE, G_THREAD_PRIORITY_URGENT, NULL);
00278 }
00279
00280 void
00281 playq_shutdown(void)
00282 {
00283 struct vfsref *vr;
00284 const char *filename;
00285
00286 playq_lock();
00287 playq_flags = PF_QUIT;
00288 playq_unlock();
00289 g_cond_signal(playq_wakeup);
00290 g_thread_join(playq_runner);
00291
00292 filename = config_getopt("playq.dumpfile");
00293 if (filename[0] != '\0') {
00294 if (vfs_list_empty(&playq_list)) {
00295
00296 vfs_delete(filename);
00297 } else {
00298
00299 vr = vfs_write_playlist(&playq_list, NULL, filename);
00300 if (vr != NULL)
00301 vfs_close(vr);
00302 }
00303 }
00304 }
00305
00306
00307
00308
00309
00310 void
00311 playq_song_add_head(struct vfsref *vr)
00312 {
00313 struct vfslist newlist = VFSLIST_INITIALIZER;
00314
00315
00316 vfs_unfold(&newlist, vr);
00317 if (vfs_list_empty(&newlist))
00318 return;
00319
00320 playq_lock();
00321
00322 while ((vr = vfs_list_last(&newlist)) != NULL) {
00323 vfs_list_remove(&newlist, vr);
00324 vfs_list_insert_head(&playq_list, vr);
00325 gui_playq_notify_post_insertion(1);
00326 }
00327
00328 gui_playq_notify_done();
00329 g_cond_signal(playq_wakeup);
00330 playq_unlock();
00331 }
00332
00333 void
00334 playq_song_add_tail(struct vfsref *vr)
00335 {
00336 struct vfslist newlist = VFSLIST_INITIALIZER;
00337
00338
00339 vfs_unfold(&newlist, vr);
00340 if (vfs_list_empty(&newlist))
00341 return;
00342
00343 playq_lock();
00344
00345 while ((vr = vfs_list_first(&newlist)) != NULL) {
00346 vfs_list_remove(&newlist, vr);
00347 vfs_list_insert_tail(&playq_list, vr);
00348 gui_playq_notify_post_insertion(vfs_list_items(&playq_list));
00349 }
00350
00351 gui_playq_notify_done();
00352 g_cond_signal(playq_wakeup);
00353 playq_unlock();
00354 }
00355
00359 void
00360 playq_cursong_seek(int len, int rel)
00361 {
00362 int fl;
00363
00364 fl = rel ? PF_SEEK_REL : PF_SEEK_ABS;
00365 playq_lock();
00366 playq_flags = (playq_flags & ~PF_SEEK) | fl;
00367 playq_seek_time = len;
00368 playq_unlock();
00369
00370 g_cond_signal(playq_wakeup);
00371 }
00372
00373 void
00374 playq_cursong_next(void)
00375 {
00376 playq_lock();
00377 if (funcs->next() == 0) {
00378
00379 playq_flags |= PF_SKIP;
00380 g_cond_signal(playq_wakeup);
00381 }
00382 playq_unlock();
00383 }
00384
00385 void
00386 playq_cursong_prev(void)
00387 {
00388 playq_lock();
00389 if (funcs->prev() == 0) {
00390
00391 playq_flags |= PF_SKIP;
00392 g_cond_signal(playq_wakeup);
00393 }
00394 playq_unlock();
00395 }
00396
00397 void
00398 playq_cursong_stop(void)
00399 {
00400 playq_lock();
00401
00402 playq_flags |= (PF_SKIP|PF_STOP);
00403 playq_unlock();
00404
00405 g_cond_signal(playq_wakeup);
00406 }
00407
00408 void
00409 playq_cursong_pause(void)
00410 {
00411 playq_lock();
00412
00413 playq_flags ^= PF_PAUSE;
00414 playq_unlock();
00415
00416 g_cond_signal(playq_wakeup);
00417 }
00418
00419 void
00420 playq_repeat_toggle(void)
00421 {
00422 char *msg;
00423
00424 playq_repeat = !playq_repeat;
00425
00426 msg = g_strdup_printf(_("Repeat: %s"),
00427 playq_repeat ? _("on") : _("off"));
00428 gui_msgbar_warn(msg);
00429 g_free(msg);
00430 }
00431
00432 void
00433 playq_song_fast_remove(struct vfsref *vr, unsigned int index)
00434 {
00435 funcs->notify_pre_removal(vr);
00436 gui_playq_notify_pre_removal(index);
00437 vfs_list_remove(&playq_list, vr);
00438 vfs_close(vr);
00439 gui_playq_notify_done();
00440 }
00441
00442 void
00443 playq_song_fast_add_before(struct vfsref *nvr, struct vfsref *lvr,
00444 unsigned int index)
00445 {
00446 struct vfslist newlist = VFSLIST_INITIALIZER;
00447
00448
00449 vfs_unfold(&newlist, nvr);
00450 if (vfs_list_empty(&newlist))
00451 return;
00452
00453
00454 while ((nvr = vfs_list_first(&newlist)) != NULL) {
00455 vfs_list_remove(&newlist, nvr);
00456 vfs_list_insert_before(&playq_list, nvr, lvr);
00457 gui_playq_notify_post_insertion(index);
00458 }
00459
00460 gui_playq_notify_done();
00461 g_cond_signal(playq_wakeup);
00462 }
00463
00464 void
00465 playq_song_fast_add_after(struct vfsref *nvr, struct vfsref *lvr,
00466 unsigned int index)
00467 {
00468 struct vfslist newlist = VFSLIST_INITIALIZER;
00469
00470
00471 vfs_unfold(&newlist, nvr);
00472 if (vfs_list_empty(&newlist))
00473 return;
00474
00475
00476 while ((nvr = vfs_list_last(&newlist)) != NULL) {
00477 vfs_list_remove(&newlist, nvr);
00478 vfs_list_insert_after(&playq_list, nvr, lvr);
00479 gui_playq_notify_post_insertion(index + 1);
00480 }
00481
00482 gui_playq_notify_done();
00483 g_cond_signal(playq_wakeup);
00484 }
00485
00486 void
00487 playq_song_fast_move_up(struct vfsref *vr, unsigned int index)
00488 {
00489 struct vfsref *pvr;
00490
00491
00492 pvr = vfs_list_prev(vr);
00493 gui_playq_notify_pre_removal(index - 1);
00494 vfs_list_remove(&playq_list, pvr);
00495
00496
00497 vfs_list_insert_after(&playq_list, pvr, vr);
00498 gui_playq_notify_post_insertion(index);
00499 gui_playq_notify_done();
00500 }
00501
00502 void
00503 playq_song_fast_move_down(struct vfsref *vr, unsigned int index)
00504 {
00505 struct vfsref *nvr;
00506
00507
00508 nvr = vfs_list_next(vr);
00509 gui_playq_notify_pre_removal(index + 1);
00510 vfs_list_remove(&playq_list, nvr);
00511
00512
00513 vfs_list_insert_before(&playq_list, nvr, vr);
00514 gui_playq_notify_post_insertion(index);
00515 gui_playq_notify_done();
00516
00517 }
00518
00519 void
00520 playq_song_fast_move_head(struct vfsref *vr, unsigned int index)
00521 {
00522
00523 gui_playq_notify_pre_removal(index);
00524 vfs_list_remove(&playq_list, vr);
00525
00526
00527 vfs_list_insert_head(&playq_list, vr);
00528 gui_playq_notify_post_insertion(1);
00529 gui_playq_notify_done();
00530 }
00531
00532 void
00533 playq_song_fast_move_tail(struct vfsref *vr, unsigned int index)
00534 {
00535
00536 gui_playq_notify_pre_removal(index);
00537 vfs_list_remove(&playq_list, vr);
00538
00539
00540 vfs_list_insert_tail(&playq_list, vr);
00541 gui_playq_notify_post_insertion(vfs_list_items(&playq_list));
00542 gui_playq_notify_done();
00543 }
00544
00545 void
00546 playq_song_fast_select(struct vfsref *vr)
00547 {
00548 if (funcs->select(vr) != 0)
00549 return;
00550
00551
00552 playq_flags &= ~PF_STOP;
00553 playq_flags |= PF_SKIP;
00554 g_cond_signal(playq_wakeup);
00555 }
00556
00557 void
00558 playq_song_remove_all(void)
00559 {
00560 struct vfsref *vr;
00561
00562 playq_lock();
00563 while ((vr = vfs_list_first(&playq_list)) != NULL) {
00564 funcs->notify_pre_removal(vr);
00565 gui_playq_notify_pre_removal(1);
00566 vfs_list_remove(&playq_list, vr);
00567 vfs_close(vr);
00568 }
00569 gui_playq_notify_done();
00570 playq_unlock();
00571 }
00572
00573 void
00574 playq_song_randomize(void)
00575 {
00576 unsigned int remaining, idx = 0;
00577 struct vfsref *vr, **vrlist;
00578
00579
00580
00581
00582
00583
00584
00585 playq_lock();
00586 remaining = vfs_list_items(&playq_list);
00587 if (remaining < 2)
00588 goto done;
00589
00590
00591 vrlist = g_new(struct vfsref *, remaining);
00592 VFS_LIST_FOREACH(&playq_list, vr)
00593 vrlist[idx++] = vr;
00594 vfs_list_init(&playq_list);
00595
00596 do {
00597
00598 idx = g_rand_int_range(playq_rand, 0, remaining);
00599
00600
00601 vfs_list_insert_tail(&playq_list, vrlist[idx]);
00602
00603 vrlist[idx] = vrlist[--remaining];
00604 } while (remaining != 0);
00605
00606
00607 g_free(vrlist);
00608
00609 gui_playq_notify_post_randomization();
00610 gui_playq_notify_done();
00611 done: playq_unlock();
00612 }