Fix FreeBSD sound timing problems

This commit is contained in:
ejurgensen 2014-09-27 22:59:19 +02:00
parent dafa26a48a
commit 65110a9f39
3 changed files with 208 additions and 267 deletions

View File

@ -863,21 +863,20 @@ murmur_hash64(const void *key, int len, uint32_t seed)
# error Platform not supported # error Platform not supported
#endif #endif
#if defined(__linux__)
int int
clock_gettime_with_res(clockid_t clock_id, struct timespec *tp, struct timespec *res) clock_gettime_with_res(clockid_t clock_id, struct timespec *tp, struct timespec *res)
{ {
int r_val = -1; int ret;
if(res && tp)
{ if ((!tp) || (!res))
r_val = clock_gettime(clock_id, tp); return -1;
/* this will only work for sub-second resolutions. */
if(r_val == 0 && res->tv_nsec > 1) ret = clock_gettime(clock_id, tp);
{ /* this will only work for sub-second resolutions. */
tp->tv_nsec = (tp->tv_nsec/res->tv_nsec)*res->tv_nsec; if (ret == 0 && res->tv_nsec > 1)
} tp->tv_nsec = (tp->tv_nsec/res->tv_nsec)*res->tv_nsec;
}
return r_val; return ret;
} }
struct timespec struct timespec
@ -888,10 +887,10 @@ timespec_add(struct timespec time1, struct timespec time2)
result.tv_sec = time1.tv_sec + time2.tv_sec; result.tv_sec = time1.tv_sec + time2.tv_sec;
result.tv_nsec = time1.tv_nsec + time2.tv_nsec; result.tv_nsec = time1.tv_nsec + time2.tv_nsec;
if (result.tv_nsec >= 1000000000L) if (result.tv_nsec >= 1000000000L)
{ {
result.tv_sec++; result.tv_sec++;
result.tv_nsec -= 1000000000L; result.tv_nsec -= 1000000000L;
} }
return result; return result;
} }
@ -914,4 +913,3 @@ timespec_cmp(struct timespec time1, struct timespec time2)
else else
return 0; return 0;
} }
#endif /* __linux__ */

View File

@ -3,9 +3,7 @@
#define __MISC_H__ #define __MISC_H__
#include <stdint.h> #include <stdint.h>
#if defined(__linux__) #include <time.h>
# include <time.h>
#endif
struct onekeyval { struct onekeyval {
char *name; char *name;
@ -84,8 +82,7 @@ b64_encode(uint8_t *in, size_t len);
uint64_t uint64_t
murmur_hash64(const void *key, int len, uint32_t seed); murmur_hash64(const void *key, int len, uint32_t seed);
#if defined(__linux__) /* Timer function for platforms without hi-res timers */
/* Timer functions for platforms without hi-res timers */
int int
clock_gettime_with_res(clockid_t clock_id, struct timespec *tp, struct timespec *res); clock_gettime_with_res(clockid_t clock_id, struct timespec *tp, struct timespec *res);
@ -94,6 +91,5 @@ timespec_add(struct timespec time1, struct timespec time2);
int int
timespec_cmp(struct timespec time1, struct timespec time2); timespec_cmp(struct timespec time1, struct timespec time2);
#endif /* __linux__ */
#endif /* !__MISC_H__ */ #endif /* !__MISC_H__ */

View File

@ -34,17 +34,15 @@
#if defined(__linux__) #if defined(__linux__)
# include <sys/timerfd.h> # include <sys/timerfd.h>
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# include <sys/time.h>
# include <sys/event.h>
#endif #endif
#if defined(HAVE_SYS_EVENTFD_H) && defined(HAVE_EVENTFD) #ifdef HAVE_LIBEVENT2
# define USE_EVENTFD # include <event2/event.h>
# include <sys/eventfd.h> #else
# include <event.h>
#endif #endif
#include <event.h>
#include <gcrypt.h> #include <gcrypt.h>
#include "db.h" #include "db.h"
@ -141,15 +139,11 @@ static const char *raop_devtype[] =
struct event_base *evbase_player; struct event_base *evbase_player;
#ifdef USE_EVENTFD
static int exit_efd;
#else
static int exit_pipe[2]; static int exit_pipe[2];
#endif
static int cmd_pipe[2]; static int cmd_pipe[2];
static int player_exit; static int player_exit;
static struct event exitev; static struct event *exitev;
static struct event cmdev; static struct event *cmdev;
static pthread_t tid_player; static pthread_t tid_player;
/* Player status */ /* Player status */
@ -161,15 +155,17 @@ static char shuffle;
static player_status_handler update_handler; static player_status_handler update_handler;
/* Playback timer */ /* Playback timer */
static int pb_timer_fd;
static struct event pb_timer_ev;
#if defined(__linux__) #if defined(__linux__)
static int pb_timer_fd;
#else
timer_t pb_timer;
#endif
static struct event *pb_timer_ev;
static struct timespec pb_timer_last; static struct timespec pb_timer_last;
static struct timespec packet_timer_last; static struct timespec packet_timer_last;
static uint64_t MINIMUM_STREAM_PERIOD; static uint64_t MINIMUM_STREAM_PERIOD;
static struct timespec packet_time = { 0, AIRTUNES_V2_STREAM_PERIOD }; static struct timespec packet_time = { 0, AIRTUNES_V2_STREAM_PERIOD };
static struct timespec timer_res; static struct timespec timer_res;
#endif
/* Sync source */ /* Sync source */
static enum player_sync_source pb_sync_source; static enum player_sync_source pb_sync_source;
@ -222,7 +218,7 @@ command_async_end(struct player_command *cmd)
pthread_mutex_unlock(&cmd->lck); pthread_mutex_unlock(&cmd->lck);
/* Process commands again */ /* Process commands again */
event_add(&cmdev, NULL); event_add(cmdev, NULL);
} }
static void static void
@ -379,11 +375,7 @@ player_get_current_pos_clock(uint64_t *pos, struct timespec *ts, int commit)
uint64_t delta; uint64_t delta;
int ret; int ret;
#if defined(__linux__)
ret = clock_gettime_with_res(CLOCK_MONOTONIC, ts, &timer_res); ret = clock_gettime_with_res(CLOCK_MONOTONIC, ts, &timer_res);
#else
ret = clock_gettime(CLOCK_MONOTONIC, ts);
#endif
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_PLAYER, "Couldn't get clock: %s\n", strerror(errno)); DPRINTF(E_LOG, L_PLAYER, "Couldn't get clock: %s\n", strerror(errno));
@ -427,11 +419,7 @@ player_get_current_pos_laudio(uint64_t *pos, struct timespec *ts, int commit)
*pos = laudio_get_pos(); *pos = laudio_get_pos();
#if defined(__linux__)
ret = clock_gettime_with_res(CLOCK_MONOTONIC, ts, &timer_res); ret = clock_gettime_with_res(CLOCK_MONOTONIC, ts, &timer_res);
#else
ret = clock_gettime(CLOCK_MONOTONIC, ts);
#endif
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_PLAYER, "Couldn't get clock: %s\n", strerror(errno)); DPRINTF(E_LOG, L_PLAYER, "Couldn't get clock: %s\n", strerror(errno));
@ -469,6 +457,71 @@ player_get_current_pos(uint64_t *pos, struct timespec *ts, int commit)
return -1; return -1;
} }
static int
pb_timer_start(struct timespec *ts)
{
struct itimerspec next;
int ret;
next.it_interval.tv_sec = 0;
next.it_interval.tv_nsec = 0;
next.it_value.tv_sec = ts->tv_sec;
next.it_value.tv_nsec = ts->tv_nsec;
#if defined(__linux__)
ret = timerfd_settime(pb_timer_fd, TFD_TIMER_ABSTIME, &next, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not arm playback timer: %s\n", strerror(errno));
return -1;
}
ret = event_add(pb_timer_ev, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not add playback timer event\n");
return -1;
}
#else
ret = timer_settime(pb_timer, TIMER_ABSTIME, &next, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not arm playback timer: %s\n", strerror(errno));
return -1;
}
#endif
return 0;
}
static int
pb_timer_stop(void)
{
struct itimerspec next;
int ret;
memset(&next, 0, sizeof(struct itimerspec));
#if defined(__linux__)
event_del(pb_timer_ev);
ret = timerfd_settime(pb_timer_fd, TFD_TIMER_ABSTIME, &next, NULL);
#else
ret = timer_settime(pb_timer, TIMER_ABSTIME, &next, NULL);
#endif
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not disarm playback timer: %s\n", strerror(errno));
return -1;
}
return 0;
}
/* Forward */ /* Forward */
static void static void
playback_abort(void); playback_abort(void);
@ -1618,19 +1671,19 @@ playback_write(void)
raop_v2_write(rawbuf, last_rtptime); raop_v2_write(rawbuf, last_rtptime);
} }
#if defined(__linux__)
static void static void
player_playback_cb(int fd, short what, void *arg) player_playback_cb(int fd, short what, void *arg)
{ {
struct itimerspec next;
uint64_t ticks;
int ret;
uint32_t packet_send_count = 0; uint32_t packet_send_count = 0;
struct timespec next_tick; struct timespec next_tick;
struct timespec stream_period = { 0, MINIMUM_STREAM_PERIOD }; struct timespec stream_period = { 0, MINIMUM_STREAM_PERIOD };
#if defined(__linux__)
uint64_t ticks;
int ret;
/* Acknowledge timer */ /* Acknowledge timer */
read(fd, &ticks, sizeof(ticks)); read(fd, &ticks, sizeof(ticks));
#endif /* __linux__ */
/* Decide how many packets to send */ /* Decide how many packets to send */
next_tick = timespec_add(pb_timer_last, stream_period); next_tick = timespec_add(pb_timer_last, stream_period);
@ -1648,80 +1701,18 @@ player_playback_cb(int fd, short what, void *arg)
return; return;
} }
} }
while (timespec_cmp(packet_timer_last, next_tick) < 0);
while(timespec_cmp(packet_timer_last, next_tick) < 0);
/* Make sure playback is still running */ /* Make sure playback is still running */
if (player_state == PLAY_STOPPED) if (player_state == PLAY_STOPPED)
return; return;
pb_timer_last.tv_nsec += MINIMUM_STREAM_PERIOD; pb_timer_last = timespec_add(pb_timer_last, stream_period);
if (pb_timer_last.tv_nsec >= 1000000000)
{
pb_timer_last.tv_sec++;
pb_timer_last.tv_nsec -= 1000000000;
}
next.it_interval.tv_sec = 0; ret = pb_timer_start(&pb_timer_last);
next.it_interval.tv_nsec = 0;
next.it_value.tv_sec = pb_timer_last.tv_sec;
next.it_value.tv_nsec = pb_timer_last.tv_nsec;
ret = timerfd_settime(pb_timer_fd, TFD_TIMER_ABSTIME, &next, NULL);
if (ret < 0) if (ret < 0)
{ playback_abort();
DPRINTF(E_LOG, L_PLAYER, "Could not set playback timer: %s\n", strerror(errno));
playback_abort();
return;
}
ret = event_add(&pb_timer_ev, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not re-add playback timer event\n");
playback_abort();
return;
}
} }
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
static void
player_playback_cb(int fd, short what, void *arg)
{
struct timespec ts;
struct kevent kev;
int ret;
ts.tv_sec = 0;
ts.tv_nsec = 0;
while (kevent(pb_timer_fd, NULL, 0, &kev, 1, &ts) > 0)
{
if (kev.filter != EVFILT_TIMER)
continue;
playback_write();
/* Make sure playback is still running */
if (player_state == PLAY_STOPPED)
return;
}
ret = event_add(&pb_timer_ev, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not re-add playback timer event\n");
playback_abort();
return;
}
}
#endif /* __FreeBSD__ || __FreeBSD_kernel__ */
static void static void
device_free(struct raop_device *dev) device_free(struct raop_device *dev)
@ -2079,24 +2070,14 @@ device_activate_cb(struct raop_device *dev, struct raop_session *rs, enum raop_s
if ((player_state == PLAY_PLAYING) && (raop_sessions == 1)) if ((player_state == PLAY_PLAYING) && (raop_sessions == 1))
{ {
#if defined(__linux__)
ret = clock_gettime_with_res(CLOCK_MONOTONIC, &ts, &timer_res); ret = clock_gettime_with_res(CLOCK_MONOTONIC, &ts, &timer_res);
#else
ret = clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_PLAYER, "Could not get current time: %s\n", strerror(errno)); DPRINTF(E_LOG, L_PLAYER, "Could not get current time: %s\n", strerror(errno));
#if defined(__linux__)
/* Fallback to nearest timer expiration time */ /* Fallback to nearest timer expiration time */
ts.tv_sec = pb_timer_last.tv_sec; ts.tv_sec = pb_timer_last.tv_sec;
ts.tv_nsec = pb_timer_last.tv_nsec; ts.tv_nsec = pb_timer_last.tv_nsec;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
if (cur_cmd->ret != -2)
cur_cmd->ret = -1;
goto out;
#endif
} }
raop_playback_start(last_rtptime + AIRTUNES_V2_PACKET_SAMPLES, &ts); raop_playback_start(last_rtptime + AIRTUNES_V2_PACKET_SAMPLES, &ts);
@ -2216,12 +2197,7 @@ playback_abort(void)
if (raop_sessions > 0) if (raop_sessions > 0)
raop_playback_stop(); raop_playback_stop();
if (event_initialized(&pb_timer_ev)) pb_timer_stop();
event_del(&pb_timer_ev);
if (pb_timer_fd != -1)
close(pb_timer_fd);
pb_timer_fd = -1;
if (cur_playing) if (cur_playing)
source_stop(cur_playing); source_stop(cur_playing);
@ -2351,12 +2327,7 @@ playback_stop(struct player_command *cmd)
*/ */
cmd->raop_pending = raop_flush(device_command_cb, last_rtptime + AIRTUNES_V2_PACKET_SAMPLES); cmd->raop_pending = raop_flush(device_command_cb, last_rtptime + AIRTUNES_V2_PACKET_SAMPLES);
if (event_initialized(&pb_timer_ev)) pb_timer_stop();
event_del(&pb_timer_ev);
if (pb_timer_fd != -1)
close(pb_timer_fd);
pb_timer_fd = -1;
if (cur_playing) if (cur_playing)
{ {
@ -2389,11 +2360,6 @@ playback_stop(struct player_command *cmd)
static int static int
playback_start_bh(struct player_command *cmd) playback_start_bh(struct player_command *cmd)
{ {
#if defined(__linux__)
struct itimerspec next;
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
struct kevent kev;
#endif
int ret; int ret;
if ((laudio_status == LAUDIO_CLOSED) && (raop_sessions == 0)) if ((laudio_status == LAUDIO_CLOSED) && (raop_sessions == 0))
@ -2417,11 +2383,7 @@ playback_start_bh(struct player_command *cmd)
} }
} }
#if defined(__linux__)
ret = clock_gettime_with_res(CLOCK_MONOTONIC, &pb_pos_stamp, &timer_res); ret = clock_gettime_with_res(CLOCK_MONOTONIC, &pb_pos_stamp, &timer_res);
#else
ret = clock_gettime(CLOCK_MONOTONIC, &pb_pos_stamp);
#endif
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_PLAYER, "Couldn't get current clock: %s\n", strerror(errno)); DPRINTF(E_LOG, L_PLAYER, "Couldn't get current clock: %s\n", strerror(errno));
@ -2429,9 +2391,8 @@ playback_start_bh(struct player_command *cmd)
goto out_fail; goto out_fail;
} }
memset(&pb_timer_ev, 0, sizeof(struct event)); pb_timer_stop();
#if defined(__linux__)
/* /*
* initialize the packet timer to the same relative time that we have * initialize the packet timer to the same relative time that we have
* for the playback timer. * for the playback timer.
@ -2442,58 +2403,9 @@ playback_start_bh(struct player_command *cmd)
pb_timer_last.tv_sec = pb_pos_stamp.tv_sec; pb_timer_last.tv_sec = pb_pos_stamp.tv_sec;
pb_timer_last.tv_nsec = pb_pos_stamp.tv_nsec; pb_timer_last.tv_nsec = pb_pos_stamp.tv_nsec;
pb_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); ret = pb_timer_start(&pb_timer_last);
if (pb_timer_fd < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create playback timer: %s\n", strerror(errno));
goto out_fail;
}
next.it_interval.tv_sec = 0;
next.it_interval.tv_nsec = 0;
next.it_value.tv_sec = pb_timer_last.tv_sec;
next.it_value.tv_nsec = pb_timer_last.tv_nsec;
ret = timerfd_settime(pb_timer_fd, TFD_TIMER_ABSTIME, &next, NULL);
if (ret < 0) if (ret < 0)
{ goto out_fail;
DPRINTF(E_LOG, L_PLAYER, "Could not set playback timer: %s\n", strerror(errno));
goto out_fail;
}
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
pb_timer_fd = kqueue();
if (pb_timer_fd < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create kqueue: %s\n", strerror(errno));
goto out_fail;
}
memset(&kev, 0, sizeof(struct kevent));
EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD | EV_ENABLE, 0, AIRTUNES_V2_STREAM_PERIOD, 0);
ret = kevent(pb_timer_fd, &kev, 1, NULL, 0, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not add kevent timer: %s\n", strerror(errno));
goto out_fail;
}
#endif
event_set(&pb_timer_ev, pb_timer_fd, EV_READ, player_playback_cb, NULL);
event_base_set(evbase_player, &pb_timer_ev);
ret = event_add(&pb_timer_ev, NULL);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not set up playback timer event\n");
goto out_fail;
}
/* Everything OK, start RAOP */ /* Everything OK, start RAOP */
if (raop_sessions > 0) if (raop_sessions > 0)
@ -2504,9 +2416,6 @@ playback_start_bh(struct player_command *cmd)
return 0; return 0;
out_fail: out_fail:
if (pb_timer_fd != -1)
close(pb_timer_fd);
pb_timer_fd = -1;
playback_abort(); playback_abort();
return -1; return -1;
@ -2921,12 +2830,7 @@ playback_pause(struct player_command *cmd)
if (laudio_status != LAUDIO_CLOSED) if (laudio_status != LAUDIO_CLOSED)
laudio_stop(); laudio_stop();
if (event_initialized(&pb_timer_ev)) pb_timer_stop();
event_del(&pb_timer_ev);
if (pb_timer_fd != -1)
close(pb_timer_fd);
pb_timer_fd = -1;
if (ps->play_next) if (ps->play_next)
source_stop(ps->play_next); source_stop(ps->play_next);
@ -3783,7 +3687,7 @@ command_cb(int fd, short what, void *arg)
} }
readd: readd:
event_add(&cmdev, NULL); event_add(cmdev, NULL);
} }
@ -4620,8 +4524,6 @@ player_init(void)
cur_cmd = NULL; cur_cmd = NULL;
pb_timer_fd = -1;
source_head = NULL; source_head = NULL;
shuffle_head = NULL; shuffle_head = NULL;
cur_playing = NULL; cur_playing = NULL;
@ -4634,9 +4536,8 @@ player_init(void)
update_handler = NULL; update_handler = NULL;
history = (struct player_history *) calloc(1, sizeof(struct player_history)); history = (struct player_history *)calloc(1, sizeof(struct player_history));
#if defined(__linux__)
/* /*
* Determine if the resolution of the system timer is > or < the size * Determine if the resolution of the system timer is > or < the size
* of an audio packet. NOTE: this assumes the system clock resolution * of an audio packet. NOTE: this assumes the system clock resolution
@ -4648,9 +4549,31 @@ player_init(void)
return -1; return -1;
} }
MINIMUM_STREAM_PERIOD = MAX(timer_res.tv_nsec, AIRTUNES_V2_STREAM_PERIOD);
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
/* FreeBSD will report a resolution of 1, but actually has a resolution
* larger than an audio packet
*/
if (timer_res.tv_nsec == 1)
timer_res.tv_nsec = 2 * AIRTUNES_V2_STREAM_PERIOD;
#endif #endif
MINIMUM_STREAM_PERIOD = MAX(timer_res.tv_nsec, AIRTUNES_V2_STREAM_PERIOD);
/* Create a timer */
#if defined(__linux__)
pb_timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
ret = pb_timer_fd;
#else
ret = timer_create(CLOCK_MONOTONIC, NULL, &pb_timer);
#endif
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create playback timer: %s\n", strerror(errno));
return -1;
}
/* Random RTP time start */ /* Random RTP time start */
gcry_randomize(&rnd, sizeof(rnd), GCRY_STRONG_RANDOM); gcry_randomize(&rnd, sizeof(rnd), GCRY_STRONG_RANDOM);
last_rtptime = ((uint64_t)1 << 32) | rnd; last_rtptime = ((uint64_t)1 << 32) | rnd;
@ -4668,33 +4591,22 @@ player_init(void)
{ {
DPRINTF(E_LOG, L_PLAYER, "Could not allocate evbuffer for audio buffer\n"); DPRINTF(E_LOG, L_PLAYER, "Could not allocate evbuffer for audio buffer\n");
return -1; goto audio_fail;
} }
raop_v6enabled = cfg_getbool(cfg_getsec(cfg, "general"), "ipv6"); raop_v6enabled = cfg_getbool(cfg_getsec(cfg, "general"), "ipv6");
#if defined(__linux__)
#ifdef USE_EVENTFD
exit_efd = eventfd(0, EFD_CLOEXEC);
if (exit_efd < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create eventfd: %s\n", strerror(errno));
goto exit_fail;
}
#else
# if defined(__linux__)
ret = pipe2(exit_pipe, O_CLOEXEC); ret = pipe2(exit_pipe, O_CLOEXEC);
# else #else
ret = pipe(exit_pipe); ret = pipe(exit_pipe);
# endif #endif
if (ret < 0) if (ret < 0)
{ {
DPRINTF(E_LOG, L_PLAYER, "Could not create pipe: %s\n", strerror(errno)); DPRINTF(E_LOG, L_PLAYER, "Could not create pipe: %s\n", strerror(errno));
goto exit_fail; goto exit_fail;
} }
#endif /* USE_EVENTFD */
# if defined(__linux__) # if defined(__linux__)
ret = pipe2(cmd_pipe, O_CLOEXEC); ret = pipe2(cmd_pipe, O_CLOEXEC);
@ -4716,17 +4628,70 @@ player_init(void)
goto evbase_fail; goto evbase_fail;
} }
#ifdef USE_EVENTFD #ifdef HAVE_LIBEVENT2
event_set(&exitev, exit_efd, EV_READ, exit_cb, NULL); exitev = event_new(evbase_player, exit_pipe[0], EV_READ, exit_cb, NULL);
#else if (!exitev)
event_set(&exitev, exit_pipe[0], EV_READ, exit_cb, NULL); {
#endif DPRINTF(E_LOG, L_PLAYER, "Could not create exit event\n");
event_base_set(evbase_player, &exitev); goto evnew_fail;
event_add(&exitev, NULL); }
event_set(&cmdev, cmd_pipe[0], EV_READ, command_cb, NULL); cmdev = event_new(evbase_player, cmd_pipe[0], EV_READ, command_cb, NULL);
event_base_set(evbase_player, &cmdev); if (!cmdev)
event_add(&cmdev, NULL); {
DPRINTF(E_LOG, L_PLAYER, "Could not create cmd event\n");
goto evnew_fail;
}
# if defined(__linux__)
pb_timer_ev = event_new(evbase_player, pb_timer_fd, EV_READ, player_playback_cb, NULL);
# else
pb_timer_ev = evsignal_new(evbase_player, SIGALRM, player_playback_cb, NULL);
# endif
if (!pb_timer_ev)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create playback timer event\n");
goto evnew_fail;
}
#else
exitev = (struct event *)malloc(sizeof(struct event));
if (!exitev)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create exit event\n");
goto evnew_fail;
}
event_set(exitev, exit_pipe[0], EV_READ, exit_cb, NULL);
event_base_set(evbase_player, exitev);
cmdev = (struct event *)malloc(sizeof(struct event));
if (!cmdev)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create cmd event\n");
goto evnew_fail;
}
event_set(cmdev, cmd_pipe[0], EV_READ, command_cb, NULL);
event_base_set(evbase_player, cmdev);
pb_timer_ev = (struct event *)malloc(sizeof(struct event));
if (!pb_timer_ev)
{
DPRINTF(E_LOG, L_PLAYER, "Could not create playback timer event\n");
goto evnew_fail;
}
# if defined(__linux__)
event_set(pb_timer_ev, pb_timer_fd, EV_READ, player_playback_cb, NULL);
# else
signal_set(pb_timer_ev, SIGALRM, player_playback_cb, NULL);
# endif
event_base_set(evbase_player, pb_timer_ev);
#endif /* HAVE_LIBEVENT2 */
event_add(exitev, NULL);
event_add(cmdev, NULL);
#ifndef __linux__
event_add(pb_timer_ev, NULL);
#endif
ret = laudio_init(player_laudio_status_cb); ret = laudio_init(player_laudio_status_cb);
if (ret < 0) if (ret < 0)
@ -4773,19 +4738,18 @@ player_init(void)
raop_fail: raop_fail:
laudio_deinit(); laudio_deinit();
laudio_fail: laudio_fail:
evnew_fail:
event_base_free(evbase_player); event_base_free(evbase_player);
evbase_fail: evbase_fail:
close(cmd_pipe[0]); close(cmd_pipe[0]);
close(cmd_pipe[1]); close(cmd_pipe[1]);
cmd_fail: cmd_fail:
#ifdef USE_EVENTFD
close(exit_efd);
#else
close(exit_pipe[0]); close(exit_pipe[0]);
close(exit_pipe[1]); close(exit_pipe[1]);
#endif
exit_fail: exit_fail:
evbuffer_free(audio_buf); evbuffer_free(audio_buf);
audio_fail:
close(pb_timer_fd);
return -1; return -1;
} }
@ -4795,26 +4759,15 @@ void
player_deinit(void) player_deinit(void)
{ {
int ret; int ret;
#ifdef USE_EVENTFD
ret = eventfd_write(exit_efd, 1);
if (ret < 0)
{
DPRINTF(E_LOG, L_PLAYER, "Could not send exit event: %s\n", strerror(errno));
return;
}
#else
int dummy = 42; int dummy = 42;
ret = write(exit_pipe[1], &dummy, sizeof(dummy)); ret = write(exit_pipe[1], &dummy, sizeof(dummy));
if (ret != sizeof(dummy)) if (ret != sizeof(dummy))
{ {
DPRINTF(E_LOG, L_PLAYER, "Could not write to exit fd: %s\n", strerror(errno)); DPRINTF(E_LOG, L_PLAYER, "Could not write to exit pipe: %s\n", strerror(errno));
return; return;
} }
#endif
ret = pthread_join(tid_player, NULL); ret = pthread_join(tid_player, NULL);
if (ret != 0) if (ret != 0)
@ -4829,22 +4782,16 @@ player_deinit(void)
free(history); free(history);
pb_timer_stop();
close(pb_timer_fd);
evbuffer_free(audio_buf); evbuffer_free(audio_buf);
laudio_deinit(); laudio_deinit();
raop_deinit(); raop_deinit();
if (event_initialized(&pb_timer_ev))
event_del(&pb_timer_ev);
event_del(&cmdev);
#ifdef USE_EVENTFD
close(exit_efd);
#else
close(exit_pipe[0]); close(exit_pipe[0]);
close(exit_pipe[1]); close(exit_pipe[1]);
#endif
close(cmd_pipe[0]); close(cmd_pipe[0]);
close(cmd_pipe[1]); close(cmd_pipe[1]);
cmd_pipe[0] = -1; cmd_pipe[0] = -1;