add support for module search path as command line argument

protocol-native: move first data request into ack of stream creation
improve mainloop API: return the number of dispatched sources on iterate()
fix a resampling bug
introduce network latency measurement

WARNING: all these changes together may break some applications


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@189 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-09-10 22:35:12 +00:00
parent 0c99fb3182
commit 25123469d5
20 changed files with 210 additions and 60 deletions

View file

@ -20,7 +20,7 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
AC_PREREQ(2.57)
AC_INIT([polypaudio],[0.4],[mzcbylcnhqvb (at) 0pointer (dot) de])
AC_INIT([polypaudio],[0.5],[mzcbylcnhqvb (at) 0pointer (dot) de])
AC_CONFIG_SRCDIR([polyp/main.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([foreign -Wall])

View file

@ -12,6 +12,13 @@
- add sample directory
- config file for command line arguments
- option to use default fragment size on alsa drivers
- keep volume in xmms-polyp (and allow volume changing when not playing)
- lazy sample cache
- per-channel volume
- add version number to library names
- extend pa_usec_t to 64 bit
- make use of network latency in all apps
- rename streams/contexts
** later ***
- xmlrpc/http
@ -23,7 +30,8 @@
***********
backends for:
- mplayer
- sdl
- gstreamer
- portaudio
- sdl
- gstreamer (semi-done)
- alsa-lib
- OSS (esddsp style)

View file

@ -78,6 +78,7 @@ void pa_cmdline_help(const char *argv0) {
" -X SECS Terminate the daemon after the last client quit and this time passed\n"
" -h Show this help\n"
" -l TARGET Specify the log target (syslog, stderr, auto)\n"
" -p DIR Append a directory to the search path for dynamic modules\n"
" -V Show version\n", e, cfg);
pa_xfree(cfg);
@ -101,11 +102,12 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
cmdline->fail = cmdline->auto_log_target = 1;
cmdline->quit_after_last_client_time = -1;
cmdline->log_target = -1;
cmdline->dl_searchdir = NULL;
buf = pa_strbuf_new();
assert(buf);
while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:")) != -1) {
while ((c = getopt(argc, argv, "L:F:CDhfvrRVndX:l:p:")) != -1) {
switch (c) {
case 'L':
pa_strbuf_printf(buf, "load %s\n", optarg);
@ -146,6 +148,11 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) {
case 'X':
cmdline->quit_after_last_client_time = atoi(optarg);
break;
case 'p':
if (cmdline->dl_searchdir)
pa_xfree(cmdline->dl_searchdir);
cmdline->dl_searchdir = pa_xstrdup(optarg);
break;
case 'l':
if (!strcmp(optarg, "syslog")) {
cmdline->auto_log_target = 0;
@ -185,5 +192,6 @@ fail:
void pa_cmdline_free(struct pa_cmdline *cmd) {
assert(cmd);
pa_xfree(cmd->cli_commands);
pa_xfree(cmd->dl_searchdir);
pa_xfree(cmd);
}

View file

@ -36,6 +36,7 @@ struct pa_cmdline {
quit_after_last_client_time,
auto_log_target;
char *cli_commands;
char *dl_searchdir;
enum pa_log_target log_target;
};

View file

@ -180,6 +180,10 @@ int main(int argc, char *argv[]) {
r = lt_dlinit();
assert(r == 0);
if (cmdline->dl_searchdir)
lt_dladdsearchdir(cmdline->dl_searchdir);
#ifdef DLSEARCHDIR
lt_dladdsearchdir(DLSEARCHDIR);
#endif

View file

@ -378,9 +378,10 @@ static void rebuild_pollfds(struct pa_mainloop *m) {
}
}
static void dispatch_pollfds(struct pa_mainloop *m) {
static int dispatch_pollfds(struct pa_mainloop *m) {
uint32_t index = PA_IDXSET_INVALID;
struct pa_io_event *e;
int r = 0;
for (e = pa_idxset_first(m->io_events, &index); e; e = pa_idxset_next(m->io_events, &index)) {
if (e->dead || !e->pollfd || !e->pollfd->revents)
@ -394,12 +395,16 @@ static void dispatch_pollfds(struct pa_mainloop *m) {
(e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0),
e->userdata);
e->pollfd->revents = 0;
r++;
}
return r;
}
static void dispatch_defer(struct pa_mainloop *m) {
static int dispatch_defer(struct pa_mainloop *m) {
uint32_t index;
struct pa_defer_event *e;
int r = 0;
for (e = pa_idxset_first(m->defer_events, &index); e; e = pa_idxset_next(m->defer_events, &index)) {
if (e->dead || !e->enabled)
@ -407,7 +412,10 @@ static void dispatch_defer(struct pa_mainloop *m) {
assert(e->callback);
e->callback(&m->api, e, e->userdata);
r++;
}
return r;
}
static int calc_next_timeout(struct pa_mainloop *m) {
@ -451,15 +459,16 @@ static int calc_next_timeout(struct pa_mainloop *m) {
return t;
}
static void dispatch_timeout(struct pa_mainloop *m) {
static int dispatch_timeout(struct pa_mainloop *m) {
uint32_t index;
struct pa_time_event *e;
struct timeval now;
int got_time = 0;
int r = 0;
assert(m);
if (pa_idxset_isempty(m->time_events))
return;
return 0;
for (e = pa_idxset_first(m->time_events, &index); e; e = pa_idxset_next(m->time_events, &index)) {
@ -477,51 +486,66 @@ static void dispatch_timeout(struct pa_mainloop *m) {
e->enabled = 0;
e->callback(&m->api, e, &e->timeval, e->userdata);
r++;
}
}
return r;
}
int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval) {
int r;
int r, t, dispatched = 0;
assert(m && !m->running);
if(m->quit) {
if (retval)
*retval = m->retval;
return 1;
return -2;
}
m->running = 1;
scan_dead(m);
dispatch_defer(m);
dispatched += dispatch_defer(m);
if (m->rebuild_pollfds) {
rebuild_pollfds(m);
m->rebuild_pollfds = 0;
}
do {
int t = block ? calc_next_timeout(m) : 0;
/*pa_log(__FILE__": %u\n", t);*/
r = poll(m->pollfds, m->n_pollfds, t);
} while (r < 0 && errno == EINTR);
t = block ? calc_next_timeout(m) : 0;
r = poll(m->pollfds, m->n_pollfds, t);
dispatch_timeout(m);
if (r > 0)
dispatch_pollfds(m);
else if (r < 0)
pa_log(__FILE__": select(): %s\n", strerror(errno));
if (r < 0) {
if (errno == EINTR)
r = 0;
else
pa_log(__FILE__": select(): %s\n", strerror(errno));
} else {
dispatched += dispatch_timeout(m);
if (r > 0)
dispatched += dispatch_pollfds(m);
}
m->running = 0;
return r < 0 ? -1 : 0;
/* pa_log("dispatched: %i\n", dispatched); */
return r < 0 ? -1 : dispatched;
}
int pa_mainloop_run(struct pa_mainloop *m, int *retval) {
int r;
while ((r = pa_mainloop_iterate(m, 1, retval)) == 0);
return r;
while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0);
if (r == -2)
return 1;
else if (r < 0)
return -1;
else
return 0;
}
void pa_mainloop_quit(struct pa_mainloop *m, int r) {

View file

@ -50,7 +50,7 @@ void pa_mainloop_free(struct pa_mainloop* m);
on error or exit request. If block is nonzero, block for events if
none are queued. Optionally return the return value as specified with
the main loop's quit() routine in the integer variable retval points
to */
to. On success returns the number of source dispatched in this iteration. */
int pa_mainloop_iterate(struct pa_mainloop *m, int block, int *retval);
/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */

View file

@ -149,9 +149,9 @@ int pa_memblockq_peek(struct pa_memblockq* bq, struct pa_memchunk *chunk) {
void pa_memblockq_drop(struct pa_memblockq *bq, const struct pa_memchunk *chunk, size_t length) {
assert(bq && chunk && length);
if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(struct pa_memchunk)))
if (!bq->blocks || memcmp(&bq->blocks->chunk, chunk, sizeof(struct pa_memchunk)))
return;
assert(length <= bq->blocks->chunk.length);
pa_memblockq_skip(bq, length);
}

View file

@ -431,11 +431,10 @@ void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_co
int pa_context_is_pending(struct pa_context *c) {
assert(c && c->ref >= 1);
if (c->state != PA_CONTEXT_READY)
return 0;
assert(c->pstream && c->pdispatch);
return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
/* pa_log("pstream: %i\n", pa_pstream_is_pending(c->pstream)); */
/* pa_log("pdispatch: %i\n", pa_pdispatch_is_pending(c->pdispatch)); */
return (c->pstream && pa_pstream_is_pending(c->pstream)) || (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || c->client;
}
static void set_dispatch_callbacks(struct pa_operation *o);

View file

@ -133,7 +133,8 @@ enum pa_subscription_event_type {
/** A structure for latency info. See pa_stream_get_latency(). The
* total latency a sample that is written with pa_stream_write() takes
* to be played is buffer_usec+sink_usec. The buffer to which
* to be played may be estimated by
* buffer_usec+sink_usec+transport_usec. The buffer to which
* buffer_usec relates may be manipulated freely (with
* pa_stream_write()'s delta argument, pa_stream_flush() and friends),
* the playback buffer sink_usec relates to is a FIFO which cannot be
@ -141,6 +142,7 @@ enum pa_subscription_event_type {
struct pa_latency_info {
pa_usec_t buffer_usec; /**< Time in usecs the current buffer takes to play */
pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. */
pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to the daemon. \since 0.5 */
int playing; /**< Non-zero when the stream is currently playing */
uint32_t queue_length; /**< Queue size in bytes. */
};

View file

@ -30,6 +30,7 @@
#include "polyplib-internal.h"
#include "xmalloc.h"
#include "pstream-util.h"
#include "util.h"
struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) {
struct pa_stream *s;
@ -193,6 +194,7 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32
if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
((s->direction == PA_STREAM_PLAYBACK) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0) ||
!pa_tagstruct_eof(t)) {
pa_context_fail(s->context, PA_ERROR_PROTOCOL);
goto finish;
@ -202,6 +204,9 @@ void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32
pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
pa_stream_set_state(s, PA_STREAM_READY);
if (s->requested_bytes && s->ref > 1 && s->write_callback)
s->write_callback(s, s->requested_bytes, s->write_userdata);
finish:
pa_stream_unref(s);
}
@ -321,6 +326,7 @@ struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa
static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
struct pa_operation *o = userdata;
struct pa_latency_info i, *p = NULL;
struct timeval local, remote, now;
assert(pd && o && o->stream && o->context);
if (command != PA_COMMAND_REPLY) {
@ -331,12 +337,23 @@ static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t comman
pa_tagstruct_getu32(t, &i.sink_usec) < 0 ||
pa_tagstruct_get_boolean(t, &i.playing) < 0 ||
pa_tagstruct_getu32(t, &i.queue_length) < 0 ||
pa_tagstruct_get_timeval(t, &local) < 0 ||
pa_tagstruct_get_timeval(t, &remote) < 0 ||
!pa_tagstruct_eof(t)) {
pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish;
} else
p = &i;
gettimeofday(&now, NULL);
if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now))
/* local and remote seem to have synchronized clocks */
i.transport_usec = pa_timeval_diff(&remote, &local);
else
/* clocks are not synchronized, let's estimate latency then */
i.transport_usec = pa_timeval_diff(&now, &local)/2;
if (o->callback) {
void (*cb)(struct pa_stream *s, const struct pa_latency_info *i, void *userdata) = o->callback;
cb(o->stream, p, o->userdata);
@ -351,6 +368,7 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc
uint32_t tag;
struct pa_operation *o;
struct pa_tagstruct *t;
struct timeval now;
o = pa_operation_new(s->context, s);
assert(o);
@ -362,6 +380,10 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struc
pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
pa_tagstruct_putu32(t, tag = s->context->ctag++);
pa_tagstruct_putu32(t, s->channel);
gettimeofday(&now, NULL);
pa_tagstruct_put_timeval(t, &now);
pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, o);

View file

@ -342,7 +342,7 @@ static void request_bytes(struct playback_stream *s) {
if (!(l = pa_memblockq_missing(s->memblockq)))
return;
if (l <= s->requested_bytes)
return;
@ -361,7 +361,7 @@ static void request_bytes(struct playback_stream *s) {
pa_tagstruct_putu32(t, l);
pa_pstream_send_tagstruct(s->connection->pstream, t);
/*pa_log(__FILE__": Requesting %u bytes\n", l);*/
/* pa_log(__FILE__": Requesting %u bytes\n", l); */
}
static void send_memblock(struct connection *c) {
@ -541,6 +541,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com
pa_tagstruct_putu32(reply, s->index);
assert(s->sink_input);
pa_tagstruct_putu32(reply, s->sink_input->index);
pa_tagstruct_putu32(reply, s->requested_bytes = pa_memblockq_missing(s->memblockq));
pa_pstream_send_tagstruct(c->pstream, reply);
request_bytes(s);
}
@ -809,10 +810,12 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma
struct connection *c = userdata;
struct pa_tagstruct *reply;
struct playback_stream *s;
struct timeval tv, now;
uint32_t index;
assert(c && t);
if (pa_tagstruct_getu32(t, &index) < 0 ||
pa_tagstruct_get_timeval(t, &tv) < 0 ||
!pa_tagstruct_eof(t)) {
protocol_error(c);
return;
@ -836,6 +839,9 @@ static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t comma
pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink));
pa_tagstruct_put_boolean(reply, pa_memblockq_is_readable(s->memblockq));
pa_tagstruct_putu32(reply, pa_memblockq_get_length(s->memblockq));
pa_tagstruct_put_timeval(reply, &tv);
gettimeofday(&now, NULL);
pa_tagstruct_put_timeval(reply, &now);
pa_pstream_send_tagstruct(c->pstream, reply);
}
@ -1439,7 +1445,7 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui
/*pa_log(__FILE__": after_recv: %u\n", pa_memblockq_get_length(p->memblockq));*/
pa_sink_notify(p->sink_input->sink);
/*pa_log(__FILE__": Recieved %u bytes.\n", chunk->length);*/
/* pa_log(__FILE__": Recieved %u bytes.\n", chunk->length); */
} else {
struct upload_stream *u = (struct upload_stream*) stream;

View file

@ -215,7 +215,7 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) {
struct item_info *i;
assert(p && packet);
/*pa_log(__FILE__": push-packet %p\n", packet);*/
/* pa_log(__FILE__": push-packet %p\n", packet); */
i = pa_xmalloc(sizeof(struct item_info));
i->type = PA_PSTREAM_ITEM_PACKET;
@ -228,6 +228,8 @@ void pa_pstream_send_packet(struct pa_pstream*p, struct pa_packet *packet) {
void pa_pstream_send_memblock(struct pa_pstream*p, uint32_t channel, uint32_t delta, const struct pa_memchunk *chunk) {
struct item_info *i;
assert(p && channel != (uint32_t) -1 && chunk);
/* pa_log(__FILE__": push-memblock %p\n", chunk); */
i = pa_xmalloc(sizeof(struct item_info));
i->type = PA_PSTREAM_ITEM_MEMBLOCK;

View file

@ -23,7 +23,6 @@
#include <config.h>
#endif
#include <stdlib.h>
#include <assert.h>
#include <samplerate.h>
@ -31,6 +30,7 @@
#include "resampler.h"
#include "sconv.h"
#include "xmalloc.h"
#include "log.h"
struct pa_resampler {
struct pa_sample_spec i_ss, o_ss;
@ -120,6 +120,8 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru
/* How many input samples? */
ins = in->length/r->i_sz;
/* pa_log("%u / %u = %u\n", in->length, r->i_sz, ins); */
/* How much space for output samples? */
if (r->src_state)
ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024;
@ -137,6 +139,9 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru
eff_ins = ins;
eff_ons = ons;
}
/* pa_log("eff_ins = %u \n", eff_ins); */
out->memblock = pa_memblock_new(out->length = (ons*r->o_sz), r->memblock_stat);
out->index = 0;
@ -145,7 +150,9 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru
if (r->i_alloc < eff_ins)
r->i_buf = pa_xrealloc(r->i_buf, sizeof(float) * (r->i_alloc = eff_ins));
assert(r->i_buf);
/* pa_log("eff_ins = %u \n", eff_ins); */
r->to_float32_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, r->i_buf);
if (r->src_state) {
@ -179,6 +186,13 @@ void pa_resampler_run(struct pa_resampler *r, const struct pa_memchunk *in, stru
} else
cbuf = r->i_buf;
r->from_float32_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels);
if (eff_ons)
r->from_float32_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels);
out->length = ons*r->o_sz;
if (!out->length) {
pa_memblock_unref(out->memblock);
out->memblock = NULL;
}
}

View file

@ -28,6 +28,7 @@
#include "endianmacros.h"
#include "sconv.h"
#include "log.h"
#ifndef INT16_FROM
#define INT16_FROM INT16_FROM_LE
@ -61,6 +62,9 @@ void pa_sconv_s16le_to_float32(unsigned n, const void *a, unsigned an, float *b)
void pa_sconv_s16le_from_float32(unsigned n, const float *a, void *b, unsigned bn) {
int16_t *cb = b;
/* pa_log("%u %p %p %u\n", n, a, b, bn); */
assert(n && a && b && bn);
for (; n > 0; n--) {

View file

@ -129,7 +129,7 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) {
if (!i->resampler)
return i->peek(i, chunk);
if (!i->resampled_chunk.memblock) {
while (!i->resampled_chunk.memblock) {
struct pa_memchunk tchunk;
size_t l;
int ret;
@ -141,10 +141,11 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) {
l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
if (tchunk.length > l)
tchunk.length = l;
if (l > tchunk.length)
l = tchunk.length;
i->drop(i, &tchunk, tchunk.length);
i->drop(i, &tchunk, l);
tchunk.length = l;
pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk);
pa_memblock_unref(tchunk.memblock);

View file

@ -43,6 +43,7 @@ enum tags {
TAG_ARBITRARY = 'x',
TAG_BOOLEAN_TRUE = '1',
TAG_BOOLEAN_FALSE = '0',
TAG_TIMEVAL = 'T',
};
struct pa_tagstruct {
@ -145,6 +146,15 @@ void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b) {
t->length += 1;
}
void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv) {
assert(t);
extend(t, 9);
t->data[t->length] = TAG_TIMEVAL;
*((uint32_t*) (t->data+t->length+1)) = htonl(tv->tv_sec);
*((uint32_t*) (t->data+t->length+5)) = htonl(tv->tv_usec);
t->length += 9;
}
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) {
int error = 0;
size_t n;
@ -263,4 +273,18 @@ int pa_tagstruct_get_boolean(struct pa_tagstruct*t, int *b) {
return 0;
}
int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv) {
if (t->rindex+9 > t->length)
return -1;
if (t->data[t->rindex] != TAG_TIMEVAL)
return -1;
tv->tv_sec = ntohl(*((uint32_t*) (t->data+t->rindex+1)));
tv->tv_usec = ntohl(*((uint32_t*) (t->data+t->rindex+5)));
t->rindex += 9;
return 0;
}

View file

@ -39,6 +39,7 @@ void pa_tagstruct_putu8(struct pa_tagstruct*t, uint8_t c);
void pa_tagstruct_put_sample_spec(struct pa_tagstruct *t, const struct pa_sample_spec *ss);
void pa_tagstruct_put_arbitrary(struct pa_tagstruct*t, const void *p, size_t length);
void pa_tagstruct_put_boolean(struct pa_tagstruct*t, int b);
void pa_tagstruct_put_timeval(struct pa_tagstruct*t, const struct timeval *tv);
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s);
int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i);
@ -46,6 +47,7 @@ int pa_tagstruct_getu8(struct pa_tagstruct*t, uint8_t *c);
int pa_tagstruct_get_sample_spec(struct pa_tagstruct *t, struct pa_sample_spec *ss);
int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t length);
int pa_tagstruct_get_boolean(struct pa_tagstruct *t, int *b);
int pa_tagstruct_get_timeval(struct pa_tagstruct*t, struct timeval *tv);
int pa_tagstruct_eof(struct pa_tagstruct*t);
const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l);

View file

@ -221,26 +221,52 @@ char *pa_get_host_name(char *s, size_t l) {
return s;
}
uint32_t pa_age(struct timeval *tv) {
struct timeval now;
uint32_t r;
assert(tv);
pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) {
pa_usec_t r;
assert(a && b);
if (tv->tv_sec == 0)
return 0;
if (pa_timeval_cmp(a, b) < 0) {
const struct timeval *c;
c = a;
a = b;
b = c;
}
gettimeofday(&now, NULL);
r = (now.tv_sec-tv->tv_sec) * 1000000;
r = (a->tv_sec - b->tv_sec)* 1000000;
if (now.tv_usec >= tv->tv_usec)
r += now.tv_usec - tv->tv_usec;
else
r -= tv->tv_usec - now.tv_usec;
if (a->tv_usec > b->tv_usec)
r += (a->tv_usec - b->tv_usec);
else if (a->tv_usec < b->tv_usec)
r -= (b->tv_usec - a->tv_usec);
return r;
}
int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) {
assert(a && b);
if (a->tv_sec < b->tv_sec)
return -1;
if (a->tv_sec > b->tv_sec)
return 1;
if (a->tv_usec < b->tv_usec)
return -1;
if (a->tv_usec > b->tv_usec)
return 1;
return 0;
}
pa_usec_t pa_age(const struct timeval *tv) {
struct timeval now;
assert(tv);
gettimeofday(&now, NULL);
return pa_timeval_diff(&now, tv);
}
#define NICE_LEVEL (-15)
void pa_raise_priority(void) {

View file

@ -27,6 +27,7 @@
#include <stdarg.h>
#include "gcc-printf.h"
#include "sample.h"
void pa_make_nonblock_fd(int fd);
@ -43,7 +44,9 @@ char *pa_vsprintf_malloc(const char *format, va_list ap);
char *pa_get_user_name(char *s, size_t l);
char *pa_get_host_name(char *s, size_t l);
uint32_t pa_age(struct timeval *tv);
pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b);
int pa_timeval_cmp(const struct timeval *a, const struct timeval *b);
pa_usec_t pa_age(const struct timeval *tv);
void pa_raise_priority(void);
void pa_reset_priority(void);