summaryrefslogtreecommitdiffstats
path: root/src/pulsecore
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore')
-rw-r--r--src/pulsecore/asyncq.c2
-rw-r--r--src/pulsecore/core-util.c4
-rw-r--r--src/pulsecore/dbus-util.c7
-rw-r--r--src/pulsecore/flist.c6
-rw-r--r--src/pulsecore/flist.h4
-rw-r--r--src/pulsecore/log.c4
-rw-r--r--src/pulsecore/log.h2
-rw-r--r--src/pulsecore/memblock.c2
-rw-r--r--src/pulsecore/protocol-native.c60
-rw-r--r--src/pulsecore/pstream.c2
-rw-r--r--src/pulsecore/ratelimit.c4
-rw-r--r--src/pulsecore/ratelimit.h3
-rw-r--r--src/pulsecore/sink.c35
13 files changed, 73 insertions, 62 deletions
diff --git a/src/pulsecore/asyncq.c b/src/pulsecore/asyncq.c
index 072ef02c..e62d0c16 100644
--- a/src/pulsecore/asyncq.c
+++ b/src/pulsecore/asyncq.c
@@ -206,7 +206,7 @@ void pa_asyncq_post(pa_asyncq*l, void *p) {
/* OK, we couldn't push anything in the queue. So let's queue it
* locally and push it later */
- if (pa_log_ratelimit())
+ if (pa_log_ratelimit(PA_LOG_WARN))
pa_log_warn("q overrun, queuing locally");
if (!(q = pa_flist_pop(PA_STATIC_FLIST_GET(localq))))
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index effc598e..4e7d0d71 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -680,7 +680,7 @@ int pa_make_realtime(int rtprio) {
}
for (p = rtprio-1; p >= 1; p--)
- if (set_scheduler(p)) {
+ if (set_scheduler(p) >= 0) {
pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
return 0;
}
@@ -750,7 +750,7 @@ int pa_raise_priority(int nice_level) {
}
for (n = nice_level+1; n < 0; n++)
- if (set_nice(n) > 0) {
+ if (set_nice(n) >= 0) {
pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
return 0;
}
diff --git a/src/pulsecore/dbus-util.c b/src/pulsecore/dbus-util.c
index 8b203051..09ab071b 100644
--- a/src/pulsecore/dbus-util.c
+++ b/src/pulsecore/dbus-util.c
@@ -595,14 +595,19 @@ void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_repl
void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
DBusMessageIter array_iter;
+ unsigned i;
+ unsigned item_size;
pa_assert(iter);
pa_assert(dbus_type_is_basic(item_type));
pa_assert(array || n == 0);
+ item_size = basic_type_size(item_type);
+
pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
- pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, item_type, array, n));
+ for (i = 0; i < n; ++i)
+ pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
};
diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
index 1867525b..e342a579 100644
--- a/src/pulsecore/flist.c
+++ b/src/pulsecore/flist.c
@@ -83,13 +83,14 @@ static void stack_push(pa_atomic_ptr_t *list, pa_flist_elem *new_elem) {
pa_flist *pa_flist_new_with_name(unsigned size, const char *name) {
pa_flist *l;
unsigned i;
+ pa_assert(name);
if (!size)
size = FLIST_SIZE;
l = pa_xmalloc0(sizeof(pa_flist) + sizeof(pa_flist_elem) * size);
- l->name = name;
+ l->name = pa_xstrdup(name);
l->size = size;
pa_atomic_ptr_store(&l->stored, NULL);
pa_atomic_ptr_store(&l->empty, NULL);
@@ -105,6 +106,7 @@ pa_flist *pa_flist_new(unsigned size) {
void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) {
pa_assert(l);
+ pa_assert(l->name);
if (free_cb) {
pa_flist_elem *elem;
@@ -122,7 +124,7 @@ int pa_flist_push(pa_flist *l, void *p) {
elem = stack_pop(&l->empty);
if (elem == NULL) {
- if (pa_log_ratelimit())
+ if (pa_log_ratelimit(PA_LOG_DEBUG))
pa_log_debug("%s flist is full (don't worry)", l->name);
return -1;
}
diff --git a/src/pulsecore/flist.h b/src/pulsecore/flist.h
index 7fb50359..915b1135 100644
--- a/src/pulsecore/flist.h
+++ b/src/pulsecore/flist.h
@@ -33,8 +33,8 @@
typedef struct pa_flist pa_flist;
pa_flist * pa_flist_new(unsigned size);
-/* Freeing the name is responsibility of caller. The name is only used
- * for debug printing. */
+/* Name string is copied and added to flist structure. The original is
+ * responsibility of the caller. The name is only used for debug printing. */
pa_flist * pa_flist_new_with_name(unsigned size, const char *name);
void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb);
diff --git a/src/pulsecore/log.c b/src/pulsecore/log.c
index 0c5a317c..7ba41ee9 100644
--- a/src/pulsecore/log.c
+++ b/src/pulsecore/log.c
@@ -431,7 +431,7 @@ void pa_log_level(pa_log_level_t level, const char *format, ...) {
va_end(ap);
}
-pa_bool_t pa_log_ratelimit(void) {
+pa_bool_t pa_log_ratelimit(pa_log_level_t level) {
/* Not more than 10 messages every 5s */
static PA_DEFINE_RATELIMIT(ratelimit, 5 * PA_USEC_PER_SEC, 10);
@@ -440,5 +440,5 @@ pa_bool_t pa_log_ratelimit(void) {
if (no_rate_limit)
return TRUE;
- return pa_ratelimit_test(&ratelimit);
+ return pa_ratelimit_test(&ratelimit, level);
}
diff --git a/src/pulsecore/log.h b/src/pulsecore/log.h
index 2f379f68..1fd38d44 100644
--- a/src/pulsecore/log.h
+++ b/src/pulsecore/log.h
@@ -135,6 +135,6 @@ LOG_FUNC(error, PA_LOG_ERROR)
#define pa_log pa_log_error
-pa_bool_t pa_log_ratelimit(void);
+pa_bool_t pa_log_ratelimit(pa_log_level_t level);
#endif
diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c
index f38b17c6..454900d1 100644
--- a/src/pulsecore/memblock.c
+++ b/src/pulsecore/memblock.c
@@ -258,7 +258,7 @@ static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) {
slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * (size_t) idx));
if (!slot) {
- if (pa_log_ratelimit())
+ if (pa_log_ratelimit(PA_LOG_DEBUG))
pa_log_debug("Pool full");
pa_atomic_inc(&p->stat.n_pool_full);
return NULL;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 85245a93..cc6a6b1d 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -125,6 +125,10 @@ typedef struct playback_stream {
uint32_t drain_tag;
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_usec_t configured_sink_latency;
pa_buffer_attr buffer_attr;
@@ -1100,6 +1104,8 @@ static playback_stream* playback_stream_new(
s->buffer_attr = *a;
s->adjust_latency = adjust_latency;
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->pop = sink_input_pop_cb;
@@ -1359,42 +1365,35 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
switch (code) {
- case SINK_INPUT_MESSAGE_SEEK: {
- int64_t windex;
-
- windex = 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);
-
- handle_seek(s, windex);
- return 0;
- }
-
+ case SINK_INPUT_MESSAGE_SEEK:
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_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
-
- if (pa_memblockq_push_align(s->memblockq, chunk) < 0) {
+ pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE);
+ windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq));
+ }
- if (pa_log_ratelimit())
+ if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) {
+ if (pa_log_ratelimit(PA_LOG_WARN))
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_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, TRUE);
}
- handle_seek(s, windex);
-
-/* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
-
+ /* If more data is in queue, we rewind later instead. */
+ if (s->seek_windex != -1)
+ 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;
}
@@ -4464,11 +4463,12 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
if (playback_stream_isinstance(stream)) {
playback_stream *ps = PLAYBACK_STREAM(stream);
+ pa_atomic_inc(&ps->seek_or_post_in_queue);
if (chunk->memblock) {
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, NULL, NULL);
-
- pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, 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);
+ else
+ pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
} else
pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset+chunk->length, NULL, NULL);
diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c
index 1d4ac177..3e0bfa3b 100644
--- a/src/pulsecore/pstream.c
+++ b/src/pulsecore/pstream.c
@@ -832,7 +832,7 @@ static int do_read(pa_pstream *p) {
ntohl(p->read.shm_info[PA_PSTREAM_SHM_INDEX]),
ntohl(p->read.shm_info[PA_PSTREAM_SHM_LENGTH])))) {
- if (pa_log_ratelimit())
+ if (pa_log_ratelimit(PA_LOG_DEBUG))
pa_log_debug("Failed to import memory block.");
}
diff --git a/src/pulsecore/ratelimit.c b/src/pulsecore/ratelimit.c
index 844dd77d..a274d2cc 100644
--- a/src/pulsecore/ratelimit.c
+++ b/src/pulsecore/ratelimit.c
@@ -35,7 +35,7 @@ static pa_static_mutex mutex = PA_STATIC_MUTEX_INIT;
/* Modelled after Linux' lib/ratelimit.c by Dave Young
* <hidave.darkstar@gmail.com>, which is licensed GPLv2. */
-pa_bool_t pa_ratelimit_test(pa_ratelimit *r) {
+pa_bool_t pa_ratelimit_test(pa_ratelimit *r, pa_log_level_t t) {
pa_usec_t now;
pa_mutex *m;
@@ -52,7 +52,7 @@ pa_bool_t pa_ratelimit_test(pa_ratelimit *r) {
r->begin + r->interval < now) {
if (r->n_missed > 0)
- pa_log_warn("%u events suppressed", r->n_missed);
+ pa_logl(t, "%u events suppressed", r->n_missed);
r->begin = now;
diff --git a/src/pulsecore/ratelimit.h b/src/pulsecore/ratelimit.h
index 9857a291..9a36195d 100644
--- a/src/pulsecore/ratelimit.h
+++ b/src/pulsecore/ratelimit.h
@@ -23,6 +23,7 @@
***/
#include <pulse/sample.h>
+#include <pulsecore/log.h>
#include <pulsecore/macro.h>
typedef struct pa_ratelimit {
@@ -51,6 +52,6 @@ typedef struct pa_ratelimit {
r->begin = 0; \
} while (FALSE);
-pa_bool_t pa_ratelimit_test(pa_ratelimit *r);
+pa_bool_t pa_ratelimit_test(pa_ratelimit *r, pa_log_level_t t);
#endif
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 7b4e626d..62000e0d 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -751,8 +751,11 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
if (s->thread_info.state == PA_SINK_SUSPENDED)
return;
- if (nbytes > 0)
+ if (nbytes > 0) {
pa_log_debug("Processing rewind...");
+ if (s->flags & PA_SINK_SYNC_VOLUME)
+ pa_sink_volume_change_rewind(s, nbytes);
+ }
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
pa_sink_input_assert_ref(i);
@@ -762,8 +765,6 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
if (nbytes > 0) {
if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
pa_source_process_rewind(s->monitor_source, nbytes);
- if (s->flags & PA_SINK_SYNC_VOLUME)
- pa_sink_volume_change_rewind(s, nbytes);
}
}
@@ -2905,10 +2906,7 @@ void pa_sink_volume_change_push(pa_sink *s) {
return;
}
- /* Get the latency of the sink */
- if (PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &nc->at, 0, NULL) < 0)
- nc->at = 0;
-
+ nc->at = pa_sink_get_latency_within_thread(s);
nc->at += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
if (s->thread_info.volume_changes_tail) {
@@ -2991,7 +2989,7 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
if (s->thread_info.volume_changes) {
if (usec_to_next)
*usec_to_next = s->thread_info.volume_changes->at - now;
- if (pa_log_ratelimit())
+ if (pa_log_ratelimit(PA_LOG_DEBUG))
pa_log_debug("Next volume change in %lld usec", s->thread_info.volume_changes->at - now);
}
else {
@@ -3006,20 +3004,25 @@ pa_bool_t pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes) {
/* All the queued volume events later than current latency are shifted to happen earlier. */
pa_sink_volume_change *c;
+ pa_volume_t prev_vol = pa_cvolume_avg(&s->thread_info.current_hw_volume);
pa_usec_t rewound = pa_bytes_to_usec(nbytes, &s->sample_spec);
- pa_usec_t limit;
-
- /* Get the latency of the sink */
- if (PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &limit, 0, NULL) < 0)
- limit = 0;
+ pa_usec_t limit = pa_sink_get_latency_within_thread(s);
+ pa_log_debug("latency = %lld", limit);
limit += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
PA_LLIST_FOREACH(c, s->thread_info.volume_changes) {
- if (c->at > limit) {
+ pa_usec_t modified_limit = limit;
+ if (prev_vol > pa_cvolume_avg(&c->hw_volume))
+ modified_limit -= s->thread_info.volume_change_safety_margin;
+ else
+ modified_limit += s->thread_info.volume_change_safety_margin;
+ if (c->at > modified_limit) {
c->at -= rewound;
- if (c->at < limit)
- c->at = limit;
+ if (c->at < modified_limit)
+ c->at = modified_limit;
}
+ prev_vol = pa_cvolume_avg(&c->hw_volume);
}
+ pa_sink_volume_change_apply(s, NULL);
}