[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.15-58-g84a92f2
Lennart Poettering
gitmailer-noreply at 0pointer.de
Tue Apr 28 19:15:30 PDT 2009
This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.
The master branch has been updated
from 0b2d96d6c0f586bb8436950080eda11daa170ba3 (commit)
- Log -----------------------------------------------------------------
84a92f2 protocol-http: allow listening into sinks/sources via HTTP
c215011 ioline: add new calls pa_ioline_detach_iochannel() and pa_ioline_is_drained()
a64097a ioline: add callback that can be called when the ioline object is fully drained
4cb6ea2 simple-protocol: don't hit an assert when we call connection_unlink() early
-----------------------------------------------------------------------
Summary of changes:
src/pulsecore/ioline.c | 48 ++++-
src/pulsecore/ioline.h | 11 +
src/pulsecore/protocol-http.c | 505 ++++++++++++++++++++++++++++++---------
src/pulsecore/protocol-simple.c | 2 +-
4 files changed, 451 insertions(+), 115 deletions(-)
-----------------------------------------------------------------------
commit 4cb6ea2d96d40aaebc2015957cef297315bcdec4
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Apr 29 04:13:07 2009 +0200
simple-protocol: don't hit an assert when we call connection_unlink() early
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 44fe597..776d74b 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -130,7 +130,7 @@ static void connection_unlink(connection *c) {
c->io = NULL;
}
- pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c);
+ pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
c->protocol = NULL;
connection_unref(c);
}
commit a64097ab1f3be781aae36f8e66a3ce03987629c3
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Apr 29 04:14:23 2009 +0200
ioline: add callback that can be called when the ioline object is fully drained
diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c
index 5c38d6e..7f252bc 100644
--- a/src/pulsecore/ioline.c
+++ b/src/pulsecore/ioline.c
@@ -57,6 +57,9 @@ struct pa_ioline {
pa_ioline_cb_t callback;
void *userdata;
+ pa_ioline_drain_cb_t drain_callback;
+ void *drain_userdata;
+
pa_bool_t dead:1;
pa_bool_t defer_close:1;
};
@@ -81,6 +84,9 @@ pa_ioline* pa_ioline_new(pa_iochannel *io) {
l->callback = NULL;
l->userdata = NULL;
+ l->drain_callback = NULL;
+ l->drain_userdata = NULL;
+
l->mainloop = pa_iochannel_get_mainloop_api(io);
l->defer_event = l->mainloop->defer_new(l->mainloop, defer_callback, l);
@@ -202,6 +208,17 @@ void pa_ioline_set_callback(pa_ioline*l, pa_ioline_cb_t callback, void *userdata
l->userdata = userdata;
}
+void pa_ioline_set_drain_callback(pa_ioline*l, pa_ioline_drain_cb_t callback, void *userdata) {
+ pa_assert(l);
+ pa_assert(PA_REFCNT_VALUE(l) >= 1);
+
+ if (l->dead)
+ return;
+
+ l->drain_callback = callback;
+ l->drain_userdata = userdata;
+}
+
static void failure(pa_ioline *l, pa_bool_t process_leftover) {
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
@@ -336,7 +353,7 @@ static int do_write(pa_ioline *l) {
if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) {
if (r < 0 && errno == EAGAIN)
- return 0;
+ break;
if (r < 0 && errno != EPIPE)
pa_log("write(): %s", pa_cstrerror(errno));
@@ -354,6 +371,9 @@ static int do_write(pa_ioline *l) {
l->wbuf_index = 0;
}
+ if (l->wbuf_valid_length <= 0 && l->drain_callback)
+ l->drain_callback(l, l->drain_userdata);
+
return 0;
}
diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h
index 9f32d60..26e2a22 100644
--- a/src/pulsecore/ioline.h
+++ b/src/pulsecore/ioline.h
@@ -32,6 +32,7 @@
typedef struct pa_ioline pa_ioline;
typedef void (*pa_ioline_cb_t)(pa_ioline*io, const char *s, void *userdata);
+typedef void (*pa_ioline_drain_cb_t)(pa_ioline *io, void *userdata);
pa_ioline* pa_ioline_new(pa_iochannel *io);
void pa_ioline_unref(pa_ioline *l);
@@ -47,6 +48,9 @@ void pa_ioline_printf(pa_ioline *s, const char *format, ...) PA_GCC_PRINTF_ATTR(
/* Set the callback function that is called for every recieved line */
void pa_ioline_set_callback(pa_ioline*io, pa_ioline_cb_t callback, void *userdata);
+/* Set the callback function that is called when everything has been written */
+void pa_ioline_set_drain_callback(pa_ioline*io, pa_ioline_drain_cb_t callback, void *userdata);
+
/* Make sure to close the ioline object as soon as the send buffer is emptied */
void pa_ioline_defer_close(pa_ioline *io);
commit c2150118bfded6dab8c3023ee5b21f87204b8228
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Apr 29 04:14:52 2009 +0200
ioline: add new calls pa_ioline_detach_iochannel() and pa_ioline_is_drained()
diff --git a/src/pulsecore/ioline.c b/src/pulsecore/ioline.c
index 7f252bc..7afdb08 100644
--- a/src/pulsecore/ioline.c
+++ b/src/pulsecore/ioline.c
@@ -283,7 +283,7 @@ static int do_read(pa_ioline *l) {
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
- while (!l->dead && pa_iochannel_is_readable(l->io)) {
+ while (l->io && !l->dead && pa_iochannel_is_readable(l->io)) {
ssize_t r;
size_t len;
@@ -348,7 +348,7 @@ static int do_write(pa_ioline *l) {
pa_assert(l);
pa_assert(PA_REFCNT_VALUE(l) >= 1);
- while (!l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length) {
+ while (l->io && !l->dead && pa_iochannel_is_writable(l->io) && l->wbuf_valid_length > 0) {
if ((r = pa_iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) <= 0) {
@@ -443,3 +443,25 @@ void pa_ioline_printf(pa_ioline *l, const char *format, ...) {
pa_ioline_puts(l, t);
pa_xfree(t);
}
+
+pa_iochannel* pa_ioline_detach_iochannel(pa_ioline *l) {
+ pa_iochannel *r;
+
+ pa_assert(l);
+
+ if (!l->io)
+ return NULL;
+
+ r = l->io;
+ l->io = NULL;
+
+ pa_iochannel_set_callback(r, NULL, NULL);
+
+ return r;
+}
+
+pa_bool_t pa_ioline_is_drained(pa_ioline *l) {
+ pa_assert(l);
+
+ return l->wbuf_valid_length <= 0;
+}
diff --git a/src/pulsecore/ioline.h b/src/pulsecore/ioline.h
index 26e2a22..d973a3c 100644
--- a/src/pulsecore/ioline.h
+++ b/src/pulsecore/ioline.h
@@ -54,4 +54,11 @@ void pa_ioline_set_drain_callback(pa_ioline*io, pa_ioline_drain_cb_t callback, v
/* Make sure to close the ioline object as soon as the send buffer is emptied */
void pa_ioline_defer_close(pa_ioline *io);
+/* Returns TRUE when everything was written */
+pa_bool_t pa_ioline_is_drained(pa_ioline *io);
+
+/* Detaches from the iochannel and returns it. Data that has already
+ * been read will not be available in the detached iochannel */
+pa_iochannel* pa_ioline_detach_iochannel(pa_ioline *l);
+
#endif
commit 84a92f2a88e9655a4d54410b37d9ca1d741646b9
Author: Lennart Poettering <lennart at poettering.net>
Date: Wed Apr 29 04:15:24 2009 +0200
protocol-http: allow listening into sinks/sources via HTTP
diff --git a/src/pulsecore/protocol-http.c b/src/pulsecore/protocol-http.c
index 08a70e5..6467024 100644
--- a/src/pulsecore/protocol-http.c
+++ b/src/pulsecore/protocol-http.c
@@ -1,7 +1,7 @@
/***
This file is part of PulseAudio.
- Copyright 2005-2006 Lennart Poettering
+ Copyright 2005-2009 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
@@ -26,16 +26,20 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include <pulse/util.h>
#include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
#include <pulsecore/ioline.h>
+#include <pulsecore/thread-mq.h>
#include <pulsecore/macro.h>
#include <pulsecore/log.h>
#include <pulsecore/namereg.h>
#include <pulsecore/cli-text.h>
#include <pulsecore/shared.h>
+#include <pulsecore/core-error.h>
#include "protocol-http.h"
@@ -46,7 +50,7 @@
#define URL_CSS "/style"
#define URL_STATUS "/status"
#define URL_LISTEN "/listen"
-#define URL_LISTEN_PREFIX "/listen/"
+#define URL_LISTEN_SOURCE "/listen/source/"
#define MIME_HTML "text/html; charset=utf-8"
#define MIME_TEXT "text/plain; charset=utf-8"
@@ -65,6 +69,10 @@
#define HTML_FOOTER \
" </body>\n" \
"</html>\n"
+
+#define RECORD_BUFFER_SECONDS (5)
+#define DEFAULT_SOURCE_LATENCY (300*PA_USEC_PER_MSEC)
+
enum state {
STATE_REQUEST_LINE,
STATE_MIME_HEADER,
@@ -73,7 +81,11 @@ enum state {
struct connection {
pa_http_protocol *protocol;
+ pa_iochannel *io;
pa_ioline *line;
+ pa_memblockq *output_memblockq;
+ pa_source_output *source_output;
+ pa_client *client;
enum state state;
char *url;
pa_module *module;
@@ -86,6 +98,163 @@ struct pa_http_protocol {
pa_idxset *connections;
};
+enum {
+ SOURCE_OUTPUT_MESSAGE_POST_DATA = PA_SOURCE_OUTPUT_MESSAGE_MAX
+};
+
+/* Called from main context */
+static void connection_unlink(struct connection *c) {
+ pa_assert(c);
+
+ if (c->source_output) {
+ pa_source_output_unlink(c->source_output);
+ pa_source_output_unref(c->source_output);
+ }
+
+ if (c->client)
+ pa_client_free(c->client);
+
+ pa_xfree(c->url);
+
+ if (c->line)
+ pa_ioline_unref(c->line);
+
+ if (c->io)
+ pa_iochannel_free(c->io);
+
+ if (c->output_memblockq)
+ pa_memblockq_free(c->output_memblockq);
+
+ pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
+
+ pa_xfree(c);
+}
+
+/* Called from main context */
+static int do_write(struct connection *c) {
+ pa_memchunk chunk;
+ ssize_t r;
+ void *p;
+
+ pa_assert(c);
+
+ if (pa_memblockq_peek(c->output_memblockq, &chunk) < 0)
+ return 0;
+
+ pa_assert(chunk.memblock);
+ pa_assert(chunk.length > 0);
+
+ p = pa_memblock_acquire(chunk.memblock);
+ r = pa_iochannel_write(c->io, (uint8_t*) p+chunk.index, chunk.length);
+ pa_memblock_release(chunk.memblock);
+
+ pa_memblock_unref(chunk.memblock);
+
+ if (r < 0) {
+
+ if (errno == EINTR || errno == EAGAIN)
+ return 0;
+
+ pa_log("write(): %s", pa_cstrerror(errno));
+ return -1;
+ }
+
+ pa_memblockq_drop(c->output_memblockq, (size_t) r);
+
+ return 0;
+}
+
+/* Called from main context */
+static void do_work(struct connection *c) {
+ pa_assert(c);
+
+ if (pa_iochannel_is_hungup(c->io))
+ goto fail;
+
+ if (pa_iochannel_is_writable(c->io))
+ if (do_write(c) < 0)
+ goto fail;
+
+ return;
+
+fail:
+ connection_unlink(c);
+}
+
+/* Called from thread context, except when it is not */
+static int source_output_process_msg(pa_msgobject *m, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
+ pa_source_output *o = PA_SOURCE_OUTPUT(m);
+ struct connection *c;
+
+ pa_source_output_assert_ref(o);
+ pa_assert_se(c = o->userdata);
+
+ switch (code) {
+
+ case SOURCE_OUTPUT_MESSAGE_POST_DATA:
+ /* While this function is usually called from IO thread
+ * context, this specific command is not! */
+ pa_memblockq_push_align(c->output_memblockq, chunk);
+ do_work(c);
+ break;
+
+ default:
+ return pa_source_output_process_msg(m, code, userdata, offset, chunk);
+ }
+
+ return 0;
+}
+
+/* Called from thread context */
+static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) {
+ struct connection *c;
+
+ pa_source_output_assert_ref(o);
+ pa_assert_se(c = o->userdata);
+ pa_assert(chunk);
+
+ pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(o), SOURCE_OUTPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL);
+}
+
+/* Called from main context */
+static void source_output_kill_cb(pa_source_output *o) {
+ struct connection*c;
+
+ pa_source_output_assert_ref(o);
+ pa_assert_se(c = o->userdata);
+
+ connection_unlink(c);
+}
+
+/* Called from main context */
+static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
+ struct connection*c;
+
+ pa_source_output_assert_ref(o);
+ pa_assert_se(c = o->userdata);
+
+ return pa_bytes_to_usec(pa_memblockq_get_length(c->output_memblockq), &c->source_output->sample_spec);
+}
+
+/*** client callbacks ***/
+static void client_kill_cb(pa_client *client) {
+ struct connection*c;
+
+ pa_assert(client);
+ pa_assert_se(c = client->userdata);
+
+ connection_unlink(c);
+}
+
+/*** pa_iochannel callbacks ***/
+static void io_callback(pa_iochannel*io, void *userdata) {
+ struct connection *c = userdata;
+
+ pa_assert(c);
+ pa_assert(io);
+
+ do_work(c);
+}
static pa_bool_t is_mime_sample_spec(const pa_sample_spec *ss, const pa_channel_map *cm) {
@@ -317,162 +486,254 @@ static void html_response(
pa_ioline_defer_close(c->line);
}
-static void internal_server_error(struct connection *c) {
- pa_assert(c);
+static void html_print_field(pa_ioline *line, const char *left, const char *right) {
+ char *eleft, *eright;
- html_response(c, 500, "Internal Server Error", NULL);
+ eleft = escape_html(left);
+ eright = escape_html(right);
+
+ pa_ioline_printf(line,
+ "<tr><td><b>%s</b></td>"
+ "<td>%s</td></tr>\n", eleft, eright);
+
+ pa_xfree(eleft);
+ pa_xfree(eright);
}
-static void connection_unlink(struct connection *c) {
+static void handle_root(struct connection *c) {
+ char *t;
+
pa_assert(c);
- if (c->url)
- pa_xfree(c->url);
+ http_response(c, 200, "OK", MIME_HTML);
- if (c->line)
- pa_ioline_unref(c->line);
+ pa_ioline_puts(c->line,
+ HTML_HEADER(PACKAGE_NAME" "PACKAGE_VERSION)
+ "<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
+ "<table>\n");
- pa_idxset_remove_by_data(c->protocol->connections, c, NULL);
+ t = pa_get_user_name_malloc();
+ html_print_field(c->line, "User Name:", t);
+ pa_xfree(t);
- pa_xfree(c);
+ t = pa_get_host_name_malloc();
+ html_print_field(c->line, "Host name:", t);
+ pa_xfree(t);
+
+ t = pa_machine_id();
+ html_print_field(c->line, "Machine ID:", t);
+ pa_xfree(t);
+
+ t = pa_uname_string();
+ html_print_field(c->line, "System:", t);
+ pa_xfree(t);
+
+ t = pa_sprintf_malloc("%lu", (unsigned long) getpid());
+ html_print_field(c->line, "Process ID:", t);
+ pa_xfree(t);
+
+ pa_ioline_puts(c->line,
+ "</table>\n"
+ "<p><a href=\"" URL_STATUS "\">Show an extensive server status report</a></p>\n"
+ "<p><a href=\"" URL_LISTEN "\">Monitor sinks and sources</a></p>\n"
+ HTML_FOOTER);
+
+ pa_ioline_defer_close(c->line);
}
-static void html_print_field(pa_ioline *line, const char *left, const char *right) {
- char *eleft, *eright;
+static void handle_css(struct connection *c) {
+ pa_assert(c);
- eleft = escape_html(left);
- eright = escape_html(right);
+ http_response(c, 200, "OK", MIME_CSS);
- pa_ioline_printf(line,
- "<tr><td><b>%s</b></td>"
- "<td>%s</td></tr>\n", eleft, eright);
+ pa_ioline_puts(c->line,
+ "body { color: black; background-color: white; }\n"
+ "a:link, a:visited { color: #900000; }\n"
+ "div.news-date { font-size: 80%; font-style: italic; }\n"
+ "pre { background-color: #f0f0f0; padding: 0.4cm; }\n"
+ ".grey { color: #8f8f8f; font-size: 80%; }"
+ "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
+ "td { padding-left:10px; padding-right:10px; }\n");
- pa_xfree(eleft);
- pa_xfree(eright);
+ pa_ioline_defer_close(c->line);
}
-static void handle_url(struct connection *c) {
+static void handle_status(struct connection *c) {
+ char *r;
+
pa_assert(c);
- pa_log_debug("Request for %s", c->url);
+ http_response(c, 200, "OK", MIME_TEXT);
+ r = pa_full_status_string(c->protocol->core);
+ pa_ioline_puts(c->line, r);
+ pa_xfree(r);
- if (pa_streq(c->url, URL_ROOT)) {
- char *t;
+ pa_ioline_defer_close(c->line);
+}
- http_response(c, 200, "OK", MIME_HTML);
+static void handle_listen(struct connection *c) {
+ pa_source *source;
+ pa_sink *sink;
+ uint32_t idx;
- pa_ioline_puts(c->line,
- HTML_HEADER(PACKAGE_NAME" "PACKAGE_VERSION)
- "<h1>"PACKAGE_NAME" "PACKAGE_VERSION"</h1>\n"
- "<table>\n");
+ http_response(c, 200, "OK", MIME_HTML);
- t = pa_get_user_name_malloc();
- html_print_field(c->line, "User Name:", t);
- pa_xfree(t);
+ pa_ioline_puts(c->line,
+ HTML_HEADER("Listen")
+ "<h2>Sinks</h2>\n"
+ "<p>\n");
- t = pa_get_host_name_malloc();
- html_print_field(c->line, "Host name:", t);
- pa_xfree(t);
+ PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
+ char *t, *m;
- t = pa_machine_id();
- html_print_field(c->line, "Machine ID:", t);
- pa_xfree(t);
+ t = escape_html(pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
+ m = mimefy_and_stringify_sample_spec(&sink->sample_spec, &sink->channel_map);
+
+ pa_ioline_printf(c->line,
+ "<a href=\"" URL_LISTEN_SOURCE "%s\" title=\"%s\">%s</a><br/>\n",
+ sink->monitor_source->name, m, t);
- t = pa_uname_string();
- html_print_field(c->line, "System:", t);
pa_xfree(t);
+ pa_xfree(m);
+ }
+
+ pa_ioline_puts(c->line,
+ "</p>\n"
+ "<h2>Sources</h2>\n"
+ "<p>\n");
+
+ PA_IDXSET_FOREACH(source, c->protocol->core->sources, idx) {
+ char *t, *m;
+
+ if (source->monitor_of)
+ continue;
- t = pa_sprintf_malloc("%lu", (unsigned long) getpid());
- html_print_field(c->line, "Process ID:", t);
+ t = escape_html(pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
+ m = mimefy_and_stringify_sample_spec(&source->sample_spec, &source->channel_map);
+
+ pa_ioline_printf(c->line,
+ "<a href=\"" URL_LISTEN_SOURCE "%s\" title=\"%s\">%s</a><br/>\n",
+ source->name, m, t);
+
+ pa_xfree(m);
pa_xfree(t);
- pa_ioline_puts(c->line,
- "</table>\n"
- "<p><a href=\"/status\">Show an extensive server status report</a></p>\n"
- "<p><a href=\"/listen\">Monitor sinks and sources</a></p>\n"
- HTML_FOOTER);
+ }
- pa_ioline_defer_close(c->line);
+ pa_ioline_puts(c->line,
+ "</p>\n"
+ HTML_FOOTER);
- } else if (pa_streq(c->url, URL_CSS)) {
- http_response(c, 200, "OK", MIME_CSS);
+ pa_ioline_defer_close(c->line);
+}
- pa_ioline_puts(c->line,
- "body { color: black; background-color: white; }\n"
- "a:link, a:visited { color: #900000; }\n"
- "div.news-date { font-size: 80%; font-style: italic; }\n"
- "pre { background-color: #f0f0f0; padding: 0.4cm; }\n"
- ".grey { color: #8f8f8f; font-size: 80%; }"
- "table { margin-left: 1cm; border:1px solid lightgrey; padding: 0.2cm; }\n"
- "td { padding-left:10px; padding-right:10px; }\n");
+static void line_drain_callback(pa_ioline *l, void *userdata) {
+ struct connection *c;
- pa_ioline_defer_close(c->line);
+ pa_assert(l);
+ pa_assert_se(c = userdata);
- } else if (pa_streq(c->url, URL_STATUS)) {
- char *r;
+ /* We don't need the line reader anymore, instead we need a real
+ * binary io channel */
+ pa_assert_se(c->io = pa_ioline_detach_iochannel(c->line));
+ pa_iochannel_set_callback(c->io, io_callback, c);
- http_response(c, 200, "OK", MIME_TEXT);
- r = pa_full_status_string(c->protocol->core);
- pa_ioline_puts(c->line, r);
- pa_xfree(r);
+ pa_iochannel_socket_set_sndbuf(c->io, pa_memblockq_get_length(c->output_memblockq));
- pa_ioline_defer_close(c->line);
+ pa_ioline_unref(c->line);
+ c->line = NULL;
+}
- } else if (pa_streq(c->url, URL_LISTEN)) {
- pa_source *source;
- pa_sink *sink;
- uint32_t idx;
+static void handle_listen_prefix(struct connection *c, const char *source_name) {
+ pa_source *source;
+ pa_source_output_new_data data;
+ pa_sample_spec ss;
+ pa_channel_map cm;
+ char *t;
+ size_t l;
- http_response(c, 200, "OK", MIME_HTML);
+ pa_assert(c);
+ pa_assert(source_name);
- pa_ioline_puts(c->line,
- HTML_HEADER("Listen")
- "<h2>Sinks</h2>\n"
- "<p>\n");
+ pa_assert(c->line);
+ pa_assert(!c->io);
- PA_IDXSET_FOREACH(sink, c->protocol->core->sinks, idx) {
- char *t, *m;
+ if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) {
+ html_response(c, 404, "Source not found", NULL);
+ return;
+ }
- t = escape_html(pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
- m = mimefy_and_stringify_sample_spec(&sink->sample_spec, &sink->channel_map);
+ ss = source->sample_spec;
+ cm = source->channel_map;
- pa_ioline_printf(c->line,
- "<a href=\"/listen/%s\" title=\"%s\">%s</a><br/>\n",
- sink->monitor_source->name, m, t);
+ mimefy_sample_spec(&ss, &cm);
- pa_xfree(t);
- pa_xfree(m);
- }
+ pa_source_output_new_data_init(&data);
+ data.driver = __FILE__;
+ data.module = c->module;
+ data.client = c->client;
+ data.source = source;
+ pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
+ pa_source_output_new_data_set_sample_spec(&data, &ss);
+ pa_source_output_new_data_set_channel_map(&data, &cm);
- pa_ioline_puts(c->line,
- "</p>\n"
- "<h2>Sources</h2>\n"
- "<p>\n");
+ pa_source_output_new(&c->source_output, c->protocol->core, &data, 0);
+ pa_source_output_new_data_done(&data);
- PA_IDXSET_FOREACH(source, c->protocol->core->sources, idx) {
- char *t, *m;
+ if (!c->source_output) {
+ html_response(c, 403, "Cannot create source output", NULL);
+ return;
+ }
- if (source->monitor_of)
- continue;
+ c->source_output->parent.process_msg = source_output_process_msg;
+ c->source_output->push = source_output_push_cb;
+ c->source_output->kill = source_output_kill_cb;
+ c->source_output->get_latency = source_output_get_latency_cb;
+ c->source_output->userdata = c;
- t = escape_html(pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
- m = mimefy_and_stringify_sample_spec(&source->sample_spec, &source->channel_map);
+ pa_source_output_set_requested_latency(c->source_output, DEFAULT_SOURCE_LATENCY);
- pa_ioline_printf(c->line,
- "<a href=\"/listen/%s\" title=\"%s\">%s</a><br/>\n",
- source->name, m, t);
+ l = (size_t) (pa_bytes_per_second(&ss)*RECORD_BUFFER_SECONDS);
+ c->output_memblockq = pa_memblockq_new(
+ 0,
+ l,
+ 0,
+ pa_frame_size(&ss),
+ 1,
+ 0,
+ 0,
+ NULL);
- pa_xfree(m);
- pa_xfree(t);
+ pa_source_output_put(c->source_output);
- }
+ t = sample_spec_to_mime_type(&ss, &cm);
+ http_response(c, 200, "OK", t);
+ pa_xfree(t);
- pa_ioline_puts(c->line,
- "</p>\n"
- HTML_FOOTER);
+ pa_ioline_set_callback(c->line, NULL, NULL);
- pa_ioline_defer_close(c->line);
- } else
+ if (pa_ioline_is_drained(c->line))
+ line_drain_callback(c->line, c);
+ else
+ pa_ioline_set_drain_callback(c->line, line_drain_callback, c);
+}
+
+static void handle_url(struct connection *c) {
+ pa_assert(c);
+
+ pa_log_debug("Request for %s", c->url);
+
+ if (pa_streq(c->url, URL_ROOT))
+ handle_root(c);
+ else if (pa_streq(c->url, URL_CSS))
+ handle_css(c);
+ else if (pa_streq(c->url, URL_STATUS))
+ handle_status(c);
+ else if (pa_streq(c->url, URL_LISTEN))
+ handle_listen(c);
+ else if (pa_startswith(c->url, URL_LISTEN_SOURCE))
+ handle_listen_prefix(c, c->url + sizeof(URL_LISTEN_SOURCE)-1);
+ else
html_response(c, 404, "Not Found", NULL);
}
@@ -519,11 +780,13 @@ static void line_callback(pa_ioline *line, const char *s, void *userdata) {
return;
fail:
- internal_server_error(c);
+ html_response(c, 500, "Internal Server Error", NULL);
}
void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *m) {
struct connection *c;
+ pa_client_new_data client_data;
+ char pname[128];
pa_assert(p);
pa_assert(io);
@@ -535,16 +798,36 @@ void pa_http_protocol_connect(pa_http_protocol *p, pa_iochannel *io, pa_module *
return;
}
- c = pa_xnew(struct connection, 1);
+ c = pa_xnew0(struct connection, 1);
c->protocol = p;
- c->line = pa_ioline_new(io);
c->state = STATE_REQUEST_LINE;
- c->url = NULL;
c->module = m;
+ c->line = pa_ioline_new(io);
pa_ioline_set_callback(c->line, line_callback, c);
+ pa_client_new_data_init(&client_data);
+ client_data.module = c->module;
+ client_data.driver = __FILE__;
+ pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
+ pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "HTTP client (%s)", pname);
+ pa_proplist_sets(client_data.proplist, "http-protocol.peer", pname);
+ c->client = pa_client_new(p->core, &client_data);
+ pa_client_new_data_done(&client_data);
+
+ if (!c->client)
+ goto fail;
+
+ c->client->kill = client_kill_cb;
+ c->client->userdata = c;
+
pa_idxset_put(p->connections, c, NULL);
+
+ return;
+
+fail:
+ if (c)
+ connection_unlink(c);
}
void pa_http_protocol_disconnect(pa_http_protocol *p, pa_module *m) {
--
hooks/post-receive
PulseAudio Sound Server
More information about the pulseaudio-commits
mailing list