From 847ca4193e3fbc5b27285979888ab364bbf1792e Mon Sep 17 00:00:00 2001 From: Adam Simpkins Date: Wed, 9 Jan 2013 11:52:01 -0800 Subject: Add play and pause commands Add commands that always play and always pause, in addition to the current toggle pause command. Closes #342. --- contrib/config-example | 6 +++++- contrib/pianobar.1 | 14 ++++++++++--- src/main.c | 2 ++ src/player.c | 54 ++++++++++++++++++++++++++++++++------------------ src/player.h | 6 ++++-- src/settings.h | 4 +++- src/ui_act.c | 36 ++++++++++++++++++++++++--------- src/ui_act.h | 4 +++- src/ui_dispatch.h | 14 ++++++++----- 9 files changed, 99 insertions(+), 41 deletions(-) diff --git a/contrib/config-example b/contrib/config-example index c854e39..4958e66 100644 --- a/contrib/config-example +++ b/contrib/config-example @@ -24,10 +24,14 @@ #act_addshared = j #act_songmove = m #act_songnext = n -#act_songpause = p +#act_songpause = S +#act_songpausetoggle = p +#act_songpausetoggle2 = +#act_songplay = P #act_quit = q #act_stationrename = r #act_stationchange = s +#act_stationcreatefromsong = v #act_songtired = t #act_upcoming = u #act_stationselectquickmix = x diff --git a/contrib/pianobar.1 b/contrib/pianobar.1 index 86f1138..12cd06d 100644 --- a/contrib/pianobar.1 +++ b/contrib/pianobar.1 @@ -113,10 +113,18 @@ Move current song to another station Skip current song. .TP -.B act_songpause = p +.B act_songpause = S +Pause playback + +.TP +.B act_songpausetoggle = p .TQ -.B act_songpause2 = -Pause/Continue +.B act_songpausetoggle2 = +Pause/resume playback + +.TP +.B act_songplay = P +Resume playback .TP .B act_quit = q diff --git a/src/main.c b/src/main.c index f611706..b16eb97 100644 --- a/src/main.c +++ b/src/main.c @@ -269,6 +269,7 @@ static void BarMainStartPlayback (BarApp_t *app, pthread_t *playerThread) { app->player.audioFormat = app->playlist->audioFormat; app->player.settings = &app->settings; pthread_mutex_init (&app->player.pauseMutex, NULL); + pthread_cond_init (&app->player.pauseCond, NULL); /* throw event */ BarUiStartEventCmd (&app->settings, "songstart", @@ -296,6 +297,7 @@ static void BarMainPlayerCleanup (BarApp_t *app, pthread_t *playerThread) { /* FIXME: pthread_join blocks everything if network connection * is hung up e.g. */ pthread_join (*playerThread, &threadRet); + pthread_cond_destroy (&app->player.pauseCond); pthread_mutex_destroy (&app->player.pauseMutex); /* don't continue playback if thread reports error */ diff --git a/src/player.c b/src/player.c index 1cb44de..8a46f31 100644 --- a/src/player.c +++ b/src/player.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2012 +Copyright (c) 2008-2013 Lars-Dominik Braun Permission is hereby granted, free of charge, to any person obtaining a copy @@ -38,20 +38,34 @@ THE SOFTWARE. #define bigToHostEndian32(x) ntohl(x) -/* wait while locked, but don't slow down main thread by keeping - * locks too long */ -#define QUIT_PAUSE_CHECK \ - pthread_mutex_lock (&player->pauseMutex); \ - pthread_mutex_unlock (&player->pauseMutex); \ - if (player->doQuit) { \ - /* err => abort playback */ \ - return WAITRESS_CB_RET_ERR; \ - } - /* pandora uses float values with 2 digits precision. Scale them by 100 to get * a "nice" integer */ #define RG_SCALE_FACTOR 100 +/* wait until the pause flag is cleared + * @param player structure + * @return true if the player should quit + */ +static bool BarPlayerCheckPauseQuit (struct audioPlayer *player) { + bool quit = false; + + pthread_mutex_lock (&player->pauseMutex); + while (true) { + if (player->doQuit) { + quit = true; + break; + } + if (!player->doPause) { + break; + } + pthread_cond_wait(&player->pauseCond, + &player->pauseMutex); + } + pthread_mutex_unlock (&player->pauseMutex); + + return quit; +} + /* compute replaygain scale factor * algo taken from here: http://www.dsprelated.com/showmessage/29246/1.php * mpd does the same @@ -125,9 +139,8 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size, const char *data = ptr; struct audioPlayer *player = stream; - QUIT_PAUSE_CHECK; - - if (!BarPlayerBufferFill (player, data, size)) { + if (BarPlayerCheckPauseQuit (player) || + !BarPlayerBufferFill (player, data, size)) { return WAITRESS_CB_RET_ERR; } @@ -141,7 +154,9 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size, player->sampleSize[player->sampleSizeCurr]) { /* going through this loop can take up to a few seconds => * allow earlier thread abort */ - QUIT_PAUSE_CHECK; + if (BarPlayerCheckPauseQuit (player)) { + return WAITRESS_CB_RET_ERR; + } /* decode frame */ aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo, @@ -335,9 +350,8 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size, struct audioPlayer *player = stream; size_t i; - QUIT_PAUSE_CHECK; - - if (!BarPlayerBufferFill (player, data, size)) { + if (BarPlayerCheckPauseQuit (player) || + !BarPlayerBufferFill (player, data, size)) { return WAITRESS_CB_RET_ERR; } @@ -417,7 +431,9 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size, (unsigned long long int) player->samplerate; } - QUIT_PAUSE_CHECK; + if (BarPlayerCheckPauseQuit (player)) { + return WAITRESS_CB_RET_ERR; + } } while (player->mp3Stream.error != MAD_ERROR_BUFLEN); player->bufferRead += player->mp3Stream.next_frame - player->buffer; diff --git a/src/player.h b/src/player.h index ac6853c..d0eac22 100644 --- a/src/player.h +++ b/src/player.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2010 +Copyright (c) 2008-2013 Lars-Dominik Braun Permission is hereby granted, free of charge, to any person obtaining a copy @@ -49,7 +49,8 @@ THE SOFTWARE. #define BAR_PLAYER_BUFSIZE (WAITRESS_BUFFER_SIZE*2) struct audioPlayer { - char doQuit; + bool doQuit; /* protected by pauseMutex */ + bool doPause; /* protected by pauseMutex */ unsigned char channels; unsigned char aoError; @@ -102,6 +103,7 @@ struct audioPlayer { unsigned char *buffer; pthread_mutex_t pauseMutex; + pthread_cond_t pauseCond; WaitressHandle_t waith; }; diff --git a/src/settings.h b/src/settings.h index 6ccad5d..392ea58 100644 --- a/src/settings.h +++ b/src/settings.h @@ -57,8 +57,10 @@ typedef enum { BAR_KS_MANAGESTATION = 23, BAR_KS_PLAYPAUSE2 = 24, BAR_KS_CREATESTATIONFROMSONG = 25, + BAR_KS_PLAY = 26, + BAR_KS_PAUSE = 27, /* insert new shortcuts _before_ this element and increase its value */ - BAR_KS_COUNT = 26, + BAR_KS_COUNT = 28, } BarKeyShortcutId_t; #define BAR_KS_DISABLED '\x00' diff --git a/src/ui_act.c b/src/ui_act.c index 70fbc9a..8d9ac09 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2012 +Copyright (c) 2008-2013 Lars-Dominik Braun Permission is hereby granted, free of charge, to any person obtaining a copy @@ -49,9 +49,9 @@ THE SOFTWARE. static inline void BarUiDoSkipSong (struct audioPlayer *player) { assert (player != NULL); - player->doQuit = 1; - /* unlocking an unlocked mutex is forbidden by some implementations */ - pthread_mutex_trylock (&player->pauseMutex); + pthread_mutex_lock (&player->pauseMutex); + player->doQuit = true; + pthread_cond_broadcast (&player->pauseCond); pthread_mutex_unlock (&player->pauseMutex); } @@ -335,13 +335,31 @@ BarUiActCallback(BarUiActSkipSong) { BarUiDoSkipSong (&app->player); } +/* play + */ +BarUiActCallback(BarUiActPlay) { + pthread_mutex_lock (&app->player.pauseMutex); + app->player.doPause = false; + pthread_cond_broadcast (&app->player.pauseCond); + pthread_mutex_unlock (&app->player.pauseMutex); +} + /* pause */ BarUiActCallback(BarUiActPause) { - /* already locked => unlock/unpause */ - if (pthread_mutex_trylock (&app->player.pauseMutex) == EBUSY) { - pthread_mutex_unlock (&app->player.pauseMutex); - } + pthread_mutex_lock (&app->player.pauseMutex); + app->player.doPause = true; + pthread_cond_broadcast (&app->player.pauseCond); + pthread_mutex_unlock (&app->player.pauseMutex); +} + +/* toggle pause + */ +BarUiActCallback(BarUiActTogglePause) { + pthread_mutex_lock (&app->player.pauseMutex); + app->player.doPause = !app->player.doPause; + pthread_cond_broadcast (&app->player.pauseCond); + pthread_mutex_unlock (&app->player.pauseMutex); } /* rename current station @@ -483,7 +501,7 @@ BarUiActCallback(BarUiActSelectQuickMix) { /* quit */ BarUiActCallback(BarUiActQuit) { - app->doQuit = 1; + app->doQuit = true; BarUiDoSkipSong (&app->player); } diff --git a/src/ui_act.h b/src/ui_act.h index d225556..3e6c4c5 100644 --- a/src/ui_act.h +++ b/src/ui_act.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2008-2011 +Copyright (c) 2008-2013 Lars-Dominik Braun Permission is hereby granted, free of charge, to any person obtaining a copy @@ -45,7 +45,9 @@ BarUiActCallback(BarUiActStationFromGenre); BarUiActCallback(BarUiActSongInfo); BarUiActCallback(BarUiActLoveSong); BarUiActCallback(BarUiActSkipSong); +BarUiActCallback(BarUiActPlay); BarUiActCallback(BarUiActPause); +BarUiActCallback(BarUiActTogglePause); BarUiActCallback(BarUiActRenameStation); BarUiActCallback(BarUiActSelectStation); BarUiActCallback(BarUiActTempBanSong); diff --git a/src/ui_dispatch.h b/src/ui_dispatch.h index 9d87659..6b96ae3 100644 --- a/src/ui_dispatch.h +++ b/src/ui_dispatch.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2010-2012 +Copyright (c) 2010-2013 Lars-Dominik Braun Permission is hereby granted, free of charge, to any person obtaining a copy @@ -71,8 +71,8 @@ static const BarUiDispatchAction_t dispatchActions[BAR_KS_COUNT] = { "act_addshared"}, {'n', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActSkipSong, "next song", "act_songnext"}, - {'p', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActPause, "pause/continue", - "act_songpause"}, + {'p', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActTogglePause, "pause/resume playback", + "act_songpausetoggle"}, {'q', BAR_DC_GLOBAL, BarUiActQuit, "quit", "act_quit"}, {'r', BAR_DC_STATION, BarUiActRenameStation, "rename station", "act_stationrename"}, @@ -93,10 +93,14 @@ static const BarUiDispatchAction_t dispatchActions[BAR_KS_COUNT] = { "act_volup"}, {'=', BAR_DC_STATION, BarUiActManageStation, "delete seeds/feedback", "act_managestation"}, - {' ', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActPause, NULL, - "act_songpause2"}, + {' ', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActTogglePause, NULL, + "act_songpausetoggle2"}, {'v', BAR_DC_SONG, BarUiActCreateStationFromSong, "create new station from song or artist", "act_stationcreatefromsong"}, + {'P', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActPlay, "resume playback", + "act_songplay"}, + {'S', BAR_DC_GLOBAL | BAR_DC_STATION, BarUiActPause, "pause playback", + "act_songpause"}, }; #include -- cgit v1.2.3