diff options
| -rw-r--r-- | configure.ac | 2 | ||||
| -rw-r--r-- | doc/todo | 12 | ||||
| -rw-r--r-- | polyp/cli-text.c | 28 | ||||
| -rw-r--r-- | polyp/cpulimit.c | 2 | ||||
| -rw-r--r-- | polyp/main.c | 47 | ||||
| -rw-r--r-- | polyp/memblockq.c | 9 | ||||
| -rw-r--r-- | polyp/memblockq.h | 3 | ||||
| -rw-r--r-- | polyp/native-common.h | 3 | ||||
| -rw-r--r-- | polyp/pacat.c | 8 | ||||
| -rw-r--r-- | polyp/pactl.c | 4 | ||||
| -rw-r--r-- | polyp/polyplib-context.c | 4 | ||||
| -rw-r--r-- | polyp/polyplib-def.h | 5 | ||||
| -rw-r--r-- | polyp/polyplib-internal.h | 2 | ||||
| -rw-r--r-- | polyp/polyplib-simple.c | 4 | ||||
| -rw-r--r-- | polyp/polyplib-stream.c | 102 | ||||
| -rw-r--r-- | polyp/polyplib-stream.h | 40 | ||||
| -rw-r--r-- | polyp/polyplib.h | 7 | ||||
| -rw-r--r-- | polyp/protocol-esound.c | 89 | ||||
| -rw-r--r-- | polyp/protocol-native.c | 76 | ||||
| -rw-r--r-- | polyp/sample.c | 2 | ||||
| -rw-r--r-- | polyp/sample.h | 2 | ||||
| -rw-r--r-- | polyp/sink-input.c | 14 | ||||
| -rw-r--r-- | polyp/sink-input.h | 3 | ||||
| -rw-r--r-- | polyp/source-output.c | 14 | ||||
| -rw-r--r-- | polyp/source-output.h | 3 | ||||
| -rw-r--r-- | polyp/util.c | 1 | 
26 files changed, 392 insertions, 94 deletions
diff --git a/configure.ac b/configure.ac index 24a7e985..3a0675c3 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.5.1],[mzcbylcnhqvb (at) 0pointer (dot) de]) +AC_INIT([polypaudio],[0.6],[mzcbylcnhqvb (at) 0pointer (dot) de])  AC_CONFIG_SRCDIR([polyp/main.c])  AC_CONFIG_HEADERS([config.h])  AM_INIT_AUTOMAKE([foreign -Wall]) @@ -4,23 +4,29 @@  - per-channel volume  - unix socket directories include user name  - add sample directory -- udp based protocol  - make mcalign merge chunks  - option to use default fragment size on alsa drivers  - improve module-oss-mmap latency measurement  - proper locking around native protocol socket +- pacat sample type args +- filter capture data in client through alignment +- paplay +- check module-combine algo +- add redirection module +- add matching module +- add radio module +- make autoload list use idxset  ** later ***  - xmlrpc/http  - dbus  - slp/rendezvous -- modinfo  - make alsa modules use mmap  ***********  backends for: -- portaudio +- portaudio  (semi-done)  - alsa-lib  - sdl  - gstreamer (semi-done) diff --git a/polyp/cli-text.c b/polyp/cli-text.c index 3cedf920..f9bc6c7a 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -64,7 +64,7 @@ char *pa_client_list_to_string(struct pa_core *c) {      s = pa_strbuf_new();      assert(s); -    pa_strbuf_printf(s, "%u client(s).\n", pa_idxset_ncontents(c->clients)); +    pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_ncontents(c->clients));      for (client = pa_idxset_first(c->clients, &index); client; client = pa_idxset_next(c->clients, &index)) {          pa_strbuf_printf(s, "    index: %u\n\tname: <%s>\n\tprotocol_name: <%s>\n", client->index, client->name, client->protocol_name); @@ -148,6 +148,11 @@ char *pa_source_output_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_source_output *o;      uint32_t index = PA_IDXSET_INVALID; +    static const char* const state_table[] = { +        "RUNNING", +        "CORKED", +        "DISCONNECTED" +    };      assert(c);      s = pa_strbuf_new(); @@ -160,15 +165,16 @@ char *pa_source_output_list_to_string(struct pa_core *c) {          pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec);          assert(o->source);          pa_strbuf_printf( -            s, "  index: %u\n\tname: <%s>\n\tsource: <%u>\n\tsample_spec: <%s>\n", +            s, "  index: %u\n\tname: '%s'\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n",              o->index,              o->name, -            o->source->index, +            state_table[o->state], +            o->source->index, o->source->name,              ss);          if (o->owner)              pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index);          if (o->client) -            pa_strbuf_printf(s, "\tclient: <%u>\n", o->client->index); +            pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", o->client->index, o->client->name);      }      return pa_strbuf_tostring_free(s); @@ -178,8 +184,13 @@ char *pa_sink_input_list_to_string(struct pa_core *c) {      struct pa_strbuf *s;      struct pa_sink_input *i;      uint32_t index = PA_IDXSET_INVALID; -    assert(c); +    static const char* const state_table[] = { +        "RUNNING", +        "CORKED", +        "DISCONNECTED" +    }; +    assert(c);      s = pa_strbuf_new();      assert(s); @@ -190,10 +201,11 @@ char *pa_sink_input_list_to_string(struct pa_core *c) {          pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);          assert(i->sink);          pa_strbuf_printf( -            s, "    index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", +            s, "    index: %u\n\tname: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n",              i->index,              i->name, -            i->sink->index, +            state_table[i->state], +            i->sink->index, i->sink->name,              (unsigned) i->volume,              pa_volume_to_dB(i->volume),              (float) pa_sink_input_get_latency(i), @@ -202,7 +214,7 @@ char *pa_sink_input_list_to_string(struct pa_core *c) {          if (i->owner)              pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index);          if (i->client) -            pa_strbuf_printf(s, "\tclient: <%u>\n", i->client->index); +            pa_strbuf_printf(s, "\tclient: <%u> '%s'\n", i->client->index, i->client->name);      }      return pa_strbuf_tostring_free(s); diff --git a/polyp/cpulimit.c b/polyp/cpulimit.c index fc49f5bb..a60c03d7 100644 --- a/polyp/cpulimit.c +++ b/polyp/cpulimit.c @@ -35,7 +35,7 @@  /* Utilize this much CPU time at maximum */  #define CPUTIME_PERCENT 70 -#define CPUTIME_INTERVAL_SOFT (5) +#define CPUTIME_INTERVAL_SOFT (10)  #define CPUTIME_INTERVAL_HARD (2)  static time_t last_time = 0; diff --git a/polyp/main.c b/polyp/main.c index 08677f7f..0837e58d 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -48,6 +48,7 @@  #include "daemon-conf.h"  #include "dumpmodules.h"  #include "caps.h" +#include "cli-text.h"  static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {      pa_log(__FILE__": Got signal %s.\n", pa_strsignal(sig)); @@ -60,7 +61,47 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e,          case SIGUSR2:              pa_module_load(userdata, "module-cli-protocol-unix", NULL);              return; -         + +        case SIGHUP: { +            int i; + +            for (i = 0;; i++) { +                char *c; +                switch (i) { +                    case 0:  +                        c = pa_sink_list_to_string(userdata); +                        break; +                    case 1: +                        c = pa_source_list_to_string(userdata); +                        break; +                    case 2: +                        c = pa_sink_input_list_to_string(userdata); +                        break; +                    case 3: +                        c = pa_source_output_list_to_string(userdata); +                        break; +                    case 4:  +                        c = pa_client_list_to_string(userdata); +                        break; +                    case 5: +                        c = pa_module_list_to_string(userdata); +                        break; +                    case 6: +                        c = pa_scache_list_to_string(userdata); +                        break; +                    case 7: +                        c = pa_autoload_list_to_string(userdata); +                        break; +                    default: +                        return; +                } +                pa_log(c); +                pa_xfree(c); +            } + +            return; +        } +          case SIGINT:          case SIGTERM:          default: @@ -70,7 +111,8 @@ static void signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e,      }  } -static void close_pipe(int p[2]) { + +            static void close_pipe(int p[2]) {      if (p[0] != -1)          close(p[0]);      if (p[1] != -1) @@ -223,6 +265,7 @@ int main(int argc, char *argv[]) {      pa_signal_new(SIGUSR1, signal_callback, c);      pa_signal_new(SIGUSR2, signal_callback, c); +    pa_signal_new(SIGHUP, signal_callback, c);      r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));      assert(r == 0); diff --git a/polyp/memblockq.c b/polyp/memblockq.c index 59794d6c..0e71fa8c 100644 --- a/polyp/memblockq.c +++ b/polyp/memblockq.c @@ -42,7 +42,7 @@ struct memblock_list {  struct pa_memblockq {      struct memblock_list *blocks, *blocks_tail;      unsigned n_blocks; -    size_t current_length, maxlength, tlength, base, prebuf, minreq; +    size_t current_length, maxlength, tlength, base, prebuf, orig_prebuf, minreq;      struct pa_mcalign *mcalign;      struct pa_memblock_stat *memblock_stat;  }; @@ -72,6 +72,8 @@ struct pa_memblockq* pa_memblockq_new(size_t maxlength, size_t tlength, size_t b      bq->prebuf = (bq->prebuf/base)*base;      if (bq->prebuf > bq->maxlength)          bq->prebuf = bq->maxlength; + +    bq->orig_prebuf = bq->prebuf;      bq->minreq = (minreq/base)*base;      if (bq->minreq == 0) @@ -285,6 +287,11 @@ void pa_memblockq_prebuf_disable(struct pa_memblockq *bq) {      bq->prebuf = 0;  } +void pa_memblockq_prebuf_reenable(struct pa_memblockq *bq) { +    assert(bq); +    bq->prebuf = bq->orig_prebuf; +} +  void pa_memblockq_seek(struct pa_memblockq *bq, size_t length) {      assert(bq); diff --git a/polyp/memblockq.h b/polyp/memblockq.h index 16b51d7a..aeed4193 100644 --- a/polyp/memblockq.h +++ b/polyp/memblockq.h @@ -83,6 +83,9 @@ uint32_t pa_memblockq_get_minreq(struct pa_memblockq *bq);  /* Force disabling of pre-buf even when the pre-buffer is not yet filled */  void pa_memblockq_prebuf_disable(struct pa_memblockq *bq); +/* Reenable pre-buf to the initial level */ +void pa_memblockq_prebuf_reenable(struct pa_memblockq *bq); +  /* Manipulate the write pointer */  void pa_memblockq_seek(struct pa_memblockq *bq, size_t delta); diff --git a/polyp/native-common.h b/polyp/native-common.h index a052fca2..5ecb26c0 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -87,6 +87,9 @@ enum {      PA_COMMAND_GET_AUTOLOAD_INFO,      PA_COMMAND_GET_AUTOLOAD_INFO_LIST,      PA_COMMAND_GET_RECORD_LATENCY, +    PA_COMMAND_CORK_RECORD_STREAM, +    PA_COMMAND_FLUSH_RECORD_STREAM, +    PA_COMMAND_PREBUF_PLAYBACK_STREAM,      PA_COMMAND_MAX  }; diff --git a/polyp/pacat.c b/polyp/pacat.c index b9cb047a..1eb37d4d 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -37,6 +37,10 @@  #include <polyp/mainloop.h>  #include <polyp/mainloop-signal.h> +#if PA_API_VERSION != PA_API_VERSION_0_6 +#error Invalid Polypaudio API version +#endif +  static enum { RECORD, PLAYBACK } mode = PLAYBACK;  static struct pa_context *context = NULL; @@ -165,9 +169,9 @@ static void context_state_callback(struct pa_context *c, void *userdata) {              pa_stream_set_read_callback(stream, stream_read_callback, NULL);              if (mode == PLAYBACK) -                pa_stream_connect_playback(stream, device, NULL, volume); +                pa_stream_connect_playback(stream, device, NULL, 0, volume);              else -                pa_stream_connect_record(stream, device, NULL); +                pa_stream_connect_record(stream, device, NULL, 0);              break; diff --git a/polyp/pactl.c b/polyp/pactl.c index 2a466b39..cf2f51c3 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -41,6 +41,10 @@  #include <polyp/mainloop-signal.h>  #include <polyp/sample.h> +#if PA_API_VERSION != PA_API_VERSION_0_6 +#error Invalid Polypaudio API version +#endif +  #define BUFSIZE 1024  static struct pa_context *context = NULL; diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 32ce3888..d793c186 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -218,8 +218,10 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, ui      pa_context_ref(c);      if ((s = pa_dynarray_get(c->record_streams, channel))) { -        if (s->read_callback) +        if (s->read_callback) {              s->read_callback(s, (uint8_t*) chunk->memblock->data + chunk->index, chunk->length, s->read_userdata); +            s->counter += chunk->length; +        }      }      pa_context_unref(c); diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index bab23e47..cd0662dd 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -72,6 +72,11 @@ enum pa_stream_direction {      PA_STREAM_UPLOAD         /**< Sample upload stream */  }; +/** Some special flags for stream connections. \since 0.6 */ +enum pa_stream_flags { +    PA_STREAM_START_CORKED = 1,   /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ +}; +  /** Playback and record buffer metrics */  struct pa_buffer_attr{      uint32_t maxlength;      /**< Maximum length of the buffer */ diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 6e64755d..656d07db 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -92,6 +92,8 @@ struct pa_stream {      uint32_t device_index;      enum pa_stream_direction direction;      uint32_t requested_bytes; +    uint64_t counter; +    pa_usec_t previous_time;      enum pa_stream_state state;      void (*state_callback)(struct pa_stream*c, void *userdata); diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index aa6c88f5..9e111e2a 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -156,9 +156,9 @@ struct pa_simple* pa_simple_new(          goto fail;      if (dir == PA_STREAM_PLAYBACK) -        pa_stream_connect_playback(p->stream, dev, attr, volume); +        pa_stream_connect_playback(p->stream, dev, attr, 0, volume);      else -        pa_stream_connect_record(p->stream, dev, attr); +        pa_stream_connect_record(p->stream, dev, attr, 0);      /* Wait until the stream is ready */      while (pa_stream_get_state(p->stream) != PA_STREAM_READY) { diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 8bd098d4..291c3cd3 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -47,7 +47,7 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st      s->state_callback = NULL;      s->state_userdata = NULL; -    s->state = PA_STREAM_NODIRECTION; +    s->direction = PA_STREAM_NODIRECTION;      s->name = pa_xstrdup(name);      s->sample_spec = *ss;      s->channel = 0; @@ -57,6 +57,9 @@ struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const st      s->state = PA_STREAM_DISCONNECTED;      memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); +    s->counter = 0; +    s->previous_time = 0; +      PA_LLIST_PREPEND(struct pa_stream, c->streams, s);      return pa_stream_ref(s); @@ -211,7 +214,7 @@ finish:      pa_stream_unref(s);  } -static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume) { +static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume) {      struct pa_tagstruct *t;      uint32_t tag;      assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); @@ -247,6 +250,7 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_      pa_tagstruct_putu32(t, PA_INVALID_INDEX);      pa_tagstruct_puts(t, dev);      pa_tagstruct_putu32(t, s->buffer_attr.maxlength); +    pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED));      if (s->direction == PA_STREAM_PLAYBACK) {          pa_tagstruct_putu32(t, s->buffer_attr.tlength);          pa_tagstruct_putu32(t, s->buffer_attr.prebuf); @@ -261,16 +265,16 @@ static void create_stream(struct pa_stream *s, const char *dev, const struct pa_      pa_stream_unref(s);  } -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume) { +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume) {      assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1);      s->direction = PA_STREAM_PLAYBACK; -    create_stream(s, dev, attr, volume); +    create_stream(s, dev, attr, flags, volume);  } -void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) { +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags) {      assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1);      s->direction = PA_STREAM_RECORD; -    create_stream(s, dev, attr, 0); +    create_stream(s, dev, attr, flags, 0);  }  void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p), size_t delta) { @@ -295,6 +299,8 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void          s->requested_bytes -= length;      else          s->requested_bytes = 0; + +    s->counter += length;  }  size_t pa_stream_writable_size(struct pa_stream *s) { @@ -506,10 +512,10 @@ struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (stru      t = pa_tagstruct_new(NULL, 0);      assert(t); -    pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); +    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM);      pa_tagstruct_putu32(t, tag = s->context->ctag++);      pa_tagstruct_putu32(t, s->channel); -    pa_tagstruct_putu32(t, !!b); +    pa_tagstruct_put_boolean(t, !!b);      pa_pstream_send_tagstruct(s->context->pstream, t);      pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o); @@ -537,7 +543,11 @@ struct pa_operation* pa_stream_send_simple_command(struct pa_stream *s, uint32_t  }  struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { -    return pa_stream_send_simple_command(s, PA_COMMAND_FLUSH_PLAYBACK_STREAM, cb, userdata); +    return pa_stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata); +} + +struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { +    return pa_stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata);  }  struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata) { @@ -566,3 +576,77 @@ struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, v      return pa_operation_ref(o);  } + +uint64_t pa_stream_get_counter(struct pa_stream *s) { +    assert(s); +    return s->counter; +} + +void pa_stream_reset_counter(struct pa_stream *s) { +    assert(s); +    s->counter = 0; +    s->previous_time = 0; +} + +pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i) { +    pa_usec_t usec; +    assert(s); +     +    usec = pa_bytes_to_usec(s->counter, &s->sample_spec); + +    if (i) { +        if (s->direction == PA_STREAM_PLAYBACK) { +            pa_usec_t latency = i->transport_usec + i->buffer_usec + i->sink_usec; +            if (usec < latency) +                usec = 0; +            else +                usec -= latency; +                 +        } else if (s->direction == PA_STREAM_RECORD) { +            usec += i->source_usec + i->buffer_usec + i->transport_usec; + +            if (usec > i->sink_usec) +                usec -= i->sink_usec; +            else +                usec = 0; +        } +    } + +    if (usec < s->previous_time) +        usec = s->previous_time; + +    s->previous_time = usec; +     +    return usec; +} + +pa_usec_t pa_stream_get_total_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative) { +    assert(s && i); + +    if (s->direction == PA_STREAM_PLAYBACK) { +        if (negative) +            *negative = 0; +         +        return i->transport_usec + i->buffer_usec + i->sink_usec; +    } else if (s->direction == PA_STREAM_RECORD) { +        pa_usec_t usec = i->source_usec + i->buffer_usec + i->transport_usec; + +        if (usec >= i->sink_usec) { +            if (negative) +                *negative = 0; +            return usec - i->sink_usec; +        } else { +            if (negative) +                *negative = 1; + +            return i->sink_usec - usec; +        } +    } + +    return 0; +} + +const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s) { +    assert(s); +    return &s->sample_spec; +} diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 257f2b99..e095d7fa 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -57,10 +57,10 @@ struct pa_context* pa_stream_get_context(struct pa_stream *p);  uint32_t pa_stream_get_index(struct pa_stream *s);  /** Connect the stream to a sink */ -void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, pa_volume_t volume); +void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags, pa_volume_t volume);  /** Connect the stream to a source */ -void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr); +void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr, enum pa_stream_flags flags);  /** Disconnect a stream from a source/sink */  void pa_stream_disconnect(struct pa_stream *s); @@ -107,28 +107,56 @@ struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struc  /** Set the callback function that is called whenever the state of the stream changes */  void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata); -/** Set the callback function that is called when new data may be written to the stream */ +/** Set the callback function that is called when new data may be + * written to the stream. */  void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);  /** Set the callback function that is called when new data is available from the stream */  void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata); -/** Pause (or resume) playback of this stream temporarily. \since 0.3 */ +/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */  struct pa_operation* pa_stream_cork(struct pa_stream *s, int b, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);  /** Flush the playback buffer of this stream. Most of the time you're   * better off using the parameter delta of pa_stream_write() instead of this - * function. \since 0.3 */ + * function. Available on both playback and recording streams. \since 0.3 */  struct pa_operation* pa_stream_flush(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +/** Reenable prebuffering. Available for playback streams only. \since 0.6 */ +struct pa_operation* pa_stream_prebuf(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata); +  /** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr structure. \since + * prebuffering as specified in the pa_buffer_attr structure. Available for playback streams only. \since   * 0.3 */  struct pa_operation* pa_stream_trigger(struct pa_stream *s, void (*cb)(struct pa_stream *s, int success, void *userdata), void *userdata);  /** Rename the stream. \since 0.5 */  struct pa_operation* pa_stream_set_name(struct pa_stream *s, const char *name, void(*cb)(struct pa_stream*c, int success,  void *userdata), void *userdata); +/** Return the total number of bytes written to/read from the + * stream. This counter is not reset on pa_stream_flush(), you may do + * this yourself using pa_stream_reset_counter(). \since 0.6 */ +uint64_t pa_stream_get_counter(struct pa_stream *s); + +/** Reset the total byte count to 0. \since 0.6 */ +void pa_stream_reset_counter(struct pa_stream *s); + +/** Return the current playback/recording time. This is based on the + * counter accessible with pa_stream_get_counter(). This function + * requires a pa_latency_info structure as argument, which should be + * acquired using pa_stream_get_latency(). \since 0.6 */ +pa_usec_t pa_stream_get_time(struct pa_stream *s, const struct pa_latency_info *i); + +/** Return the total stream latency. Thus function requires a + * pa_latency_info structure as argument, which should be aquired + * using pa_stream_get_latency(). In case the stream is a monitoring + * stream the result can be negative, i.e. the captured samples are + * not yet played. In this case *negative is set to 1. \since 0.6 */ +pa_usec_t pa_stream_get_total_latency(struct pa_stream *s, const struct pa_latency_info *i, int *negative); + +/** Return a pointer to the streams sample specification. \since 0.6 */ +const struct pa_sample_spec* pa_stream_get_sample_spec(struct pa_stream *s); +  PA_C_DECL_END  #endif diff --git a/polyp/polyplib.h b/polyp/polyplib.h index f4e41934..3921e2ba 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -83,11 +83,4 @@   * synchronous API is available as "polyplib-simple".   */ -PA_C_DECL_BEGIN - -/** Return the version of the library the current application is linked to */ -const char* pa_get_library_version(void); - -PA_C_DECL_END -  #endif diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 797263f6..79978740 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -62,6 +62,7 @@  struct connection {      uint32_t index; +    int dead;      struct pa_protocol_esound *protocol;      struct pa_iochannel *io;      struct pa_client *client; @@ -76,14 +77,17 @@ struct connection {      struct pa_source_output *source_output;      struct pa_memblockq *input_memblockq, *output_memblockq;      struct pa_defer_event *defer_event; +          struct {          struct pa_memblock *current_memblock;          size_t memblock_index, fragment_size;      } playback; -    struct pa_memchunk scache_memchunk; -    char *scache_name; -    struct pa_sample_spec scache_sample_spec; +    struct { +        struct pa_memchunk memchunk; +        char *name; +        struct pa_sample_spec sample_spec; +    } scache;  };  struct pa_protocol_esound { @@ -195,9 +199,9 @@ static void connection_free(struct connection *c) {      if (c->defer_event)          c->protocol->core->mainloop->defer_free(c->defer_event); -    if (c->scache_memchunk.memblock) -        pa_memblock_unref(c->scache_memchunk.memblock); -    pa_xfree(c->scache_name); +    if (c->scache.memchunk.memblock) +        pa_memblock_unref(c->scache.memchunk.memblock); +    pa_xfree(c->scache.name);      pa_xfree(c);  } @@ -583,17 +587,17 @@ static int esd_proto_sample_cache(struct connection *c, esd_proto_t request, con      strncpy(name+sizeof(SCACHE_PREFIX)-1, (char*) data+3*sizeof(int), ESD_NAME_MAX);      name[sizeof(name)-1] = 0; -    assert(!c->scache_memchunk.memblock); -    c->scache_memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); -    c->scache_memchunk.index = 0; -    c->scache_memchunk.length = sc_length; -    c->scache_sample_spec = ss; -    assert(!c->scache_name); -    c->scache_name = pa_xstrdup(name); +    assert(!c->scache.memchunk.memblock); +    c->scache.memchunk.memblock = pa_memblock_new(sc_length, c->protocol->core->memblock_stat); +    c->scache.memchunk.index = 0; +    c->scache.memchunk.length = sc_length; +    c->scache.sample_spec = ss; +    assert(!c->scache.name); +    c->scache.name = pa_xstrdup(name);      c->state = ESD_CACHING_SAMPLE; -    pa_scache_add_item(c->protocol->core, c->scache_name, NULL, NULL, &index); +    pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &index);      ok = connection_write(c, sizeof(int));      assert(ok); @@ -747,29 +751,29 @@ static int do_read(struct connection *c) {      } else if (c->state == ESD_CACHING_SAMPLE) {          ssize_t r; -        assert(c->scache_memchunk.memblock && c->scache_name && c->scache_memchunk.index < c->scache_memchunk.length); +        assert(c->scache.memchunk.memblock && c->scache.name && c->scache.memchunk.index < c->scache.memchunk.length); -        if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache_memchunk.memblock->data+c->scache_memchunk.index, c->scache_memchunk.length-c->scache_memchunk.index)) <= 0) { +        if ((r = pa_iochannel_read(c->io, (uint8_t*) c->scache.memchunk.memblock->data+c->scache.memchunk.index, c->scache.memchunk.length-c->scache.memchunk.index)) <= 0) {              pa_log(__FILE__": read() failed: %s\n", r == 0 ? "EOF" : strerror(errno));              return -1;          } -        c->scache_memchunk.index += r; -        assert(c->scache_memchunk.index <= c->scache_memchunk.length); +        c->scache.memchunk.index += r; +        assert(c->scache.memchunk.index <= c->scache.memchunk.length); -        if (c->scache_memchunk.index == c->scache_memchunk.length) { +        if (c->scache.memchunk.index == c->scache.memchunk.length) {              uint32_t index;              int *ok; -            c->scache_memchunk.index = 0; -            pa_scache_add_item(c->protocol->core, c->scache_name, &c->scache_sample_spec, &c->scache_memchunk, &index); +            c->scache.memchunk.index = 0; +            pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &index); -            pa_memblock_unref(c->scache_memchunk.memblock); -            c->scache_memchunk.memblock = NULL; -            c->scache_memchunk.index = c->scache_memchunk.length = 0; +            pa_memblock_unref(c->scache.memchunk.memblock); +            c->scache.memchunk.memblock = NULL; +            c->scache.memchunk.index = c->scache.memchunk.length = 0; -            pa_xfree(c->scache_name); -            c->scache_name = NULL; +            pa_xfree(c->scache.name); +            c->scache.name = NULL;              c->state = ESD_NEXT_REQUEST; @@ -869,21 +873,26 @@ static void do_work(struct connection *c) {      assert(c->protocol && c->protocol->core && c->protocol->core->mainloop && c->protocol->core->mainloop->defer_enable);      c->protocol->core->mainloop->defer_enable(c->defer_event, 0); -    if (pa_iochannel_is_hungup(c->io)) -        goto fail; +    if (c->dead) +        return; +     +    if (pa_iochannel_is_readable(c->io)) +        if (do_read(c) < 0) +            goto fail;      if (pa_iochannel_is_writable(c->io))          if (do_write(c) < 0)              goto fail; -    if (pa_iochannel_is_readable(c->io)) -        if (do_read(c) < 0) -            goto fail; -      return;  fail: -    connection_free(c); + +    if (c->state == ESD_STREAMING_DATA && c->sink_input) { +        c->dead = 1; +        pa_memblockq_prebuf_disable(c->input_memblockq); +    } else +        connection_free(c);  }  static void io_callback(struct pa_iochannel*io, void *userdata) { @@ -909,8 +918,13 @@ static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk      assert(i && i->userdata && chunk);      c = i->userdata; -    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) +    if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) { + +        if (c->dead) +            connection_free(c); +                  return -1; +    }      return 0;  } @@ -985,6 +999,7 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo      c->authorized = c->protocol->public;      c->swap_byte_order = 0; +    c->dead = 0;      c->read_data_length = 0;      c->read_data = pa_xmalloc(c->read_data_alloc = proto_map[ESD_PROTO_CONNECT].data_length); @@ -1005,9 +1020,9 @@ static void on_connection(struct pa_socket_server*s, struct pa_iochannel *io, vo      c->playback.memblock_index = 0;      c->playback.fragment_size = 0; -    c->scache_memchunk.length = c->scache_memchunk.index = 0; -    c->scache_memchunk.memblock = NULL; -    c->scache_name = NULL; +    c->scache.memchunk.length = c->scache.memchunk.index = 0; +    c->scache.memchunk.memblock = NULL; +    c->scache.name = NULL;      c->defer_event = c->protocol->core->mainloop->defer_new(c->protocol->core->mainloop, defer_callback, c);      assert(c->defer_event); diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index 4c1e9696..f36bbd71 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -150,6 +150,8 @@ static void command_add_autoload(struct pa_pdispatch *pd, uint32_t command, uint  static void command_remove_autoload(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);  static void command_get_autoload_info(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);  static void command_get_autoload_info_list(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);  static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {      [PA_COMMAND_ERROR] = { NULL }, @@ -190,11 +192,18 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {      [PA_COMMAND_GET_SAMPLE_INFO_LIST] = { command_get_info_list },      [PA_COMMAND_GET_SERVER_INFO] = { command_get_server_info },      [PA_COMMAND_SUBSCRIBE] = { command_subscribe }, +      [PA_COMMAND_SET_SINK_VOLUME] = { command_set_volume },      [PA_COMMAND_SET_SINK_INPUT_VOLUME] = { command_set_volume }, +          [PA_COMMAND_CORK_PLAYBACK_STREAM] = { command_cork_playback_stream },      [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream },      [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, +    [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = { command_flush_or_trigger_playback_stream }, +     +    [PA_COMMAND_CORK_RECORD_STREAM] = { command_cork_record_stream }, +    [PA_COMMAND_FLUSH_RECORD_STREAM] = { command_flush_record_stream }, +          [PA_COMMAND_SET_DEFAULT_SINK] = { command_set_default_sink_or_source },      [PA_COMMAND_SET_DEFAULT_SOURCE] = { command_set_default_sink_or_source },      [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = { command_set_stream_name },  @@ -208,6 +217,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {      [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = { command_get_autoload_info_list },      [PA_COMMAND_ADD_AUTOLOAD] = { command_add_autoload },      [PA_COMMAND_REMOVE_AUTOLOAD] = { command_remove_autoload }, +  };  /* structure management */ @@ -538,6 +548,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com      struct pa_tagstruct *reply;      struct pa_sink *sink;      pa_volume_t volume; +    int corked;      assert(c && t && c->protocol && c->protocol->core);      if (pa_tagstruct_gets(t, &name) < 0 || !name || @@ -545,6 +556,7 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com          pa_tagstruct_getu32(t, &sink_index) < 0 ||          pa_tagstruct_gets(t, &sink_name) < 0 ||          pa_tagstruct_getu32(t, &maxlength) < 0 || +        pa_tagstruct_get_boolean(t, &corked) < 0 ||          pa_tagstruct_getu32(t, &tlength) < 0 ||          pa_tagstruct_getu32(t, &prebuf) < 0 ||          pa_tagstruct_getu32(t, &minreq) < 0 || @@ -574,6 +586,8 @@ static void command_create_playback_stream(struct pa_pdispatch *pd, uint32_t com          pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID);          return;      } + +    pa_sink_input_cork(s->sink_input, corked);      reply = pa_tagstruct_new(NULL, 0);      assert(reply); @@ -1412,12 +1426,12 @@ static void command_set_volume(struct pa_pdispatch *pd, uint32_t command, uint32  static void command_cork_playback_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {      struct connection *c = userdata;      uint32_t index; -    uint32_t b; +    int b;      struct playback_stream *s;      assert(c && t);      if (pa_tagstruct_getu32(t, &index) < 0 || -        pa_tagstruct_getu32(t, &b) < 0 || +        pa_tagstruct_get_boolean(t, &b) < 0 ||          !pa_tagstruct_eof(t)) {          protocol_error(c);          return; @@ -1459,7 +1473,9 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui          return;      } -    if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM) +    if (command == PA_COMMAND_PREBUF_PLAYBACK_STREAM) +        pa_memblockq_prebuf_reenable(s->memblockq); +    else if (command == PA_COMMAND_TRIGGER_PLAYBACK_STREAM)          pa_memblockq_prebuf_disable(s->memblockq);      else {          assert(command == PA_COMMAND_FLUSH_PLAYBACK_STREAM); @@ -1472,6 +1488,60 @@ static void command_flush_or_trigger_playback_stream(struct pa_pdispatch *pd, ui      request_bytes(s);  } +static void command_cork_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +    struct connection *c = userdata; +    uint32_t index; +    struct record_stream *s; +    int b; +    assert(c && t); + +    if (pa_tagstruct_getu32(t, &index) < 0 || +        pa_tagstruct_get_boolean(t, &b) < 0 || +        !pa_tagstruct_eof(t)) { +        protocol_error(c); +        return; +    } + +    if (!c->authorized) { +        pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); +        return; +    } + +    if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { +        pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); +        return; +    } + +    pa_source_output_cork(s->source_output, b); +    pa_pstream_send_simple_ack(c->pstream, tag); +} + +static void command_flush_record_stream(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { +    struct connection *c = userdata; +    uint32_t index; +    struct record_stream *s; +    assert(c && t); + +    if (pa_tagstruct_getu32(t, &index) < 0 || +        !pa_tagstruct_eof(t)) { +        protocol_error(c); +        return; +    } + +    if (!c->authorized) { +        pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); +        return; +    } + +    if (!(s = pa_idxset_get_by_index(c->record_streams, index))) { +        pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); +        return; +    } + +    pa_memblockq_flush(s->memblockq); +    pa_pstream_send_simple_ack(c->pstream, tag); +} +  static void command_set_default_sink_or_source(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {      struct connection *c = userdata;      uint32_t index; diff --git a/polyp/sample.c b/polyp/sample.c index 143e1e41..65ae8ff3 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -59,7 +59,7 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec) {      return spec->rate*pa_frame_size(spec);  } -pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) { +pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec) {      assert(spec);      return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); diff --git a/polyp/sample.h b/polyp/sample.h index 501172a8..912cdaa0 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -77,7 +77,7 @@ size_t pa_bytes_per_second(const struct pa_sample_spec *spec);  size_t pa_frame_size(const struct pa_sample_spec *spec);  /** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec); +pa_usec_t pa_bytes_to_usec(uint64_t length, const struct pa_sample_spec *spec);  /** Return non-zero when the sample type specification is valid */  int pa_sample_spec_valid(const struct pa_sample_spec *spec); diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 94930231..5c8675de 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -70,7 +70,6 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con      i->get_latency = NULL;      i->userdata = NULL; -    i->corked = 0;      i->volume = PA_VOLUME_NORM;      i->resampled_chunk.memblock = NULL; @@ -92,7 +91,7 @@ struct pa_sink_input* pa_sink_input_new(struct pa_sink *s, const char *name, con  }  void pa_sink_input_disconnect(struct pa_sink_input *i) { -    assert(i && i->state == PA_SINK_INPUT_RUNNING && i->sink && i->sink->core); +    assert(i && i->state != PA_SINK_INPUT_DISCONNECTED && i->sink && i->sink->core);      pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);      pa_idxset_remove_by_data(i->sink->inputs, i, NULL); @@ -163,7 +162,7 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) {      if (!i->peek || !i->drop)          return -1; -    if (i->corked) +    if (i->state == PA_SINK_INPUT_CORKED)          return -1;      if (!i->resampler) @@ -238,9 +237,12 @@ void pa_sink_input_set_volume(struct pa_sink_input *i, pa_volume_t volume) {  void pa_sink_input_cork(struct pa_sink_input *i, int b) {      int n;      assert(i && i->ref >= 1); -     -    n = i->corked && !b; -    i->corked = b; + +    if (i->state == PA_SINK_INPUT_DISCONNECTED) +        return; + +    n = i->state == PA_SINK_INPUT_CORKED && !b; +    i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;      if (n)          pa_sink_notify(i->sink); diff --git a/polyp/sink-input.h b/polyp/sink-input.h index 7c648ac1..aed5f521 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -33,6 +33,7 @@  enum pa_sink_input_state {      PA_SINK_INPUT_RUNNING, +    PA_SINK_INPUT_CORKED,      PA_SINK_INPUT_DISCONNECTED  }; @@ -42,8 +43,6 @@ struct pa_sink_input {      uint32_t index; -    int corked; -          char *name;      struct pa_module *owner;      struct pa_client *client; diff --git a/polyp/source-output.c b/polyp/source-output.c index 13b39658..5a40fa42 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -79,7 +79,7 @@ struct pa_source_output* pa_source_output_new(struct pa_source *s, const char *n  }  void pa_source_output_disconnect(struct pa_source_output*o) { -    assert(o && o->state == PA_SOURCE_OUTPUT_RUNNING && o->source && o->source->core); +    assert(o && o->state != PA_SOURCE_OUTPUT_DISCONNECTED && o->source && o->source->core);      pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL);      pa_idxset_remove_by_data(o->source->outputs, o, NULL); @@ -133,6 +133,9 @@ void pa_source_output_push(struct pa_source_output *o, const struct pa_memchunk      struct pa_memchunk rchunk;      assert(o && chunk && chunk->length && o->push); +    if (o->state == PA_SOURCE_OUTPUT_CORKED) +        return; +          if (!o->resampler) {          o->push(o, chunk);          return; @@ -163,3 +166,12 @@ pa_usec_t pa_source_output_get_latency(struct pa_source_output *o) {      return 0;  } + +void pa_source_output_cork(struct pa_source_output *o, int b) { +    assert(o && o->ref >= 1); + +    if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) +        return; +     +    o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; +} diff --git a/polyp/source-output.h b/polyp/source-output.h index 51d5936b..a535782e 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -33,6 +33,7 @@  enum pa_source_output_state {      PA_SOURCE_OUTPUT_RUNNING, +    PA_SOURCE_OUTPUT_CORKED,      PA_SOURCE_OUTPUT_DISCONNECTED  }; @@ -73,5 +74,7 @@ void pa_source_output_set_name(struct pa_source_output *i, const char *name);  pa_usec_t pa_source_output_get_latency(struct pa_source_output *i); +void pa_source_output_cork(struct pa_source_output *i, int b); +  #endif diff --git a/polyp/util.c b/polyp/util.c index 1246bbb5..6be6ffe4 100644 --- a/polyp/util.c +++ b/polyp/util.c @@ -421,6 +421,7 @@ const char *pa_strsignal(int sig) {          case SIGXCPU: return "SIGXCPU";          case SIGPIPE: return "SIGPIPE";          case SIGCHLD: return "SIGCHLD"; +        case SIGHUP: return "SIGHUP";          default: return "UNKNOWN SIGNAL";      }  }  | 
