summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--doc/todo14
-rw-r--r--polyp/cmdline.c10
-rw-r--r--polyp/cmdline.h1
-rw-r--r--polyp/main.c4
-rw-r--r--polyp/mainloop.c66
-rw-r--r--polyp/mainloop.h2
-rw-r--r--polyp/memblockq.c4
-rw-r--r--polyp/polyplib-context.c9
-rw-r--r--polyp/polyplib-def.h4
-rw-r--r--polyp/polyplib-stream.c22
-rw-r--r--polyp/protocol-native.c12
-rw-r--r--polyp/pstream.c4
-rw-r--r--polyp/resampler.c20
-rw-r--r--polyp/sconv-s16le.c4
-rw-r--r--polyp/sink-input.c9
-rw-r--r--polyp/tagstruct.c24
-rw-r--r--polyp/tagstruct.h2
-rw-r--r--polyp/util.c54
-rw-r--r--polyp/util.h5
20 files changed, 211 insertions, 61 deletions
diff --git a/configure.ac b/configure.ac
index d278ff8e..3b12b72b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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])
diff --git a/doc/todo b/doc/todo
index daed6864..35e0b224 100644
--- a/doc/todo
+++ b/doc/todo
@@ -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)
diff --git a/polyp/cmdline.c b/polyp/cmdline.c
index 1d650185..e6f4101d 100644
--- a/polyp/cmdline.c
+++ b/polyp/cmdline.c
@@ -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);
}
diff --git a/polyp/cmdline.h b/polyp/cmdline.h
index d49b65fb..bf909c84 100644
--- a/polyp/cmdline.h
+++ b/polyp/cmdline.h
@@ -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;
};
diff --git a/polyp/main.c b/polyp/main.c
index 29a7b548..2131877d 100644
--- a/polyp/main.c
+++ b/polyp/main.c
@@ -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
diff --git a/polyp/mainloop.c b/polyp/mainloop.c
index 22cd85c8..c4e12ac1 100644
--- a/polyp/mainloop.c
+++ b/polyp/mainloop.c
@@ -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) {
diff --git a/polyp/mainloop.h b/polyp/mainloop.h
index 5d4fd990..a0fe126f 100644
--- a/polyp/mainloop.h
+++ b/polyp/mainloop.h
@@ -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. */
diff --git a/polyp/memblockq.c b/polyp/memblockq.c
index a79814be..59794d6c 100644
--- a/polyp/memblockq.c
+++ b/polyp/memblockq.c
@@ -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);
}
diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c
index caaa1dbb..a15e4257 100644
--- a/polyp/polyplib-context.c
+++ b/polyp/polyplib-context.c
@@ -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);
diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h
index 067ebf89..176e1d3b 100644
--- a/polyp/polyplib-def.h
+++ b/polyp/polyplib-def.h
@@ -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. */
};
diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c
index a66a0fc6..e128a773 100644
--- a/polyp/polyplib-stream.c
+++ b/polyp/polyplib-stream.c
@@ -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);
diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c
index 943d6b22..058ba9cc 100644
--- a/polyp/protocol-native.c
+++ b/polyp/protocol-native.c
@@ -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;
diff --git a/polyp/pstream.c b/polyp/pstream.c
index 1883c95d..4ee296ce 100644
--- a/polyp/pstream.c
+++ b/polyp/pstream.c
@@ -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;
diff --git a/polyp/resampler.c b/polyp/resampler.c
index b6b87607..173c0987 100644
--- a/polyp/resampler.c
+++ b/polyp/resampler.c
@@ -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;
+ }
}
diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c
index 45b28bdb..40376b52 100644
--- a/polyp/sconv-s16le.c
+++ b/polyp/sconv-s16le.c
@@ -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--) {
diff --git a/polyp/sink-input.c b/polyp/sink-input.c
index f4f57343..b0096182 100644
--- a/polyp/sink-input.c
+++ b/polyp/sink-input.c
@@ -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);
diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c
index 5aa79e6c..55132cae 100644
--- a/polyp/tagstruct.c
+++ b/polyp/tagstruct.c
@@ -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;
+
+}
diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h
index 9a91ee96..915a9a65 100644
--- a/polyp/tagstruct.h
+++ b/polyp/tagstruct.h
@@ -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);
diff --git a/polyp/util.c b/polyp/util.c
index 408e60e9..eeb1d192 100644
--- a/polyp/util.c
+++ b/polyp/util.c
@@ -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 (pa_timeval_cmp(a, b) < 0) {
+ const struct timeval *c;
+ c = a;
+ a = b;
+ b = c;
+ }
- if (tv->tv_sec == 0)
- return 0;
+ r = (a->tv_sec - b->tv_sec)* 1000000;
- gettimeofday(&now, NULL);
-
- r = (now.tv_sec-tv->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) {
diff --git a/polyp/util.h b/polyp/util.h
index 18f883f0..adc4429b 100644
--- a/polyp/util.h
+++ b/polyp/util.h
@@ -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);