- 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
-- extend pa_usec_t to 64 bit
-- make use of network latency in all apps
- fix or work around libtool bug
- merge pa_context_connect_*
+- input latency
** later ***
- xmlrpc/http
assert(sink->monitor_source);
pa_strbuf_printf(
s,
- " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%u usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n",
+ " %c index: %u\n\tname: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n",
c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',
sink->index, sink->name,
(unsigned) sink->volume,
pa_volume_to_dB(sink->volume),
- pa_sink_get_latency(sink),
+ (float) pa_sink_get_latency(sink),
sink->monitor_source->index,
ss);
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: <%u usec>\n\tsample_spec: <%s>\n",
+ s, " index: %u\n\tname: <%s>\n\tsink: <%u>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%f usec>\n\tsample_spec: <%s>\n",
i->index,
i->name,
i->sink->index,
(unsigned) i->volume,
pa_volume_to_dB(i->volume),
- pa_sink_input_get_latency(i),
+ (float) pa_sink_input_get_latency(i),
ss);
if (i->owner)
lt_dlsetsearchpath(DLSEARCHPATH);
#endif
+ pa_log(__FILE__": sizeof(pa_usec_t) = %u\n", sizeof(pa_usec_t));
+
mainloop = pa_mainloop_new();
assert(mainloop);
do_write(u);
}
-static uint32_t sink_get_latency_cb(struct pa_sink *s) {
+static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
struct userdata *u = s->userdata;
snd_pcm_sframes_t frames;
assert(s && u && u->sink);
do_write(u);
}
-static uint32_t sink_get_latency_cb(struct pa_sink *s) {
+static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
struct userdata *u = s->userdata;
assert(s && u);
do_read(u);
}
-static uint32_t sink_get_latency_cb(struct pa_sink *s) {
+static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
int arg;
struct userdata *u = s->userdata;
assert(s && u && u->sink);
return;
}
- fprintf(stderr, "Current latency is %u usecs.\n", i->buffer_usec+i->sink_usec);
+ fprintf(stderr, "Current latency is %f usecs.\n", (float) (i->buffer_usec+i->sink_usec+i->transport_usec));
}
/* Someone requested that the latency is shown */
pa_tagstruct_getu32(t, &i.volume) < 0 ||
pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
- pa_tagstruct_getu32(t, &i.latency) < 0) {
+ pa_tagstruct_get_usec(t, &i.latency) < 0) {
pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish;
}
pa_tagstruct_getu32(t, &i.sink) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
pa_tagstruct_getu32(t, &i.volume) < 0 ||
- pa_tagstruct_getu32(t, &i.buffer_usec) < 0 ||
- pa_tagstruct_getu32(t, &i.sink_usec) < 0) {
+ pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 ||
+ pa_tagstruct_get_usec(t, &i.sink_usec) < 0) {
pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish;
}
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
pa_tagstruct_getu32(t, &i.volume) < 0 ||
- pa_tagstruct_getu32(t, &i.duration) < 0 ||
+ pa_tagstruct_get_usec(t, &i.duration) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
pa_tagstruct_getu32(t, &i.bytes) < 0) {
pa_context_fail(o->context, PA_ERROR_PROTOCOL);
if (pa_context_handle_error(o->context, command, t) < 0)
goto finish;
- } else if (pa_tagstruct_getu32(t, &i.buffer_usec) < 0 ||
- pa_tagstruct_getu32(t, &i.sink_usec) < 0 ||
+ } else if (pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 ||
+ pa_tagstruct_get_usec(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 ||
static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk);
static void sink_input_kill_cb(struct pa_sink_input *i);
-static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i);
+static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i);
static void source_output_push_cb(struct pa_source_output *o, const struct pa_memchunk *chunk);
static void source_output_kill_cb(struct pa_source_output *o);
if (!(sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1)))
latency = 0;
else {
- float usec = pa_sink_get_latency(sink);
+ double usec = pa_sink_get_latency(sink);
usec += PLAYBACK_BUFFER_SECONDS*1000000; /* A better estimation would be a good idea! */
latency = (int) ((usec*44100)/1000000);
}
}
-static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) {
+static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) {
struct connection*c = i->userdata;
assert(i && c);
return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
static int sink_input_peek_cb(struct pa_sink_input *i, struct pa_memchunk *chunk);
static void sink_input_drop_cb(struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
static void sink_input_kill_cb(struct pa_sink_input *i);
-static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i);
+static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i);
static void request_bytes(struct playback_stream*s);
playback_stream_free((struct playback_stream *) i->userdata);
}
-static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) {
+static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) {
struct playback_stream *s;
assert(i && i->userdata);
s = i->userdata;
assert(reply);
pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
pa_tagstruct_putu32(reply, tag);
- pa_tagstruct_putu32(reply, pa_sink_input_get_latency(s->sink_input));
- pa_tagstruct_putu32(reply, pa_sink_get_latency(s->sink_input->sink));
+ pa_tagstruct_put_usec(reply, pa_sink_input_get_latency(s->sink_input));
+ pa_tagstruct_put_usec(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);
pa_tagstruct_putu32(t, sink->volume);
pa_tagstruct_putu32(t, sink->monitor_source->index);
pa_tagstruct_puts(t, sink->monitor_source->name);
- pa_tagstruct_putu32(t, pa_sink_get_latency(sink));
+ pa_tagstruct_put_usec(t, pa_sink_get_latency(sink));
}
static void source_fill_tagstruct(struct pa_tagstruct *t, struct pa_source *source) {
pa_tagstruct_putu32(t, s->sink->index);
pa_tagstruct_put_sample_spec(t, &s->sample_spec);
pa_tagstruct_putu32(t, s->volume);
- pa_tagstruct_putu32(t, pa_sink_input_get_latency(s));
- pa_tagstruct_putu32(t, pa_sink_get_latency(s->sink));
+ pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s));
+ pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink));
}
static void source_output_fill_tagstruct(struct pa_tagstruct *t, struct pa_source_output *s) {
pa_tagstruct_putu32(t, e->index);
pa_tagstruct_puts(t, e->name);
pa_tagstruct_putu32(t, e->volume);
- pa_tagstruct_putu32(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec));
+ pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec));
pa_tagstruct_put_sample_spec(t, &e->sample_spec);
pa_tagstruct_putu32(t, e->memchunk.length);
}
}
-static uint32_t sink_input_get_latency_cb(struct pa_sink_input *i) {
+static pa_usec_t sink_input_get_latency_cb(struct pa_sink_input *i) {
struct connection*c = i->userdata;
assert(i && c);
return pa_bytes_to_usec(pa_memblockq_get_length(c->input_memblockq), &c->sink_input->sample_spec);
return spec->rate*pa_frame_size(spec);
}
-uint32_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) {
+pa_usec_t pa_bytes_to_usec(size_t length, const struct pa_sample_spec *spec) {
assert(spec);
- return (uint32_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate);
+ return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate);
}
int pa_sample_spec_valid(const struct pa_sample_spec *spec) {
uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */
};
-/** Type for usec specifications */
-typedef uint32_t pa_usec_t;
+/** Type for usec specifications. May be either 32 or 64 bit, depending on the architecture */
+typedef uint64_t pa_usec_t;
/** Return the amount of bytes playback of a second of audio with the speicified sample type takes */
size_t pa_bytes_per_second(const struct pa_sample_spec *spec);
int (*peek) (struct pa_sink_input *i, struct pa_memchunk *chunk);
void (*drop) (struct pa_sink_input *i, const struct pa_memchunk *chunk, size_t length);
void (*kill) (struct pa_sink_input *i);
- uint32_t (*get_latency) (struct pa_sink_input *i);
+ pa_usec_t (*get_latency) (struct pa_sink_input *i);
void *userdata;
pa_volume_t volume;
void (*notify)(struct pa_sink*sink);
- uint32_t (*get_latency)(struct pa_sink *s);
+ pa_usec_t (*get_latency)(struct pa_sink *s);
void *userdata;
};
TAG_S16 = 's',
TAG_U8 = 'B',
TAG_S8 = 'b',
+ TAG_U64 = 'R',
+ TAG_S64 = 'r',
TAG_SAMPLE_SPEC = 'a',
TAG_ARBITRARY = 'x',
TAG_BOOLEAN_TRUE = '1',
TAG_BOOLEAN_FALSE = '0',
TAG_TIMEVAL = 'T',
+ TAG_USEC = 'U', /* 64bit unsigned */
};
struct pa_tagstruct {
t->length += 9;
}
+void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u) {
+ assert(t);
+ extend(t, 9);
+ t->data[t->length] = TAG_USEC;
+ *((uint32_t*) (t->data+t->length+1)) = htonl((uint32_t) (u >> 32));
+ *((uint32_t*) (t->data+t->length+5)) = htonl((uint32_t) u);
+ t->length += 9;
+}
+
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s) {
int error = 0;
size_t n;
}
+int pa_tagstruct_get_usec(struct pa_tagstruct*t, pa_usec_t *u) {
+ assert(t && u);
+
+ if (t->rindex+9 > t->length)
+ return -1;
+
+ if (t->data[t->rindex] != TAG_USEC)
+ return -1;
+
+ *u = (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+1))) << 32;
+ *u |= (pa_usec_t) ntohl(*((uint32_t*) (t->data+t->rindex+5)));
+ t->rindex +=9;
+ return 0;
+}
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);
+void pa_tagstruct_put_usec(struct pa_tagstruct*t, pa_usec_t u);
int pa_tagstruct_gets(struct pa_tagstruct*t, const char **s);
int pa_tagstruct_getu32(struct pa_tagstruct*t, uint32_t *i);
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_get_usec(struct pa_tagstruct*t, pa_usec_t *u);
int pa_tagstruct_eof(struct pa_tagstruct*t);
const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l);
b = c;
}
- r = (a->tv_sec - b->tv_sec)* 1000000;
+ r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000;
if (a->tv_usec > b->tv_usec)
- r += (a->tv_usec - b->tv_usec);
+ r += ((pa_usec_t) a->tv_usec - b->tv_usec);
else if (a->tv_usec < b->tv_usec)
- r -= (b->tv_usec - a->tv_usec);
+ r -= ((pa_usec_t) b->tv_usec - a->tv_usec);
return r;
}