]> code.delx.au - pulseaudio/commitdiff
add support for module search path as command line argument
authorLennart Poettering <lennart@poettering.net>
Fri, 10 Sep 2004 22:35:12 +0000 (22:35 +0000)
committerLennart Poettering <lennart@poettering.net>
Fri, 10 Sep 2004 22:35:12 +0000 (22:35 +0000)
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

20 files changed:
configure.ac
doc/todo
polyp/cmdline.c
polyp/cmdline.h
polyp/main.c
polyp/mainloop.c
polyp/mainloop.h
polyp/memblockq.c
polyp/polyplib-context.c
polyp/polyplib-def.h
polyp/polyplib-stream.c
polyp/protocol-native.c
polyp/pstream.c
polyp/resampler.c
polyp/sconv-s16le.c
polyp/sink-input.c
polyp/tagstruct.c
polyp/tagstruct.h
polyp/util.c
polyp/util.h

index d278ff8e46257954cd358710d271cd262353b552..3b12b72bdb6068203dd5e13b87dda5a3d740055d 100644 (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])
index daed68643347d0494f6cdc27f72afb9873ff4e81..35e0b224e9605d10049256ef4decbb6499331675 100644 (file)
--- a/doc/todo
+++ b/doc/todo
 - 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)
index 1d6501859b0efa1d3d80853b9730d00ea4b2c338..e6f4101d2265f8d1e849c1a5e3880074d9fd0dcb 100644 (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);
 }
index d49b65fbdca3279a37adf16dbafb96b53c5b41e9..bf909c8424a4cf24a81470a97aee382e8f3f8263 100644 (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;
 };
 
index 29a7b548e6d2a34d565f4b2d665e9686a8d93623..2131877df7564b4c8baaa4714f48bfb1c0ff07ad 100644 (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
index 22cd85c8dd99531675c70e420de16197d9fea5f3..c4e12ac1cced350557765cc4f100b3a491ab63aa 100644 (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) {
index 5d4fd9904c5d6045d36e05f754e167986af756c6..a0fe126fd5ce490c4158d82c4586e0134893b9f5 100644 (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. */
index a79814be8b7eb5c6b631a844fdb1a47cc235cbac..59794d6c12a9b4d97d519750d94884c855b9f596 100644 (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);
 }
index caaa1dbb9b28261395f64beadac38062483d5e60..a15e4257dd0e8c1efd22beb574669f369ca6c016 100644 (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);
index 067ebf891b1dff74f4f957f551b873bf02d622f4..176e1d3b56f6a1ad2c7845a7f2c0c171d550f326 100644 (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. */  
 };
index a66a0fc6a2dfc60d64bffdefb9f7c089bfe354f9..e128a773c8fd7ae5376d5aff476ec8c5961889ea 100644 (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);
 
index 943d6b22da31e438d1c427cf6e6c74eae1df9d98..058ba9cc5b84ffb6afcb9bdc042516515fdc504b 100644 (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;
index 1883c95d65d1e26c5dfa08a31e7a58f8d94f43ba..4ee296cec9b7734782e25b3e5ed1683ef712e798 100644 (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;
index b6b8760763b4412051ec316cc585645964ecbfdf..173c0987f45f089a31e5b77190e83bc18c5cdc69 100644 (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;
+    }
 }
index 45b28bdb5295d91bab1475bc4160dc2fa07b134e..40376b52fd744cac047b969b4cc854cc1f152248 100644 (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--) {
index f4f57343314c9b36f5e1542e4dc2cce191d74aad..b00961824e5cacc09675bb8de50ca0a35fffcb90 100644 (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);
index 5aa79e6c203262c8bcabfb1247fb8a0de130538e..55132caee57d5329ee670a09fdef85e34a2452d2 100644 (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;
+    
+}
 
index 9a91ee962f253922241652414e926a18880f88ea..915a9a65b42438c4a4907c2fa6cb47fbad4fcd61 100644 (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);
index 408e60e9aec715edf340c6d56a7461f873da5ccd..eeb1d1922d526aeb869e4c36a01eeaac99737f57 100644 (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 (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) {
index 18f883f0bb922cf484d2f75047b142cfd55693dc..adc4429bc9660b48a623859e351b35454b83f124 100644 (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);