From 710233bbf68c845ec5f1713679f4ff0b74c517de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 15 Jul 2004 21:18:18 +0000 Subject: implement get_latency native command git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@72 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/pacat.c | 20 ++++++++++++++++++ src/pdispatch.c | 12 ++++++++++- src/polyp.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ src/polyp.h | 2 ++ src/protocol-native-spec.h | 1 + src/protocol-native.c | 34 +++++++++++++++++++++++++++++++ src/todo | 12 +++++------ 7 files changed, 125 insertions(+), 7 deletions(-) diff --git a/src/pacat.c b/src/pacat.c index c9257d03..2c5198fb 100644 --- a/src/pacat.c +++ b/src/pacat.c @@ -221,6 +221,25 @@ static void exit_signal_callback(void *id, int sig, void *userdata) { } +static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, void *userdata) { + assert(s); + + if (latency == (uint32_t) -1) { + fprintf(stderr, "Failed to get latency: %s\n", strerror(errno)); + quit(1); + return; + } + + fprintf(stderr, "Current latency is %u usecs.\n", latency); +} + +static void sigusr1_signal_callback(void *id, int sig, void *userdata) { + if (mode == PLAYBACK) { + fprintf(stderr, "Got SIGUSR1, requesting latency.\n"); + pa_stream_get_latency(stream, stream_get_latency_callback, NULL); + } +} + int main(int argc, char *argv[]) { struct pa_mainloop* m = NULL; int ret = 1, r; @@ -246,6 +265,7 @@ int main(int argc, char *argv[]) { r = pa_signal_init(mainloop_api); assert(r == 0); pa_signal_register(SIGINT, exit_signal_callback, NULL); + pa_signal_register(SIGUSR1, sigusr1_signal_callback, NULL); signal(SIGPIPE, SIG_IGN); if (!(stdio_source = mainloop_api->source_io(mainloop_api, diff --git a/src/pdispatch.c b/src/pdispatch.c index b7257dd4..32753963 100644 --- a/src/pdispatch.c +++ b/src/pdispatch.c @@ -4,6 +4,8 @@ #include "pdispatch.h" #include "protocol-native-spec.h" +#ifdef DEBUG_OPCODES + static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_ERROR] = "ERROR", [PA_COMMAND_TIMEOUT] = "TIMEOUT", @@ -19,8 +21,14 @@ static const char *command_names[PA_COMMAND_MAX] = { [PA_COMMAND_LOOKUP_SINK] = "LOOKUP_SINK", [PA_COMMAND_LOOKUP_SOURCE] = "LOOKUP_SOURCE", [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = "DRAIN_PLAYBACK_STREAM", + [PA_COMMAND_PLAYBACK_STREAM_KILLED] = "PLAYBACK_STREAM_KILLED", + [PA_COMMAND_RECORD_STREAM_KILLED] = "RECORD_STREAM_KILLED", + [PA_COMMAND_STAT] = "STAT", + [PA_COMMAND_GET_PLAYBACK_LATENCY] = "PLAYBACK_LATENCY", }; +#endif + struct reply_info { struct pa_pdispatch *pdispatch; struct reply_info *next, *previous; @@ -106,7 +114,9 @@ int pa_pdispatch_run(struct pa_pdispatch *pd, struct pa_packet*packet, void *use pa_tagstruct_getu32(ts, &tag) < 0) goto finish; - /*fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]);*/ +#ifdef DEBUG_OPCODES + fprintf(stderr, __FILE__": Recieved opcode <%s>\n", command_names[command]); +#endif if (command == PA_COMMAND_ERROR || command == PA_COMMAND_REPLY) { struct reply_info *r; diff --git a/src/polyp.c b/src/polyp.c index bc6bff5a..d6d0f908 100644 --- a/src/polyp.c +++ b/src/polyp.c @@ -89,6 +89,9 @@ struct pa_stream { void (*die_callback)(struct pa_stream*c, void *userdata); void *die_userdata; + + void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata); + void *get_latency_userdata; }; static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); @@ -602,6 +605,8 @@ struct pa_stream* pa_stream_new( s->die_userdata = NULL; s->create_complete_callback = complete; s->create_complete_userdata = NULL; + s->get_latency_callback = NULL; + s->get_latency_userdata = NULL; s->name = strdup(name); s->state = STREAM_CREATING; @@ -895,3 +900,49 @@ void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint pa_pstream_send_tagstruct(c->pstream, t); pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c); } + +static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct pa_stream *s = userdata; + uint32_t latency; + assert(pd && s); + + if (command != PA_COMMAND_REPLY) { + if (handle_error(s->context, command, t) < 0) { + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata); + return; + } + + if (pa_tagstruct_getu32(t, &latency) < 0 || + !pa_tagstruct_eof(t)) { + s->context->error = PA_ERROR_PROTOCOL; + context_dead(s->context); + return; + } + + if (s->get_latency_callback) + s->get_latency_callback(s, latency, s->get_latency_userdata); +} + +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) { + uint32_t tag; + struct pa_tagstruct *t; + + p->get_latency_callback = cb; + p->get_latency_userdata = userdata; + + if (cb == NULL) + return; + + t = pa_tagstruct_new(NULL, 0); + assert(t); + pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); + pa_tagstruct_putu32(t, tag = p->context->ctag++); + pa_tagstruct_putu32(t, p->channel); + pa_pstream_send_tagstruct(p->context->pstream, t); + pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p); +} diff --git a/src/polyp.h b/src/polyp.h index 5b730302..00849445 100644 --- a/src/polyp.h +++ b/src/polyp.h @@ -66,6 +66,8 @@ void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_strea int pa_stream_is_dead(struct pa_stream *p); int pa_stream_is_ready(struct pa_stream*p); +void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata); + struct pa_context* pa_stream_get_context(struct pa_stream *p); #endif diff --git a/src/protocol-native-spec.h b/src/protocol-native-spec.h index 0a60fd80..e1db6f64 100644 --- a/src/protocol-native-spec.h +++ b/src/protocol-native-spec.h @@ -19,6 +19,7 @@ enum { PA_COMMAND_PLAYBACK_STREAM_KILLED, PA_COMMAND_RECORD_STREAM_KILLED, PA_COMMAND_STAT, + PA_COMMAND_GET_PLAYBACK_LATENCY, PA_COMMAND_MAX }; diff --git a/src/protocol-native.c b/src/protocol-native.c index 56395e98..094c6630 100644 --- a/src/protocol-native.c +++ b/src/protocol-native.c @@ -76,6 +76,7 @@ static void command_auth(struct pa_pdispatch *pd, uint32_t command, uint32_t tag static void command_set_name(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_lookup(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata); +static void command_get_playback_latency(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 }, @@ -93,6 +94,7 @@ static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = { [PA_COMMAND_LOOKUP_SINK] = { command_lookup }, [PA_COMMAND_LOOKUP_SOURCE] = { command_lookup }, [PA_COMMAND_STAT] = { command_stat }, + [PA_COMMAND_GET_PLAYBACK_LATENCY] = { command_get_playback_latency }, }; /* structure management */ @@ -664,6 +666,38 @@ static void command_stat(struct pa_pdispatch *pd, uint32_t command, uint32_t tag pa_pstream_send_tagstruct(c->pstream, reply); } +static void command_get_playback_latency(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) { + struct connection *c = userdata; + assert(c && t); + struct pa_tagstruct *reply; + struct playback_stream *s; + uint32_t index, latency; + + 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->playback_streams, index))) { + pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); + return; + } + + latency = pa_sink_input_get_latency(s->sink_input); + reply = pa_tagstruct_new(NULL, 0); + assert(reply); + pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); + pa_tagstruct_putu32(reply, tag); + pa_tagstruct_putu32(reply, latency); + pa_pstream_send_tagstruct(c->pstream, reply); +} + /*** pstream callbacks ***/ static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) { diff --git a/src/todo b/src/todo index 107fa787..09a7a5c1 100644 --- a/src/todo +++ b/src/todo @@ -1,8 +1,3 @@ -- pactl - -- native library/protocol: - more functions (esp. latency) - - xmms+esound latency testing - prefix modules/libraries with pa_ @@ -21,7 +16,12 @@ - modinfo - move the global memblock statistics variables to the core - unix socket directories include user name - +- more complete pactl +- native library/protocol: + get server layout + subscription + module load/unload + kill client/... drivers: - libao -- cgit