mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
bum version number
add new macro PA_API_VERSION for preprocessor level conditional compiling add new native APIs: - counter - cork & flush for record streams - add flags parameters to pa_stream_connect_xx() - new prebuf command - time api, and total latency calculator - return sample spec ability to cork source output streams dump server status on SIGHUP to syslog show sink input/source outputs status in cli-text.c don't flush esound output buffer when client disconnects move version api to polyplib-version.h git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@240 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
405fac5ea7
commit
5bac3c3ce5
26 changed files with 392 additions and 94 deletions
|
|
@ -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])
|
||||
|
|
|
|||
12
doc/todo
12
doc/todo
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
47
polyp/main.c
47
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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue