Fix FreeBSD sound timing problems
This commit is contained in:
parent
dafa26a48a
commit
65110a9f39
32
src/misc.c
32
src/misc.c
|
@ -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__ */
|
|
||||||
|
|
|
@ -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__ */
|
||||||
|
|
435
src/player.c
435
src/player.c
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue