mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	Fighting rewinds: Reduce calls to handle_seek
If many small blocks are in queue, handle_seek is being called for every one of them, sometimes causing a rewind. Delay the call until all blocks are handled, then call handle_seek only once. Signed-off-by: David Henningsson <david.henningsson@canonical.com>
This commit is contained in:
		
							parent
							
								
									3aeb047282
								
							
						
					
					
						commit
						6b280e97e3
					
				
					 1 changed files with 26 additions and 30 deletions
				
			
		| 
						 | 
					@ -125,6 +125,10 @@ typedef struct playback_stream {
 | 
				
			||||||
    uint32_t drain_tag;
 | 
					    uint32_t drain_tag;
 | 
				
			||||||
    uint32_t syncid;
 | 
					    uint32_t syncid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Optimization to avoid too many rewinds with a lot of small blocks */
 | 
				
			||||||
 | 
					    pa_atomic_t seek_or_post_in_queue;
 | 
				
			||||||
 | 
					    int64_t seek_windex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_atomic_t missing;
 | 
					    pa_atomic_t missing;
 | 
				
			||||||
    pa_usec_t configured_sink_latency;
 | 
					    pa_usec_t configured_sink_latency;
 | 
				
			||||||
    pa_buffer_attr buffer_attr;
 | 
					    pa_buffer_attr buffer_attr;
 | 
				
			||||||
| 
						 | 
					@ -1099,6 +1103,8 @@ static playback_stream* playback_stream_new(
 | 
				
			||||||
    s->buffer_attr = *a;
 | 
					    s->buffer_attr = *a;
 | 
				
			||||||
    s->adjust_latency = adjust_latency;
 | 
					    s->adjust_latency = adjust_latency;
 | 
				
			||||||
    s->early_requests = early_requests;
 | 
					    s->early_requests = early_requests;
 | 
				
			||||||
 | 
					    pa_atomic_store(&s->seek_or_post_in_queue, 0);
 | 
				
			||||||
 | 
					    s->seek_windex = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->sink_input->parent.process_msg = sink_input_process_msg;
 | 
					    s->sink_input->parent.process_msg = sink_input_process_msg;
 | 
				
			||||||
    s->sink_input->pop = sink_input_pop_cb;
 | 
					    s->sink_input->pop = sink_input_pop_cb;
 | 
				
			||||||
| 
						 | 
					@ -1351,7 +1357,6 @@ static void flush_write_no_account(pa_memblockq *q) {
 | 
				
			||||||
static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
 | 
					static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
 | 
				
			||||||
    pa_sink_input *i = PA_SINK_INPUT(o);
 | 
					    pa_sink_input *i = PA_SINK_INPUT(o);
 | 
				
			||||||
    playback_stream *s;
 | 
					    playback_stream *s;
 | 
				
			||||||
    int64_t windex_seek = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pa_sink_input_assert_ref(i);
 | 
					    pa_sink_input_assert_ref(i);
 | 
				
			||||||
    s = PLAYBACK_STREAM(i->userdata);
 | 
					    s = PLAYBACK_STREAM(i->userdata);
 | 
				
			||||||
| 
						 | 
					@ -1359,45 +1364,35 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch (code) {
 | 
					    switch (code) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        case SINK_INPUT_MESSAGE_SEEK: {
 | 
					        case SINK_INPUT_MESSAGE_SEEK:
 | 
				
			||||||
 | 
					 | 
				
			||||||
            windex_seek = pa_memblockq_get_write_index(s->memblockq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            /* The client side is incapable of accounting correctly
 | 
					 | 
				
			||||||
             * for seeks of a type != PA_SEEK_RELATIVE. We need to be
 | 
					 | 
				
			||||||
             * able to deal with that. */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
 | 
					 | 
				
			||||||
            if (!chunk) {
 | 
					 | 
				
			||||||
                handle_seek(s, windex_seek);
 | 
					 | 
				
			||||||
                return 0;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            /* else fall through and write some data */
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        case SINK_INPUT_MESSAGE_POST_DATA: {
 | 
					        case SINK_INPUT_MESSAGE_POST_DATA: {
 | 
				
			||||||
            int64_t windex;
 | 
					            int64_t windex = pa_memblockq_get_write_index(s->memblockq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pa_assert(chunk);
 | 
					            if (code == SINK_INPUT_MESSAGE_SEEK) {
 | 
				
			||||||
 | 
					                /* The client side is incapable of accounting correctly
 | 
				
			||||||
 | 
					                 * for seeks of a type != PA_SEEK_RELATIVE. We need to be
 | 
				
			||||||
 | 
					                 * able to deal with that. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            windex = pa_memblockq_get_write_index(s->memblockq);
 | 
					                pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
 | 
				
			||||||
            if (code == SINK_INPUT_MESSAGE_SEEK)
 | 
					                windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
 | 
				
			||||||
                windex = PA_MIN(windex, windex_seek);
 | 
					            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*             pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
 | 
				
			||||||
                if (pa_log_ratelimit(PA_LOG_WARN))
 | 
					                if (pa_log_ratelimit(PA_LOG_WARN))
 | 
				
			||||||
                    pa_log_warn("Failed to push data into queue");
 | 
					                    pa_log_warn("Failed to push data into queue");
 | 
				
			||||||
                pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
 | 
					                pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL);
 | 
				
			||||||
                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);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handle_seek(s, windex);
 | 
					            /* If more data is in queue, we rewind later instead. */
 | 
				
			||||||
 | 
					            if (s->seek_windex != -1)
 | 
				
			||||||
/*             pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
 | 
					                 windex = PA_MIN(windex, s->seek_windex);
 | 
				
			||||||
 | 
					            if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1)
 | 
				
			||||||
 | 
					                s->seek_windex = windex;
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                s->seek_windex = -1;
 | 
				
			||||||
 | 
					                handle_seek(s, windex);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4442,6 +4437,7 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
 | 
				
			||||||
    if (playback_stream_isinstance(stream)) {
 | 
					    if (playback_stream_isinstance(stream)) {
 | 
				
			||||||
        playback_stream *ps = PLAYBACK_STREAM(stream);
 | 
					        playback_stream *ps = PLAYBACK_STREAM(stream);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_atomic_inc(&ps->seek_or_post_in_queue);
 | 
				
			||||||
        if (chunk->memblock) {
 | 
					        if (chunk->memblock) {
 | 
				
			||||||
            if (seek != PA_SEEK_RELATIVE || offset != 0)
 | 
					            if (seek != PA_SEEK_RELATIVE || offset != 0)
 | 
				
			||||||
                pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
 | 
					                pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue