From 483414a1373b703c3dc6cc11f03f79b424a1fdb7 Mon Sep 17 00:00:00 2001 From: edward-p Date: Tue, 31 Jul 2018 01:15:16 +0800 Subject: [PATCH 01/11] Rebased on master: add new thread for player --- src/player.c | 215 ++++++++++++++++++++++++++++++++++++++++++--------- src/player.h | 19 +++++ 2 files changed, 198 insertions(+), 36 deletions(-) diff --git a/src/player.c b/src/player.c index ac39e385..15b74c04 100644 --- a/src/player.c +++ b/src/player.c @@ -25,6 +25,7 @@ THE SOFTWARE. #include "config.h" +#include #include #include #include @@ -74,6 +75,9 @@ void BarPlayerInit (player_t * const p, const BarSettings_t * const settings) { pthread_mutex_init (&p->lock, NULL); pthread_cond_init (&p->cond, NULL); + pthread_mutex_init (&p->aoplay_lock, NULL); + pthread_cond_init (&p->aoplay_cond, NULL); + STAILQ_INIT (&p->queue_head); BarPlayerReset (p); p->settings = settings; } @@ -81,6 +85,8 @@ void BarPlayerInit (player_t * const p, const BarSettings_t * const settings) { void BarPlayerDestroy (player_t * const p) { pthread_cond_destroy (&p->cond); pthread_mutex_destroy (&p->lock); + pthread_cond_destroy (&p->aoplay_cond); + pthread_mutex_destroy (&p->aoplay_lock); avformat_network_deinit (); ao_shutdown (); @@ -350,51 +356,61 @@ BarPlayerMode BarPlayerGetMode (player_t * const player) { static int play (player_t * const player) { assert (player != NULL); - AVPacket pkt; + const unsigned int minQueueSize = 256; + pthread_mutex_lock (&player->aoplay_lock); + player->forcePause = true; + player->queueDone = false; + player->queueSize = 0; + pthread_mutex_unlock (&player->aoplay_lock); + pthread_t aoplaythread; + pthread_create (&aoplaythread, NULL, BarAoPlayThread, player); + + AVPacket *pkt = NULL; AVCodecContext * const cctx = player->cctx; - av_init_packet (&pkt); - pkt.data = NULL; - pkt.size = 0; AVFrame *frame = NULL, *filteredFrame = NULL; frame = av_frame_alloc (); assert (frame != NULL); - filteredFrame = av_frame_alloc (); - assert (filteredFrame != NULL); enum { FILL, DRAIN, DONE } drainMode = FILL; int ret = 0; while (!shouldQuit (player) && drainMode != DONE) { + /* alloc queue element for AVPacket */ + struct _QUEUE_ELEMT * pkt_element = + (struct _QUEUE_ELEMT *) calloc (1, sizeof (struct _QUEUE_ELEMT)); + pkt_element->type = AVPACKET; + pkt = pkt_element->data.pkt = av_packet_alloc (); + assert (pkt != NULL); + av_init_packet (pkt); + pkt->data = NULL; + pkt->size = 0; + /* alloc queue element for AVFrame */ + struct _QUEUE_ELEMT * frm_element = + (struct _QUEUE_ELEMT *) calloc (1, sizeof (struct _QUEUE_ELEMT)); + frm_element->type = AVFRAME; + filteredFrame = frm_element->data.frm = av_frame_alloc (); + assert (filteredFrame != NULL); + if (drainMode == FILL) { - ret = av_read_frame (player->fctx, &pkt); + ret = av_read_frame (player->fctx, pkt); if (ret == AVERROR_EOF) { /* enter drain mode */ drainMode = DRAIN; avcodec_send_packet (cctx, NULL); - } else if (pkt.stream_index != player->streamIdx) { + } else if (pkt->stream_index != player->streamIdx) { /* unused packet */ - av_packet_unref (&pkt); + av_packet_unref (pkt); + free (pkt_element); continue; } else if (ret < 0) { /* error, abort */ break; } else { /* fill buffer */ - avcodec_send_packet (cctx, &pkt); + avcodec_send_packet (cctx, pkt); } } - /* pausing */ - pthread_mutex_lock (&player->lock); - if (player->doPause) { - av_read_pause (player->fctx); - do { - pthread_cond_wait (&player->cond, &player->lock); - } while (player->doPause); - av_read_play (player->fctx); - } - pthread_mutex_unlock (&player->lock); - while (!shouldQuit (player)) { ret = avcodec_receive_frame (cctx, frame); if (ret == AVERROR_EOF) { @@ -419,28 +435,47 @@ static int play (player_t * const player) { break; } - const int numChannels = av_get_channel_layout_nb_channels ( - filteredFrame->channel_layout); - const int bps = av_get_bytes_per_sample(filteredFrame->format); - ao_play (player->aoDev, (char *) filteredFrame->data[0], - filteredFrame->nb_samples * numChannels * bps); - - av_frame_unref (filteredFrame); + /*Insert frame for playing*/ + pthread_mutex_lock (&player->aoplay_lock); + STAILQ_INSERT_TAIL (&player->queue_head, frm_element, entry); + player->queueSize++; + if (player->queueSize >= minQueueSize) { + player->forcePause = false; + pthread_cond_broadcast (&player->aoplay_cond); + } + pthread_mutex_unlock (&player->aoplay_lock); + filteredFrame=NULL; } } - const unsigned int songPlayed = av_q2d (player->st->time_base) * (double) pkt.pts; - pthread_mutex_lock (&player->lock); - player->songPlayed = songPlayed; - pthread_mutex_unlock (&player->lock); - player->lastTimestamp = pkt.pts; - - av_packet_unref (&pkt); + /* insert packet for timestamp */ + pthread_mutex_lock (&player->aoplay_lock); + STAILQ_INSERT_TAIL (&player->queue_head, pkt_element, entry); + player->queueSize++; + if (player->queueSize >= minQueueSize) { + player->forcePause = false; + pthread_cond_broadcast (&player->aoplay_cond); + } + pthread_mutex_unlock (&player->aoplay_lock); + pkt = NULL; } - av_frame_free (&filteredFrame); + filteredFrame = NULL; av_frame_free (&frame); + /* insert EOF */ + if (drainMode == DONE) { + struct _QUEUE_ELEMT * eof_element = + (struct _QUEUE_ELEMT *) calloc (1, sizeof (struct _QUEUE_ELEMT)); + eof_element->type = QUEUE_EOF; + pthread_mutex_lock (&player->aoplay_lock); + player->queueDone = true; + pthread_cond_broadcast (&player->aoplay_cond); + STAILQ_INSERT_TAIL (&player->queue_head, eof_element, entry); + pthread_mutex_unlock (&player->aoplay_lock); + } + pthread_join (aoplaythread, NULL); + return ret; } @@ -496,3 +531,111 @@ void *BarPlayerThread (void *data) { return (void *) pret; } +void *BarAoPlayThread (void *data) { + assert (data != NULL); + + player_t *const player = data; + + AVFrame *frm = NULL; + AVPacket *pkt = NULL; + + bool quit = false; + + while (!shouldQuit (player) && !quit) { + struct _QUEUE_ELEMT * queue_element = NULL; + while (!shouldQuit (player) && !quit && queue_element == NULL) { + + /* force pausing until the queue size get 256 or decoding is done*/ + pthread_mutex_lock (&player->aoplay_lock); + if (player->forcePause && !player->queueDone) { + do { + pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); + } while (player->forcePause && !player->queueDone); + } + pthread_mutex_unlock (&player->aoplay_lock); + + /* pausing by user*/ + pthread_mutex_lock (&player->lock); + if (player->doPause) { + av_read_pause (player->fctx); + do { + pthread_cond_wait (&player->cond, &player->lock); + } while (player->doPause); + av_read_play (player->fctx); + } + pthread_mutex_unlock (&player->lock); + + pthread_mutex_lock (&player->aoplay_lock); + queue_element = STAILQ_FIRST (&player->queue_head); + pthread_mutex_unlock (&player->aoplay_lock); + } + + if (queue_element == NULL) { + break; + } + + int numChannels; + int bps; + unsigned int songPlayed; + switch (queue_element->type) { + case AVFRAME: + frm = queue_element->data.frm; + numChannels = av_get_channel_layout_nb_channels (frm->channel_layout); + bps = av_get_bytes_per_sample (frm->format); + ao_play (player->aoDev, (char *) frm->data[0], + frm->nb_samples * numChannels * bps); + av_frame_free (&frm); + frm = NULL; + break; + case AVPACKET: + pkt = queue_element->data.pkt; + songPlayed = av_q2d (player->st->time_base) * (double) pkt->pts; + pthread_mutex_lock (&player->lock); + player->songPlayed = songPlayed; + pthread_mutex_unlock (&player->lock); + player->lastTimestamp = pkt->pts; + + av_packet_free (&pkt); + pkt = NULL; + + break; + case QUEUE_EOF: + quit = true; + break; + } + pthread_mutex_lock (&player->aoplay_lock); + STAILQ_REMOVE_HEAD (&player->queue_head, entry); + player->queueSize--; + if (player->queueSize == 0) + player->forcePause = true; + pthread_mutex_unlock (&player->aoplay_lock); + free (queue_element); + } + + /*Clear the queue*/ + while (!STAILQ_EMPTY (&player->queue_head)) { + struct _QUEUE_ELEMT * queue_element = STAILQ_FIRST (&player->queue_head); + switch (queue_element->type) { + case AVFRAME: + frm = queue_element->data.frm; + av_frame_free (&frm); + frm = NULL; + break; + case AVPACKET: + pkt = queue_element->data.pkt; + av_packet_free (&pkt); + pkt = NULL; + break; + case QUEUE_EOF: + /* nothing need to do here*/ + break; + } + pthread_mutex_lock (&player->aoplay_lock); + STAILQ_REMOVE_HEAD (&player->queue_head, entry); + pthread_mutex_unlock (&player->aoplay_lock); + + free (queue_element); + queue_element = NULL; + } + return (void *) 0; +} diff --git a/src/player.h b/src/player.h index e9482c42..f501c0cb 100644 --- a/src/player.h +++ b/src/player.h @@ -25,6 +25,7 @@ THE SOFTWARE. #include "config.h" +#include /* required for freebsd */ #include #include @@ -49,6 +50,16 @@ typedef enum { PLAYER_FINISHED, } BarPlayerMode; +struct _QUEUE_ELEMT { + STAILQ_ENTRY(_QUEUE_ELEMT) entry; + /*The element could be an AVFrame or an AVPacket or a QUEUE_EOF*/ + enum { AVFRAME, AVPACKET, QUEUE_EOF } type; + union { + AVFrame * frm; + AVPacket * pkt; + } data; +}; + typedef struct { /* public attributes protected by mutex */ pthread_mutex_t lock; @@ -62,6 +73,13 @@ typedef struct { BarPlayerMode mode; + pthread_mutex_t aoplay_lock; + pthread_cond_t aoplay_cond; + /*queue head*/ + STAILQ_HEAD (_QUEUE_ELEMT_head, _QUEUE_ELEMT) queue_head; + unsigned int queueSize; + bool forcePause, queueDone; + /* private attributes _not_ protected by mutex */ /* libav */ @@ -86,6 +104,7 @@ typedef struct { enum {PLAYER_RET_OK = 0, PLAYER_RET_HARDFAIL = 1, PLAYER_RET_SOFTFAIL = 2}; void *BarPlayerThread (void *data); +void *BarAoPlayThread(void *data); void BarPlayerSetVolume (player_t * const player); void BarPlayerInit (player_t * const p, const BarSettings_t * const settings); void BarPlayerReset (player_t * const p); From 73007e15b0efb6c20531dcd9650eeb23b64754bf Mon Sep 17 00:00:00 2001 From: edward-p Date: Tue, 31 Jul 2018 17:37:54 +0800 Subject: [PATCH 02/11] fix cannot skip song caused by force pause --- src/ui_act.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ui_act.c b/src/ui_act.c index d112749e..81bd0c6f 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -57,6 +57,10 @@ static inline void BarUiDoSkipSong (player_t * const player) { player->doPause = false; pthread_cond_broadcast (&player->cond); pthread_mutex_unlock (&player->lock); + pthread_mutex_lock (&player->aoplay_lock); + player->forcePause=false; + pthread_cond_broadcast (&player->aoplay_cond); + pthread_mutex_unlock (&player->aoplay_lock); } /* transform station if necessary to allow changes like rename, rate, ... From 8aa3e88ea894ac0b829e128a308b64cd911bc607 Mon Sep 17 00:00:00 2001 From: edward-p Date: Tue, 7 Aug 2018 15:48:04 +0800 Subject: [PATCH 03/11] use av_buffer instead of TAILQ --- src/player.c | 220 +++++++++++++-------------------------------------- src/player.h | 25 +----- src/ui_act.c | 4 - 3 files changed, 57 insertions(+), 192 deletions(-) diff --git a/src/player.c b/src/player.c index 15b74c04..bc39b14c 100644 --- a/src/player.c +++ b/src/player.c @@ -25,7 +25,6 @@ THE SOFTWARE. #include "config.h" -#include #include #include #include @@ -77,7 +76,6 @@ void BarPlayerInit (player_t * const p, const BarSettings_t * const settings) { pthread_cond_init (&p->cond, NULL); pthread_mutex_init (&p->aoplay_lock, NULL); pthread_cond_init (&p->aoplay_cond, NULL); - STAILQ_INIT (&p->queue_head); BarPlayerReset (p); p->settings = settings; } @@ -356,58 +354,36 @@ BarPlayerMode BarPlayerGetMode (player_t * const player) { static int play (player_t * const player) { assert (player != NULL); - const unsigned int minQueueSize = 256; - pthread_mutex_lock (&player->aoplay_lock); - player->forcePause = true; - player->queueDone = false; - player->queueSize = 0; - pthread_mutex_unlock (&player->aoplay_lock); - pthread_t aoplaythread; - pthread_create (&aoplaythread, NULL, BarAoPlayThread, player); - - AVPacket *pkt = NULL; + AVPacket pkt; AVCodecContext * const cctx = player->cctx; + av_init_packet (&pkt); + pkt.data = NULL; + pkt.size = 0; - AVFrame *frame = NULL, *filteredFrame = NULL; + AVFrame *frame = NULL; frame = av_frame_alloc (); assert (frame != NULL); - + pthread_t aoplaythread; + pthread_create (&aoplaythread, NULL, BarAoPlayThread, player); enum { FILL, DRAIN, DONE } drainMode = FILL; int ret = 0; while (!shouldQuit (player) && drainMode != DONE) { - /* alloc queue element for AVPacket */ - struct _QUEUE_ELEMT * pkt_element = - (struct _QUEUE_ELEMT *) calloc (1, sizeof (struct _QUEUE_ELEMT)); - pkt_element->type = AVPACKET; - pkt = pkt_element->data.pkt = av_packet_alloc (); - assert (pkt != NULL); - av_init_packet (pkt); - pkt->data = NULL; - pkt->size = 0; - /* alloc queue element for AVFrame */ - struct _QUEUE_ELEMT * frm_element = - (struct _QUEUE_ELEMT *) calloc (1, sizeof (struct _QUEUE_ELEMT)); - frm_element->type = AVFRAME; - filteredFrame = frm_element->data.frm = av_frame_alloc (); - assert (filteredFrame != NULL); - if (drainMode == FILL) { - ret = av_read_frame (player->fctx, pkt); + ret = av_read_frame (player->fctx, &pkt); if (ret == AVERROR_EOF) { /* enter drain mode */ drainMode = DRAIN; avcodec_send_packet (cctx, NULL); - } else if (pkt->stream_index != player->streamIdx) { + } else if (pkt.stream_index != player->streamIdx) { /* unused packet */ - av_packet_unref (pkt); - free (pkt_element); + av_packet_unref (&pkt); continue; } else if (ret < 0) { /* error, abort */ break; } else { /* fill buffer */ - avcodec_send_packet (cctx, pkt); + avcodec_send_packet (cctx, &pkt); } } @@ -416,6 +392,9 @@ static int play (player_t * const player) { if (ret == AVERROR_EOF) { /* done draining */ drainMode = DONE; + /* mark the EOF*/ + int rt = av_buffersrc_add_frame (player->fabuf, NULL); + assert( rt == 0); break; } else if (ret != 0) { /* no more output */ @@ -428,52 +407,14 @@ static int play (player_t * const player) { } ret = av_buffersrc_write_frame (player->fabuf, frame); assert (ret >= 0); - - while (true) { - if (av_buffersink_get_frame (player->fbufsink, filteredFrame) < 0) { - /* try again next frame */ - break; - } - - /*Insert frame for playing*/ - pthread_mutex_lock (&player->aoplay_lock); - STAILQ_INSERT_TAIL (&player->queue_head, frm_element, entry); - player->queueSize++; - if (player->queueSize >= minQueueSize) { - player->forcePause = false; - pthread_cond_broadcast (&player->aoplay_cond); - } - pthread_mutex_unlock (&player->aoplay_lock); - filteredFrame=NULL; - } - } - - /* insert packet for timestamp */ - pthread_mutex_lock (&player->aoplay_lock); - STAILQ_INSERT_TAIL (&player->queue_head, pkt_element, entry); - player->queueSize++; - if (player->queueSize >= minQueueSize) { - player->forcePause = false; + pthread_mutex_lock (&player->aoplay_lock); pthread_cond_broadcast (&player->aoplay_cond); + pthread_mutex_unlock (&player->aoplay_lock); } - pthread_mutex_unlock (&player->aoplay_lock); - pkt = NULL; - } - filteredFrame = NULL; - av_frame_free (&frame); - - /* insert EOF */ - if (drainMode == DONE) { - struct _QUEUE_ELEMT * eof_element = - (struct _QUEUE_ELEMT *) calloc (1, sizeof (struct _QUEUE_ELEMT)); - eof_element->type = QUEUE_EOF; - pthread_mutex_lock (&player->aoplay_lock); - player->queueDone = true; - pthread_cond_broadcast (&player->aoplay_cond); - STAILQ_INSERT_TAIL (&player->queue_head, eof_element, entry); - pthread_mutex_unlock (&player->aoplay_lock); + av_packet_unref (&pkt); } + av_frame_free (&frame); pthread_join (aoplaythread, NULL); return ret; @@ -534,108 +475,55 @@ void *BarPlayerThread (void *data) { void *BarAoPlayThread (void *data) { assert (data != NULL); - player_t *const player = data; + player_t * const player = data; - AVFrame *frm = NULL; - AVPacket *pkt = NULL; + AVFrame *filteredFrame = NULL; + filteredFrame = av_frame_alloc (); + assert (filteredFrame != NULL); bool quit = false; - - while (!shouldQuit (player) && !quit) { - struct _QUEUE_ELEMT * queue_element = NULL; - while (!shouldQuit (player) && !quit && queue_element == NULL) { - - /* force pausing until the queue size get 256 or decoding is done*/ - pthread_mutex_lock (&player->aoplay_lock); - if (player->forcePause && !player->queueDone) { - do { - pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); - } while (player->forcePause && !player->queueDone); - } - pthread_mutex_unlock (&player->aoplay_lock); - - /* pausing by user*/ - pthread_mutex_lock (&player->lock); - if (player->doPause) { - av_read_pause (player->fctx); - do { - pthread_cond_wait (&player->cond, &player->lock); - } while (player->doPause); - av_read_play (player->fctx); + int ret; + while (true) { + while ((ret = av_buffersink_get_frame (player->fbufsink, filteredFrame)) < 0) { + if (ret == AVERROR_EOF){ + quit=true; + break; } - pthread_mutex_unlock (&player->lock); - - pthread_mutex_lock (&player->aoplay_lock); - queue_element = STAILQ_FIRST (&player->queue_head); + /* wait for more frames */ + pthread_mutex_lock (&player->aoplay_lock); + pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); pthread_mutex_unlock (&player->aoplay_lock); } - if (queue_element == NULL) { + if (shouldQuit(player) || quit){ break; } - int numChannels; - int bps; - unsigned int songPlayed; - switch (queue_element->type) { - case AVFRAME: - frm = queue_element->data.frm; - numChannels = av_get_channel_layout_nb_channels (frm->channel_layout); - bps = av_get_bytes_per_sample (frm->format); - ao_play (player->aoDev, (char *) frm->data[0], - frm->nb_samples * numChannels * bps); - av_frame_free (&frm); - frm = NULL; - break; - case AVPACKET: - pkt = queue_element->data.pkt; - songPlayed = av_q2d (player->st->time_base) * (double) pkt->pts; - pthread_mutex_lock (&player->lock); - player->songPlayed = songPlayed; - pthread_mutex_unlock (&player->lock); - player->lastTimestamp = pkt->pts; - - av_packet_free (&pkt); - pkt = NULL; - - break; - case QUEUE_EOF: - quit = true; - break; + /* pausing */ + pthread_mutex_lock (&player->lock); + if (player->doPause) { + do { + pthread_cond_wait (&player->cond, &player->lock); + } while (player->doPause); } - pthread_mutex_lock (&player->aoplay_lock); - STAILQ_REMOVE_HEAD (&player->queue_head, entry); - player->queueSize--; - if (player->queueSize == 0) - player->forcePause = true; - pthread_mutex_unlock (&player->aoplay_lock); - free (queue_element); - } + pthread_mutex_unlock (&player->lock); - /*Clear the queue*/ - while (!STAILQ_EMPTY (&player->queue_head)) { - struct _QUEUE_ELEMT * queue_element = STAILQ_FIRST (&player->queue_head); - switch (queue_element->type) { - case AVFRAME: - frm = queue_element->data.frm; - av_frame_free (&frm); - frm = NULL; - break; - case AVPACKET: - pkt = queue_element->data.pkt; - av_packet_free (&pkt); - pkt = NULL; - break; - case QUEUE_EOF: - /* nothing need to do here*/ - break; - } - pthread_mutex_lock (&player->aoplay_lock); - STAILQ_REMOVE_HEAD (&player->queue_head, entry); - pthread_mutex_unlock (&player->aoplay_lock); + const int numChannels = av_get_channel_layout_nb_channels ( + filteredFrame->channel_layout); + const int bps = av_get_bytes_per_sample(filteredFrame->format); + ao_play (player->aoDev, (char *) filteredFrame->data[0], + filteredFrame->nb_samples * numChannels * bps); - free (queue_element); - queue_element = NULL; + const unsigned int songPlayed = av_q2d (player->st->time_base) * + (double) filteredFrame->pts; + pthread_mutex_lock (&player->lock); + player->songPlayed = songPlayed; + pthread_mutex_unlock (&player->lock); + player->lastTimestamp = filteredFrame->pts; + + av_frame_unref (filteredFrame); } + av_frame_free (&filteredFrame); + return (void *) 0; } diff --git a/src/player.h b/src/player.h index f501c0cb..0a8d496d 100644 --- a/src/player.h +++ b/src/player.h @@ -25,7 +25,6 @@ THE SOFTWARE. #include "config.h" -#include /* required for freebsd */ #include #include @@ -50,21 +49,10 @@ typedef enum { PLAYER_FINISHED, } BarPlayerMode; -struct _QUEUE_ELEMT { - STAILQ_ENTRY(_QUEUE_ELEMT) entry; - /*The element could be an AVFrame or an AVPacket or a QUEUE_EOF*/ - enum { AVFRAME, AVPACKET, QUEUE_EOF } type; - union { - AVFrame * frm; - AVPacket * pkt; - } data; -}; - typedef struct { /* public attributes protected by mutex */ - pthread_mutex_t lock; - pthread_cond_t cond; /* broadcast changes to doPause */ - + pthread_mutex_t lock, aoplay_lock; + pthread_cond_t cond, aoplay_cond; /* broadcast changes to doPause */ bool doQuit, doPause; /* measured in seconds */ @@ -73,13 +61,6 @@ typedef struct { BarPlayerMode mode; - pthread_mutex_t aoplay_lock; - pthread_cond_t aoplay_cond; - /*queue head*/ - STAILQ_HEAD (_QUEUE_ELEMT_head, _QUEUE_ELEMT) queue_head; - unsigned int queueSize; - bool forcePause, queueDone; - /* private attributes _not_ protected by mutex */ /* libav */ @@ -104,7 +85,7 @@ typedef struct { enum {PLAYER_RET_OK = 0, PLAYER_RET_HARDFAIL = 1, PLAYER_RET_SOFTFAIL = 2}; void *BarPlayerThread (void *data); -void *BarAoPlayThread(void *data); +void *BarAoPlayThread (void *data); void BarPlayerSetVolume (player_t * const player); void BarPlayerInit (player_t * const p, const BarSettings_t * const settings); void BarPlayerReset (player_t * const p); diff --git a/src/ui_act.c b/src/ui_act.c index 81bd0c6f..d112749e 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -57,10 +57,6 @@ static inline void BarUiDoSkipSong (player_t * const player) { player->doPause = false; pthread_cond_broadcast (&player->cond); pthread_mutex_unlock (&player->lock); - pthread_mutex_lock (&player->aoplay_lock); - player->forcePause=false; - pthread_cond_broadcast (&player->aoplay_cond); - pthread_mutex_unlock (&player->aoplay_lock); } /* transform station if necessary to allow changes like rename, rate, ... From 051613a0e1580f3ef5f8dfa8189eb93ccffea315 Mon Sep 17 00:00:00 2001 From: edward-p Date: Wed, 8 Aug 2018 14:13:24 +0800 Subject: [PATCH 04/11] add mutex to protect fbuf --- src/player.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/player.c b/src/player.c index bc39b14c..7b463876 100644 --- a/src/player.c +++ b/src/player.c @@ -393,8 +393,11 @@ static int play (player_t * const player) { /* done draining */ drainMode = DONE; /* mark the EOF*/ + pthread_mutex_lock (&player->aoplay_lock); int rt = av_buffersrc_add_frame (player->fabuf, NULL); assert( rt == 0); + pthread_cond_broadcast (&player->aoplay_cond); + pthread_mutex_unlock (&player->aoplay_lock); break; } else if (ret != 0) { /* no more output */ @@ -405,9 +408,9 @@ static int play (player_t * const player) { if (frame->pts == (int64_t) AV_NOPTS_VALUE) { frame->pts = 0; } + pthread_mutex_lock (&player->aoplay_lock); ret = av_buffersrc_write_frame (player->fabuf, frame); assert (ret >= 0); - pthread_mutex_lock (&player->aoplay_lock); pthread_cond_broadcast (&player->aoplay_cond); pthread_mutex_unlock (&player->aoplay_lock); } @@ -484,15 +487,21 @@ void *BarAoPlayThread (void *data) { bool quit = false; int ret; while (true) { - while ((ret = av_buffersink_get_frame (player->fbufsink, filteredFrame)) < 0) { - if (ret == AVERROR_EOF){ - quit=true; - break; - } - /* wait for more frames */ - pthread_mutex_lock (&player->aoplay_lock); - pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplay_lock); + ret = av_buffersink_get_frame (player->fbufsink, filteredFrame); + pthread_mutex_unlock (&player->aoplay_lock); + if ( ret < 0) { + do { + if (ret == AVERROR_EOF){ + quit=true; + break; + } + /* wait for more frames */ + pthread_mutex_lock (&player->aoplay_lock); + pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); + ret = av_buffersink_get_frame (player->fbufsink, filteredFrame); + pthread_mutex_unlock (&player->aoplay_lock); + } while (ret < 0); } if (shouldQuit(player) || quit){ From 97fc1a1c089b3aafc1d299fccd11617e33ac8944 Mon Sep 17 00:00:00 2001 From: edward-p Date: Thu, 9 Aug 2018 13:08:12 +0800 Subject: [PATCH 05/11] simplify the loop and fix DoSkipSong --- src/player.c | 25 +++++++++---------------- src/ui_act.c | 4 +++- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/player.c b/src/player.c index 7b463876..1478d10b 100644 --- a/src/player.c +++ b/src/player.c @@ -484,30 +484,23 @@ void *BarAoPlayThread (void *data) { filteredFrame = av_frame_alloc (); assert (filteredFrame != NULL); - bool quit = false; int ret; - while (true) { + while (!shouldQuit(player)) { pthread_mutex_lock (&player->aoplay_lock); ret = av_buffersink_get_frame (player->fbufsink, filteredFrame); pthread_mutex_unlock (&player->aoplay_lock); - if ( ret < 0) { - do { - if (ret == AVERROR_EOF){ - quit=true; - break; - } - /* wait for more frames */ - pthread_mutex_lock (&player->aoplay_lock); - pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); - ret = av_buffersink_get_frame (player->fbufsink, filteredFrame); - pthread_mutex_unlock (&player->aoplay_lock); - } while (ret < 0); - } - if (shouldQuit(player) || quit){ + if ( !shouldQuit(player) && ret < 0 && ret != AVERROR_EOF) { + /* wait for more frames */ + pthread_mutex_lock (&player->aoplay_lock); + pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); + pthread_mutex_unlock (&player->aoplay_lock); + continue; + } else if (ret == AVERROR_EOF || shouldQuit(player)){ break; } + /* pausing */ pthread_mutex_lock (&player->lock); if (player->doPause) { diff --git a/src/ui_act.c b/src/ui_act.c index d112749e..5f0d8d25 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -57,6 +57,9 @@ static inline void BarUiDoSkipSong (player_t * const player) { player->doPause = false; pthread_cond_broadcast (&player->cond); pthread_mutex_unlock (&player->lock); + pthread_mutex_lock (&player->aoplay_lock); + pthread_cond_broadcast (&player->aoplay_cond); + pthread_mutex_unlock (&player->aoplay_lock); } /* transform station if necessary to allow changes like rename, rate, ... @@ -881,4 +884,3 @@ BarUiActCallback(BarUiActManageStation) { PianoDestroyStationInfo (&reqData.info); } - From 63b3bac711ade18e463310a05489a59cbe6d7a1b Mon Sep 17 00:00:00 2001 From: edward-p Date: Sat, 11 Aug 2018 14:51:03 +0800 Subject: [PATCH 06/11] fix BarAoPlayThread won't quit when network issue happend --- src/player.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/player.c b/src/player.c index 1478d10b..84dc05d8 100644 --- a/src/player.c +++ b/src/player.c @@ -380,6 +380,12 @@ static int play (player_t * const player) { continue; } else if (ret < 0) { /* error, abort */ + /* mark the EOF, so that BarAoPlayThread can quit*/ + pthread_mutex_lock (&player->aoplay_lock); + int rt = av_buffersrc_add_frame (player->fabuf, NULL); + assert( rt == 0); + pthread_cond_broadcast (&player->aoplay_cond); + pthread_mutex_unlock (&player->aoplay_lock); break; } else { /* fill buffer */ From 3aa660ddb5ac69480ee31ebe3e2c76df463e915c Mon Sep 17 00:00:00 2001 From: edward-p Date: Tue, 21 Aug 2018 19:57:51 +0800 Subject: [PATCH 07/11] bound buffer size by timestamp --- src/player.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/player.c b/src/player.c index 84dc05d8..069d5a70 100644 --- a/src/player.c +++ b/src/player.c @@ -365,6 +365,7 @@ static int play (player_t * const player) { assert (frame != NULL); pthread_t aoplaythread; pthread_create (&aoplaythread, NULL, BarAoPlayThread, player); + int64_t buffer_health = 0; enum { FILL, DRAIN, DONE } drainMode = FILL; int ret = 0; while (!shouldQuit (player) && drainMode != DONE) { @@ -419,6 +420,17 @@ static int play (player_t * const player) { assert (ret >= 0); pthread_cond_broadcast (&player->aoplay_cond); pthread_mutex_unlock (&player->aoplay_lock); + + do { + pthread_mutex_lock (&player->aoplay_lock); + buffer_health = av_q2d (player->st->time_base) * + (double) (frame->pts - player->lastTimestamp); + if (buffer_health > 4){ + /* Buffer is healthy enough, wait */ + pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); + } + pthread_mutex_unlock (&player->aoplay_lock); + } while(buffer_health > 4); } av_packet_unref (&pkt); @@ -527,7 +539,11 @@ void *BarAoPlayThread (void *data) { pthread_mutex_lock (&player->lock); player->songPlayed = songPlayed; pthread_mutex_unlock (&player->lock); + + pthread_mutex_lock (&player->aoplay_lock); player->lastTimestamp = filteredFrame->pts; + pthread_cond_broadcast (&player->aoplay_cond); + pthread_mutex_unlock (&player->aoplay_lock); av_frame_unref (filteredFrame); } From 44cf51bbd4494892b399f5bf59bffc667aa756dd Mon Sep 17 00:00:00 2001 From: edward-p Date: Tue, 21 Aug 2018 20:10:43 +0800 Subject: [PATCH 08/11] do pausing behind ao_play --- src/player.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/player.c b/src/player.c index 069d5a70..437966af 100644 --- a/src/player.c +++ b/src/player.c @@ -518,16 +518,6 @@ void *BarAoPlayThread (void *data) { break; } - - /* pausing */ - pthread_mutex_lock (&player->lock); - if (player->doPause) { - do { - pthread_cond_wait (&player->cond, &player->lock); - } while (player->doPause); - } - pthread_mutex_unlock (&player->lock); - const int numChannels = av_get_channel_layout_nb_channels ( filteredFrame->channel_layout); const int bps = av_get_bytes_per_sample(filteredFrame->format); @@ -540,6 +530,15 @@ void *BarAoPlayThread (void *data) { player->songPlayed = songPlayed; pthread_mutex_unlock (&player->lock); + /* pausing */ + pthread_mutex_lock (&player->lock); + if (player->doPause) { + do { + pthread_cond_wait (&player->cond, &player->lock); + } while (player->doPause); + } + pthread_mutex_unlock (&player->lock); + pthread_mutex_lock (&player->aoplay_lock); player->lastTimestamp = filteredFrame->pts; pthread_cond_broadcast (&player->aoplay_cond); From c60dadcde01996a64e1bd909b58e975a51207e76 Mon Sep 17 00:00:00 2001 From: edward-p Date: Wed, 29 Aug 2018 23:38:28 +0800 Subject: [PATCH 09/11] resume only when buffer get healthy --- src/player.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/player.c b/src/player.c index 437966af..f78ea37f 100644 --- a/src/player.c +++ b/src/player.c @@ -418,7 +418,6 @@ static int play (player_t * const player) { pthread_mutex_lock (&player->aoplay_lock); ret = av_buffersrc_write_frame (player->fabuf, frame); assert (ret >= 0); - pthread_cond_broadcast (&player->aoplay_cond); pthread_mutex_unlock (&player->aoplay_lock); do { @@ -426,6 +425,8 @@ static int play (player_t * const player) { buffer_health = av_q2d (player->st->time_base) * (double) (frame->pts - player->lastTimestamp); if (buffer_health > 4){ + /* Buffer get healthy, resume */ + pthread_cond_broadcast (&player->aoplay_cond); /* Buffer is healthy enough, wait */ pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); } From 013adf28f644f06efba6bc20006b37e2584da97a Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sat, 15 Sep 2018 10:02:05 +0200 Subject: [PATCH 10/11] CamelCase variables --- src/player.c | 56 ++++++++++++++++++++++++++-------------------------- src/player.h | 4 ++-- src/ui_act.c | 6 +++--- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/player.c b/src/player.c index f78ea37f..021aa4fd 100644 --- a/src/player.c +++ b/src/player.c @@ -74,8 +74,8 @@ void BarPlayerInit (player_t * const p, const BarSettings_t * const settings) { pthread_mutex_init (&p->lock, NULL); pthread_cond_init (&p->cond, NULL); - pthread_mutex_init (&p->aoplay_lock, NULL); - pthread_cond_init (&p->aoplay_cond, NULL); + pthread_mutex_init (&p->aoplayLock, NULL); + pthread_cond_init (&p->aoplayCond, NULL); BarPlayerReset (p); p->settings = settings; } @@ -83,8 +83,8 @@ void BarPlayerInit (player_t * const p, const BarSettings_t * const settings) { void BarPlayerDestroy (player_t * const p) { pthread_cond_destroy (&p->cond); pthread_mutex_destroy (&p->lock); - pthread_cond_destroy (&p->aoplay_cond); - pthread_mutex_destroy (&p->aoplay_lock); + pthread_cond_destroy (&p->aoplayCond); + pthread_mutex_destroy (&p->aoplayLock); avformat_network_deinit (); ao_shutdown (); @@ -365,7 +365,6 @@ static int play (player_t * const player) { assert (frame != NULL); pthread_t aoplaythread; pthread_create (&aoplaythread, NULL, BarAoPlayThread, player); - int64_t buffer_health = 0; enum { FILL, DRAIN, DONE } drainMode = FILL; int ret = 0; while (!shouldQuit (player) && drainMode != DONE) { @@ -382,11 +381,11 @@ static int play (player_t * const player) { } else if (ret < 0) { /* error, abort */ /* mark the EOF, so that BarAoPlayThread can quit*/ - pthread_mutex_lock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); int rt = av_buffersrc_add_frame (player->fabuf, NULL); assert( rt == 0); - pthread_cond_broadcast (&player->aoplay_cond); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_cond_broadcast (&player->aoplayCond); + pthread_mutex_unlock (&player->aoplayLock); break; } else { /* fill buffer */ @@ -400,11 +399,11 @@ static int play (player_t * const player) { /* done draining */ drainMode = DONE; /* mark the EOF*/ - pthread_mutex_lock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); int rt = av_buffersrc_add_frame (player->fabuf, NULL); assert( rt == 0); - pthread_cond_broadcast (&player->aoplay_cond); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_cond_broadcast (&player->aoplayCond); + pthread_mutex_unlock (&player->aoplayLock); break; } else if (ret != 0) { /* no more output */ @@ -415,23 +414,24 @@ static int play (player_t * const player) { if (frame->pts == (int64_t) AV_NOPTS_VALUE) { frame->pts = 0; } - pthread_mutex_lock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); ret = av_buffersrc_write_frame (player->fabuf, frame); assert (ret >= 0); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_mutex_unlock (&player->aoplayLock); + int64_t bufferHealth = 0; do { - pthread_mutex_lock (&player->aoplay_lock); - buffer_health = av_q2d (player->st->time_base) * + pthread_mutex_lock (&player->aoplayLock); + bufferHealth = av_q2d (player->st->time_base) * (double) (frame->pts - player->lastTimestamp); - if (buffer_health > 4){ + if (bufferHealth > 4){ /* Buffer get healthy, resume */ - pthread_cond_broadcast (&player->aoplay_cond); + pthread_cond_broadcast (&player->aoplayCond); /* Buffer is healthy enough, wait */ - pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); + pthread_cond_wait (&player->aoplayCond, &player->aoplayLock); } - pthread_mutex_unlock (&player->aoplay_lock); - } while(buffer_health > 4); + pthread_mutex_unlock (&player->aoplayLock); + } while(bufferHealth > 4); } av_packet_unref (&pkt); @@ -505,15 +505,15 @@ void *BarAoPlayThread (void *data) { int ret; while (!shouldQuit(player)) { - pthread_mutex_lock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); ret = av_buffersink_get_frame (player->fbufsink, filteredFrame); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_mutex_unlock (&player->aoplayLock); if ( !shouldQuit(player) && ret < 0 && ret != AVERROR_EOF) { /* wait for more frames */ - pthread_mutex_lock (&player->aoplay_lock); - pthread_cond_wait (&player->aoplay_cond, &player->aoplay_lock); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); + pthread_cond_wait (&player->aoplayCond, &player->aoplayLock); + pthread_mutex_unlock (&player->aoplayLock); continue; } else if (ret == AVERROR_EOF || shouldQuit(player)){ break; @@ -540,10 +540,10 @@ void *BarAoPlayThread (void *data) { } pthread_mutex_unlock (&player->lock); - pthread_mutex_lock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); player->lastTimestamp = filteredFrame->pts; - pthread_cond_broadcast (&player->aoplay_cond); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_cond_broadcast (&player->aoplayCond); + pthread_mutex_unlock (&player->aoplayLock); av_frame_unref (filteredFrame); } diff --git a/src/player.h b/src/player.h index 0a8d496d..31797850 100644 --- a/src/player.h +++ b/src/player.h @@ -51,8 +51,8 @@ typedef enum { typedef struct { /* public attributes protected by mutex */ - pthread_mutex_t lock, aoplay_lock; - pthread_cond_t cond, aoplay_cond; /* broadcast changes to doPause */ + pthread_mutex_t lock, aoplayLock; + pthread_cond_t cond, aoplayCond; /* broadcast changes to doPause */ bool doQuit, doPause; /* measured in seconds */ diff --git a/src/ui_act.c b/src/ui_act.c index 5f0d8d25..fc00c010 100644 --- a/src/ui_act.c +++ b/src/ui_act.c @@ -57,9 +57,9 @@ static inline void BarUiDoSkipSong (player_t * const player) { player->doPause = false; pthread_cond_broadcast (&player->cond); pthread_mutex_unlock (&player->lock); - pthread_mutex_lock (&player->aoplay_lock); - pthread_cond_broadcast (&player->aoplay_cond); - pthread_mutex_unlock (&player->aoplay_lock); + pthread_mutex_lock (&player->aoplayLock); + pthread_cond_broadcast (&player->aoplayCond); + pthread_mutex_unlock (&player->aoplayLock); } /* transform station if necessary to allow changes like rename, rate, ... From d7b7e81990eca13f719a76c87272e28ddb7829ce Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sat, 15 Sep 2018 11:32:49 +0200 Subject: [PATCH 11/11] Fix coding style, add comments --- src/player.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/player.c b/src/player.c index 021aa4fd..ff1f1c9b 100644 --- a/src/player.c +++ b/src/player.c @@ -21,7 +21,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/* receive/play audio stream */ +/* receive/play audio stream. + * + * There are two threads involved here: + * BarPlayerThread + * Sets up the stream and fetches the data into a ffmpeg buffersrc + * BarAoPlayThread + * Reads data from the filter chain’s sink and hands it over to libao for + * playback. + * + */ #include "config.h" @@ -382,8 +391,8 @@ static int play (player_t * const player) { /* error, abort */ /* mark the EOF, so that BarAoPlayThread can quit*/ pthread_mutex_lock (&player->aoplayLock); - int rt = av_buffersrc_add_frame (player->fabuf, NULL); - assert( rt == 0); + const int rt = av_buffersrc_add_frame (player->fabuf, NULL); + assert (rt == 0); pthread_cond_broadcast (&player->aoplayCond); pthread_mutex_unlock (&player->aoplayLock); break; @@ -400,8 +409,8 @@ static int play (player_t * const player) { drainMode = DONE; /* mark the EOF*/ pthread_mutex_lock (&player->aoplayLock); - int rt = av_buffersrc_add_frame (player->fabuf, NULL); - assert( rt == 0); + const int rt = av_buffersrc_add_frame (player->fabuf, NULL); + assert (rt == 0); pthread_cond_broadcast (&player->aoplayCond); pthread_mutex_unlock (&player->aoplayLock); break; @@ -420,18 +429,19 @@ static int play (player_t * const player) { pthread_mutex_unlock (&player->aoplayLock); int64_t bufferHealth = 0; + const int64_t minBufferHealth = 4; /* in seconds */ do { pthread_mutex_lock (&player->aoplayLock); bufferHealth = av_q2d (player->st->time_base) * (double) (frame->pts - player->lastTimestamp); - if (bufferHealth > 4){ + if (bufferHealth > minBufferHealth) { /* Buffer get healthy, resume */ pthread_cond_broadcast (&player->aoplayCond); /* Buffer is healthy enough, wait */ pthread_cond_wait (&player->aoplayCond, &player->aoplayLock); } pthread_mutex_unlock (&player->aoplayLock); - } while(bufferHealth > 4); + } while (bufferHealth > minBufferHealth); } av_packet_unref (&pkt); @@ -507,21 +517,21 @@ void *BarAoPlayThread (void *data) { while (!shouldQuit(player)) { pthread_mutex_lock (&player->aoplayLock); ret = av_buffersink_get_frame (player->fbufsink, filteredFrame); - pthread_mutex_unlock (&player->aoplayLock); - - if ( !shouldQuit(player) && ret < 0 && ret != AVERROR_EOF) { + if (ret == AVERROR_EOF || shouldQuit (player)) { + /* we are done here */ + pthread_mutex_unlock (&player->aoplayLock); + break; + } else if (ret < 0) { /* wait for more frames */ - pthread_mutex_lock (&player->aoplayLock); pthread_cond_wait (&player->aoplayCond, &player->aoplayLock); pthread_mutex_unlock (&player->aoplayLock); continue; - } else if (ret == AVERROR_EOF || shouldQuit(player)){ - break; } + pthread_mutex_unlock (&player->aoplayLock); const int numChannels = av_get_channel_layout_nb_channels ( filteredFrame->channel_layout); - const int bps = av_get_bytes_per_sample(filteredFrame->format); + const int bps = av_get_bytes_per_sample (filteredFrame->format); ao_play (player->aoDev, (char *) filteredFrame->data[0], filteredFrame->nb_samples * numChannels * bps); @@ -529,10 +539,8 @@ void *BarAoPlayThread (void *data) { (double) filteredFrame->pts; pthread_mutex_lock (&player->lock); player->songPlayed = songPlayed; - pthread_mutex_unlock (&player->lock); /* pausing */ - pthread_mutex_lock (&player->lock); if (player->doPause) { do { pthread_cond_wait (&player->cond, &player->lock); @@ -540,6 +548,7 @@ void *BarAoPlayThread (void *data) { } pthread_mutex_unlock (&player->lock); + /* notify download thread, we might need more data */ pthread_mutex_lock (&player->aoplayLock); player->lastTimestamp = filteredFrame->pts; pthread_cond_broadcast (&player->aoplayCond);