mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	make use of SO_TIMESTAMP timestamp for accuracy and leave smoother paused until we have data
This commit is contained in:
		
							parent
							
								
									f204c0fe43
								
							
						
					
					
						commit
						2c2713a72c
					
				
					 3 changed files with 62 additions and 11 deletions
				
			
		| 
						 | 
					@ -52,6 +52,8 @@
 | 
				
			||||||
#include <pulsecore/rtclock.h>
 | 
					#include <pulsecore/rtclock.h>
 | 
				
			||||||
#include <pulsecore/atomic.h>
 | 
					#include <pulsecore/atomic.h>
 | 
				
			||||||
#include <pulsecore/time-smoother.h>
 | 
					#include <pulsecore/time-smoother.h>
 | 
				
			||||||
 | 
					#include <pulsecore/socket-util.h>
 | 
				
			||||||
 | 
					#include <pulsecore/once.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "module-rtp-recv-symdef.h"
 | 
					#include "module-rtp-recv-symdef.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,7 +167,7 @@ static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
 | 
				
			||||||
    pa_memblockq_rewind(s->memblockq, nbytes);
 | 
					    pa_memblockq_rewind(s->memblockq, nbytes);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Called from thread context */
 | 
					/* Called from I/O thread context */
 | 
				
			||||||
static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
 | 
					static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
 | 
				
			||||||
    struct session *s;
 | 
					    struct session *s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,11 +186,24 @@ static void sink_input_kill(pa_sink_input* i) {
 | 
				
			||||||
    session_free(s);
 | 
					    session_free(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Called from IO context */
 | 
				
			||||||
 | 
					static void sink_input_suspend_within_thread(pa_sink_input* i, pa_bool_t b) {
 | 
				
			||||||
 | 
					    struct session *s;
 | 
				
			||||||
 | 
					    pa_sink_input_assert_ref(i);
 | 
				
			||||||
 | 
					    pa_assert_se(s = i->userdata);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (b) {
 | 
				
			||||||
 | 
					        pa_smoother_pause(s->smoother, pa_rtclock_usec());
 | 
				
			||||||
 | 
					        pa_memblockq_flush_read(s->memblockq);
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					        s->first_packet = FALSE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Called from I/O thread context */
 | 
					/* Called from I/O thread context */
 | 
				
			||||||
static int rtpoll_work_cb(pa_rtpoll_item *i) {
 | 
					static int rtpoll_work_cb(pa_rtpoll_item *i) {
 | 
				
			||||||
    pa_memchunk chunk;
 | 
					    pa_memchunk chunk;
 | 
				
			||||||
    int64_t k, j, delta;
 | 
					    int64_t k, j, delta;
 | 
				
			||||||
    struct timeval now;
 | 
					    struct timeval now = { 0, 0 };
 | 
				
			||||||
    struct session *s;
 | 
					    struct session *s;
 | 
				
			||||||
    struct pollfd *p;
 | 
					    struct pollfd *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,10 +221,11 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    p->revents = 0;
 | 
					    p->revents = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->module->core->mempool) < 0)
 | 
					    if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->module->core->mempool, &now) < 0)
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->sdp_info.payload != s->rtp_context.payload) {
 | 
					    if (s->sdp_info.payload != s->rtp_context.payload ||
 | 
				
			||||||
 | 
					        !PA_SINK_IS_OPENED(s->sink_input->sink->thread_info.state)) {
 | 
				
			||||||
        pa_memblock_unref(chunk.memblock);
 | 
					        pa_memblock_unref(chunk.memblock);
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -240,10 +256,19 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_memblockq_seek(s->memblockq, delta * (int64_t) s->rtp_context.frame_size, PA_SEEK_RELATIVE, TRUE);
 | 
					    pa_memblockq_seek(s->memblockq, delta * (int64_t) s->rtp_context.frame_size, PA_SEEK_RELATIVE, TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_rtclock_get(&now);
 | 
					    if (now.tv_sec == 0) {
 | 
				
			||||||
 | 
					        PA_ONCE_BEGIN {
 | 
				
			||||||
 | 
					            pa_log_warn("Using artificial time instead of timestamp");
 | 
				
			||||||
 | 
					        } PA_ONCE_END;
 | 
				
			||||||
 | 
					        pa_rtclock_get(&now);
 | 
				
			||||||
 | 
					    } else
 | 
				
			||||||
 | 
					        pa_rtclock_from_wallclock(&now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_smoother_put(s->smoother, pa_timeval_load(&now), pa_bytes_to_usec((uint64_t) pa_memblockq_get_write_index(s->memblockq), &s->sink_input->sample_spec));
 | 
					    pa_smoother_put(s->smoother, pa_timeval_load(&now), pa_bytes_to_usec((uint64_t) pa_memblockq_get_write_index(s->memblockq), &s->sink_input->sample_spec));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Tell the smoother that we are rolling now, in case it is still paused */
 | 
				
			||||||
 | 
					    pa_smoother_resume(s->smoother, pa_timeval_load(&now), TRUE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa_memblockq_push(s->memblockq, &chunk) < 0) {
 | 
					    if (pa_memblockq_push(s->memblockq, &chunk) < 0) {
 | 
				
			||||||
        pa_log_warn("Queue overrun");
 | 
					        pa_log_warn("Queue overrun");
 | 
				
			||||||
        pa_memblockq_seek(s->memblockq, (int64_t) chunk.length, PA_SEEK_RELATIVE, TRUE);
 | 
					        pa_memblockq_seek(s->memblockq, (int64_t) chunk.length, PA_SEEK_RELATIVE, TRUE);
 | 
				
			||||||
| 
						 | 
					@ -267,6 +292,8 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
 | 
				
			||||||
        wi = pa_smoother_get(s->smoother, pa_timeval_load(&now));
 | 
					        wi = pa_smoother_get(s->smoother, pa_timeval_load(&now));
 | 
				
			||||||
        ri = pa_bytes_to_usec((uint64_t) pa_memblockq_get_read_index(s->memblockq), &s->sink_input->sample_spec);
 | 
					        ri = pa_bytes_to_usec((uint64_t) pa_memblockq_get_read_index(s->memblockq), &s->sink_input->sample_spec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_log_debug("wi=%lu ri=%lu", (unsigned long) wi, (unsigned long) ri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sink_delay = pa_sink_get_latency_within_thread(s->sink_input->sink);
 | 
					        sink_delay = pa_sink_get_latency_within_thread(s->sink_input->sink);
 | 
				
			||||||
        render_delay = pa_bytes_to_usec(pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq), &s->sink_input->sink->sample_spec);
 | 
					        render_delay = pa_bytes_to_usec(pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq), &s->sink_input->sink->sample_spec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,7 +319,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
 | 
				
			||||||
        fix_samples = (unsigned) (fix * (pa_usec_t) s->sink_input->thread_info.sample_spec.rate / (pa_usec_t) RATE_UPDATE_INTERVAL);
 | 
					        fix_samples = (unsigned) (fix * (pa_usec_t) s->sink_input->thread_info.sample_spec.rate / (pa_usec_t) RATE_UPDATE_INTERVAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Check if deviation is in bounds */
 | 
					        /* Check if deviation is in bounds */
 | 
				
			||||||
        if (fix_samples > s->sink_input->sample_spec.rate*.20)
 | 
					        if (fix_samples > s->sink_input->sample_spec.rate*.50)
 | 
				
			||||||
            pa_log_debug("Hmmm, rate fix is too large (%lu Hz), not applying.", (unsigned long) fix_samples);
 | 
					            pa_log_debug("Hmmm, rate fix is too large (%lu Hz), not applying.", (unsigned long) fix_samples);
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            /* Fix up rate */
 | 
					            /* Fix up rate */
 | 
				
			||||||
| 
						 | 
					@ -366,6 +393,14 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) {
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_make_udp_socket_low_delay(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    one = 1;
 | 
				
			||||||
 | 
					    if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) < 0) {
 | 
				
			||||||
 | 
					        pa_log("SO_TIMESTAMP failed: %s", pa_cstrerror(errno));
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    one = 1;
 | 
					    one = 1;
 | 
				
			||||||
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
 | 
					    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
 | 
				
			||||||
        pa_log("SO_REUSEADDR failed: %s", pa_cstrerror(errno));
 | 
					        pa_log("SO_REUSEADDR failed: %s", pa_cstrerror(errno));
 | 
				
			||||||
| 
						 | 
					@ -441,7 +476,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in
 | 
				
			||||||
            TRUE,
 | 
					            TRUE,
 | 
				
			||||||
            10,
 | 
					            10,
 | 
				
			||||||
            pa_timeval_load(&now),
 | 
					            pa_timeval_load(&now),
 | 
				
			||||||
            FALSE);
 | 
					            TRUE);
 | 
				
			||||||
    s->last_rate_update = pa_timeval_load(&now);
 | 
					    s->last_rate_update = pa_timeval_load(&now);
 | 
				
			||||||
    pa_atomic_store(&s->timestamp, (int) now.tv_sec);
 | 
					    pa_atomic_store(&s->timestamp, (int) now.tv_sec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -482,6 +517,7 @@ static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_in
 | 
				
			||||||
    s->sink_input->kill = sink_input_kill;
 | 
					    s->sink_input->kill = sink_input_kill;
 | 
				
			||||||
    s->sink_input->attach = sink_input_attach;
 | 
					    s->sink_input->attach = sink_input_attach;
 | 
				
			||||||
    s->sink_input->detach = sink_input_detach;
 | 
					    s->sink_input->detach = sink_input_detach;
 | 
				
			||||||
 | 
					    s->sink_input->suspend_within_thread = sink_input_suspend_within_thread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_sink_input_get_silence(s->sink_input, &silence);
 | 
					    pa_sink_input_get_silence(s->sink_input, &silence);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -162,13 +162,16 @@ pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame
 | 
				
			||||||
    return c;
 | 
					    return c;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
 | 
					int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, struct timeval *tstamp) {
 | 
				
			||||||
    int size;
 | 
					    int size;
 | 
				
			||||||
    struct msghdr m;
 | 
					    struct msghdr m;
 | 
				
			||||||
 | 
					    struct cmsghdr *cm;
 | 
				
			||||||
    struct iovec iov;
 | 
					    struct iovec iov;
 | 
				
			||||||
    uint32_t header;
 | 
					    uint32_t header;
 | 
				
			||||||
    unsigned cc;
 | 
					    unsigned cc;
 | 
				
			||||||
    ssize_t r;
 | 
					    ssize_t r;
 | 
				
			||||||
 | 
					    uint8_t aux[1024];
 | 
				
			||||||
 | 
					    pa_bool_t found_tstamp = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_assert(c);
 | 
					    pa_assert(c);
 | 
				
			||||||
    pa_assert(chunk);
 | 
					    pa_assert(chunk);
 | 
				
			||||||
| 
						 | 
					@ -208,8 +211,8 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
 | 
				
			||||||
    m.msg_namelen = 0;
 | 
					    m.msg_namelen = 0;
 | 
				
			||||||
    m.msg_iov = &iov;
 | 
					    m.msg_iov = &iov;
 | 
				
			||||||
    m.msg_iovlen = 1;
 | 
					    m.msg_iovlen = 1;
 | 
				
			||||||
    m.msg_control = NULL;
 | 
					    m.msg_control = aux;
 | 
				
			||||||
    m.msg_controllen = 0;
 | 
					    m.msg_controllen = sizeof(aux);
 | 
				
			||||||
    m.msg_flags = 0;
 | 
					    m.msg_flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    r = recvmsg(c->fd, &m, 0);
 | 
					    r = recvmsg(c->fd, &m, 0);
 | 
				
			||||||
| 
						 | 
					@ -275,6 +278,18 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
 | 
				
			||||||
        pa_memchunk_reset(&c->memchunk);
 | 
					        pa_memchunk_reset(&c->memchunk);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) {
 | 
				
			||||||
 | 
					        if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP)
 | 
				
			||||||
 | 
					            memcpy(tstamp, CMSG_DATA(cm), sizeof(struct timeval));
 | 
				
			||||||
 | 
					            found_tstamp = TRUE;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!found_tstamp) {
 | 
				
			||||||
 | 
					        pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!");
 | 
				
			||||||
 | 
					        memset(tstamp, 0, sizeof(tstamp));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fail:
 | 
					fail:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,7 +43,7 @@ pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssr
 | 
				
			||||||
int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q);
 | 
					int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size);
 | 
					pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size);
 | 
				
			||||||
int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool);
 | 
					int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, struct timeval *tstamp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pa_rtp_context_destroy(pa_rtp_context *c);
 | 
					void pa_rtp_context_destroy(pa_rtp_context *c);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue