Created
March 2, 2018 15:42
-
-
Save anonymous/f4bedb982de18683f2f70e0ecc403fc4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/main.c b/src/main.c | |
index 229c606..41f1c44 100644 | |
--- a/src/main.c | |
+++ b/src/main.c | |
@@ -259,8 +259,8 @@ static void BarMainStartPlayback (BarApp_t *app, pthread_t *playerThread) { | |
app->player.gain = curSong->fileGain; | |
app->player.settings = &app->settings; | |
app->player.songDuration = curSong->length; | |
- pthread_mutex_init (&app->player.pauseMutex, NULL); | |
- pthread_cond_init (&app->player.pauseCond, NULL); | |
+ pthread_mutex_init (&app->player.lock, NULL); | |
+ pthread_cond_init (&app->player.cond, NULL); | |
assert (interrupted == &app->doQuit); | |
interrupted = &app->player.interrupted; | |
@@ -291,8 +291,8 @@ 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); | |
+ pthread_cond_destroy (&app->player.cond); | |
+ pthread_mutex_destroy (&app->player.lock); | |
if (threadRet == (void *) PLAYER_RET_OK) { | |
app->playerErrors = 0; | |
@@ -351,14 +351,15 @@ static void BarMainLoop (BarApp_t *app) { | |
BarMainGetInitialStation (app); | |
+ player_t * const player = &app->player; | |
/* little hack, needed to signal: hey! we need a playlist, but don't | |
* free anything (there is nothing to be freed yet) */ | |
- memset (&app->player, 0, sizeof (app->player)); | |
+ memset (player, 0, sizeof (*player)); | |
while (!app->doQuit) { | |
/* song finished playing, clean up things/scrobble song */ | |
- if (app->player.mode == PLAYER_FINISHED) { | |
- if (app->player.interrupted != 0) { | |
+ if (BarPlayerGetMode (player) == PLAYER_FINISHED) { | |
+ if (player->interrupted != 0) { | |
app->doQuit = 1; | |
} | |
BarMainPlayerCleanup (app, &playerThread); | |
@@ -366,7 +367,7 @@ static void BarMainLoop (BarApp_t *app) { | |
/* check whether player finished playing and start playing new | |
* song */ | |
- if (app->player.mode == PLAYER_DEAD) { | |
+ if (BarPlayerGetMode (player) == PLAYER_DEAD) { | |
/* what's next? */ | |
if (app->playlist != NULL) { | |
PianoSong_t *histsong = app->playlist; | |
@@ -389,12 +390,12 @@ static void BarMainLoop (BarApp_t *app) { | |
BarMainHandleUserInput (app); | |
/* show time */ | |
- if (app->player.mode == PLAYER_PLAYING) { | |
+ if (BarPlayerGetMode (player) == PLAYER_PLAYING) { | |
BarMainPrintTime (app); | |
} | |
} | |
- if (app->player.mode != PLAYER_DEAD) { | |
+ if (BarPlayerGetMode (player) != PLAYER_DEAD) { | |
pthread_join (playerThread, NULL); | |
} | |
} | |
diff --git a/src/player.c b/src/player.c | |
index 9cbee69..b5c67c1 100644 | |
--- a/src/player.c | |
+++ b/src/player.c | |
@@ -122,7 +122,9 @@ static int intCb (void * const data) { | |
assert (player != NULL); | |
if (player->interrupted > 1) { | |
/* got a sigint multiple times, quit pianobar (handled by main.c). */ | |
+ pthread_mutex_lock (&player->lock); | |
player->doQuit = true; | |
+ pthread_mutex_unlock (&player->lock); | |
return 1; | |
} else if (player->interrupted != 0) { | |
/* the request is retried with the same player context */ | |
@@ -190,9 +192,11 @@ static bool openStream (player_t * const player) { | |
av_seek_frame (player->fctx, player->streamIdx, player->lastTimestamp, 0); | |
} | |
+ pthread_mutex_lock (&player->lock); | |
player->songPlayed = 0; | |
player->songDuration = av_q2d (player->st->time_base) * | |
(double) player->st->duration; | |
+ pthread_mutex_unlock (&player->lock); | |
return true; | |
} | |
@@ -283,6 +287,29 @@ static bool openDevice (player_t * const player) { | |
return true; | |
} | |
+/* Operating on shared variables and must be protected by mutex | |
+ */ | |
+ | |
+static bool shouldQuit (player_t * const player) { | |
+ pthread_mutex_lock (&player->lock); | |
+ const bool ret = player->doQuit; | |
+ pthread_mutex_unlock (&player->lock); | |
+ return ret; | |
+} | |
+ | |
+static void changeMode (player_t * const player, unsigned int mode) { | |
+ pthread_mutex_lock (&player->lock); | |
+ player->mode = mode; | |
+ pthread_mutex_unlock (&player->lock); | |
+} | |
+ | |
+unsigned int BarPlayerGetMode (player_t * const player) { | |
+ pthread_mutex_lock (&player->lock); | |
+ const unsigned int ret = player->mode; | |
+ pthread_mutex_unlock (&player->lock); | |
+ return ret; | |
+} | |
+ | |
/* decode and play stream. returns 0 or av error code. | |
*/ | |
static int play (player_t * const player) { | |
@@ -302,7 +329,7 @@ static int play (player_t * const player) { | |
enum { FILL, DRAIN, DONE } drainMode = FILL; | |
int ret = 0; | |
- while (!player->doQuit && drainMode != DONE) { | |
+ while (!shouldQuit (player) && drainMode != DONE) { | |
if (drainMode == FILL) { | |
ret = av_read_frame (player->fctx, &pkt); | |
if (ret == AVERROR_EOF) { | |
@@ -323,17 +350,17 @@ static int play (player_t * const player) { | |
} | |
/* pausing */ | |
- pthread_mutex_lock (&player->pauseMutex); | |
+ pthread_mutex_lock (&player->lock); | |
if (player->doPause) { | |
av_read_pause (player->fctx); | |
do { | |
- pthread_cond_wait (&player->pauseCond, &player->pauseMutex); | |
+ pthread_cond_wait (&player->cond, &player->lock); | |
} while (player->doPause); | |
av_read_play (player->fctx); | |
} | |
- pthread_mutex_unlock (&player->pauseMutex); | |
+ pthread_mutex_unlock (&player->lock); | |
- while (!player->doQuit) { | |
+ while (!shouldQuit (player)) { | |
ret = avcodec_receive_frame (cctx, frame); | |
if (ret == AVERROR_EOF) { | |
/* done draining */ | |
@@ -367,7 +394,9 @@ static int play (player_t * const player) { | |
} | |
} | |
+ pthread_mutex_lock (&player->lock); | |
player->songPlayed = av_q2d (player->st->time_base) * (double) pkt.pts; | |
+ pthread_mutex_unlock (&player->lock); | |
player->lastTimestamp = pkt.pts; | |
av_packet_unref (&pkt); | |
@@ -410,7 +439,7 @@ void *BarPlayerThread (void *data) { | |
retry = false; | |
if (openStream (player)) { | |
if (openFilter (player) && openDevice (player)) { | |
- player->mode = PLAYER_PLAYING; | |
+ changeMode (player, PLAYER_PLAYING); | |
BarPlayerSetVolume (player); | |
retry = play (player) == AVERROR_INVALIDDATA && | |
!player->interrupted; | |
@@ -422,11 +451,11 @@ void *BarPlayerThread (void *data) { | |
/* stream not found */ | |
pret = PLAYER_RET_SOFTFAIL; | |
} | |
- player->mode = PLAYER_WAITING; | |
+ changeMode (player, PLAYER_WAITING); | |
finish (player); | |
} while (retry); | |
- player->mode = PLAYER_FINISHED; | |
+ changeMode (player, PLAYER_FINISHED); | |
return (void *) pret; | |
} | |
diff --git a/src/player.h b/src/player.h | |
index 0213fde..570038f 100644 | |
--- a/src/player.h | |
+++ b/src/player.h | |
@@ -40,11 +40,15 @@ THE SOFTWARE. | |
#include "settings.h" | |
typedef struct { | |
- /* protected by pauseMutex */ | |
- volatile bool doQuit; | |
- volatile bool doPause; | |
- pthread_mutex_t pauseMutex; | |
- pthread_cond_t pauseCond; | |
+ /* public attributes protected by mutex */ | |
+ pthread_mutex_t lock; | |
+ pthread_cond_t cond; /* broadcast changes to doPause */ | |
+ | |
+ bool doQuit, doPause; | |
+ | |
+ /* measured in seconds */ | |
+ unsigned int songDuration; | |
+ unsigned int songPlayed; | |
enum { | |
/* not running */ | |
@@ -57,6 +61,8 @@ typedef struct { | |
PLAYER_FINISHED, | |
} mode; | |
+ /* private attributes _not_ protected by mutex */ | |
+ | |
/* libav */ | |
AVFilterContext *fvolume; | |
AVFilterGraph *fgraph; | |
@@ -70,14 +76,10 @@ typedef struct { | |
ao_device *aoDev; | |
- /* settings */ | |
+ /* settings (must be set before starting the thread) */ | |
double gain; | |
char *url; | |
const BarSettings_t *settings; | |
- | |
- /* measured in seconds */ | |
- volatile unsigned int songDuration; | |
- volatile unsigned int songPlayed; | |
} player_t; | |
enum {PLAYER_RET_OK = 0, PLAYER_RET_HARDFAIL = 1, PLAYER_RET_SOFTFAIL = 2}; | |
@@ -86,4 +88,5 @@ void *BarPlayerThread (void *data); | |
void BarPlayerSetVolume (player_t * const player); | |
void BarPlayerInit (); | |
void BarPlayerDestroy (); | |
+unsigned int BarPlayerGetMode (player_t * const player); | |
diff --git a/src/ui_act.c b/src/ui_act.c | |
index 2c5f264..8600f6e 100644 | |
--- a/src/ui_act.c | |
+++ b/src/ui_act.c | |
@@ -52,11 +52,11 @@ THE SOFTWARE. | |
static inline void BarUiDoSkipSong (player_t * const player) { | |
assert (player != NULL); | |
- pthread_mutex_lock (&player->pauseMutex); | |
+ pthread_mutex_lock (&player->lock); | |
player->doQuit = true; | |
player->doPause = false; | |
- pthread_cond_broadcast (&player->pauseCond); | |
- pthread_mutex_unlock (&player->pauseMutex); | |
+ pthread_cond_broadcast (&player->cond); | |
+ pthread_mutex_unlock (&player->lock); | |
} | |
/* transform station if necessary to allow changes like rename, rate, ... | |
@@ -419,28 +419,28 @@ BarUiActCallback(BarUiActSkipSong) { | |
/* play | |
*/ | |
BarUiActCallback(BarUiActPlay) { | |
- pthread_mutex_lock (&app->player.pauseMutex); | |
+ pthread_mutex_lock (&app->player.lock); | |
app->player.doPause = false; | |
- pthread_cond_broadcast (&app->player.pauseCond); | |
- pthread_mutex_unlock (&app->player.pauseMutex); | |
+ pthread_cond_broadcast (&app->player.cond); | |
+ pthread_mutex_unlock (&app->player.lock); | |
} | |
/* pause | |
*/ | |
BarUiActCallback(BarUiActPause) { | |
- pthread_mutex_lock (&app->player.pauseMutex); | |
+ pthread_mutex_lock (&app->player.lock); | |
app->player.doPause = true; | |
- pthread_cond_broadcast (&app->player.pauseCond); | |
- pthread_mutex_unlock (&app->player.pauseMutex); | |
+ pthread_cond_broadcast (&app->player.cond); | |
+ pthread_mutex_unlock (&app->player.lock); | |
} | |
/* toggle pause | |
*/ | |
BarUiActCallback(BarUiActTogglePause) { | |
- pthread_mutex_lock (&app->player.pauseMutex); | |
+ pthread_mutex_lock (&app->player.lock); | |
app->player.doPause = !app->player.doPause; | |
- pthread_cond_broadcast (&app->player.pauseCond); | |
- pthread_mutex_unlock (&app->player.pauseMutex); | |
+ pthread_cond_broadcast (&app->player.cond); | |
+ pthread_mutex_unlock (&app->player.lock); | |
} | |
/* rename current station |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment