summaryrefslogtreecommitdiffstats
path: root/src/pulsecore
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore')
-rw-r--r--src/pulsecore/card.c198
-rw-r--r--src/pulsecore/card.h91
-rw-r--r--src/pulsecore/cli-command.c17
-rw-r--r--src/pulsecore/cli-text.c45
-rw-r--r--src/pulsecore/cli-text.h2
-rw-r--r--src/pulsecore/cli.c19
-rw-r--r--src/pulsecore/client.c47
-rw-r--r--src/pulsecore/client.h17
-rw-r--r--src/pulsecore/core.c4
-rw-r--r--src/pulsecore/core.h8
-rw-r--r--src/pulsecore/namereg.c2
-rw-r--r--src/pulsecore/namereg.h3
-rw-r--r--src/pulsecore/play-memblockq.c2
-rw-r--r--src/pulsecore/protocol-esound.c24
-rw-r--r--src/pulsecore/protocol-native.c26
-rw-r--r--src/pulsecore/protocol-simple.c20
-rw-r--r--src/pulsecore/shared.c2
-rw-r--r--src/pulsecore/sink-input.c29
-rw-r--r--src/pulsecore/sink-input.h5
-rw-r--r--src/pulsecore/sink.c18
-rw-r--r--src/pulsecore/sink.h3
-rw-r--r--src/pulsecore/sound-file-stream.c2
-rw-r--r--src/pulsecore/source-output.c6
-rw-r--r--src/pulsecore/source.c13
-rw-r--r--src/pulsecore/source.h3
25 files changed, 541 insertions, 65 deletions
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
new file mode 100644
index 00000000..03b9ebd7
--- /dev/null
+++ b/src/pulsecore/card.c
@@ -0,0 +1,198 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 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
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/namereg.h>
+
+#include "card.h"
+
+pa_card_config *pa_card_config_new(const char *name) {
+ pa_card_config *c;
+
+ pa_assert(name);
+
+ c = pa_xnew0(pa_card_config, 1);
+ c->name = pa_xstrdup(name);
+
+ return c;
+}
+
+void pa_card_config_free(pa_card_config *c) {
+ pa_assert(c);
+
+ pa_xfree(c->name);
+ pa_xfree(c);
+}
+
+pa_card_new_data* pa_card_new_data_init(pa_card_new_data *data) {
+ pa_assert(data);
+
+ memset(data, 0, sizeof(*data));
+ data->proplist = pa_proplist_new();
+
+ return data;
+}
+
+void pa_card_new_data_set_name(pa_card_new_data *data, const char *name) {
+ pa_assert(data);
+
+ pa_xfree(data->name);
+ data->name = pa_xstrdup(name);
+}
+
+void pa_card_new_data_done(pa_card_new_data *data) {
+
+ pa_assert(data);
+
+ pa_proplist_free(data->proplist);
+
+ if (data->configs) {
+ pa_card_config *c;
+
+ while ((c = pa_hashmap_steal_first(data->configs)))
+ pa_card_config_free(c);
+
+ pa_hashmap_free(data->configs, NULL, NULL);
+ }
+
+ pa_xfree(data->name);
+}
+
+pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
+ pa_card *c;
+ const char *name;
+
+ pa_core_assert_ref(core);
+ pa_assert(data);
+ pa_assert(data->name);
+
+ c = pa_xnew(pa_card, 1);
+
+ if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_CARD, c, data->namereg_fail))) {
+ pa_xfree(c);
+ return NULL;
+ }
+
+ pa_card_new_data_set_name(data, name);
+
+ if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_NEW], data) < 0) {
+ pa_xfree(c);
+ pa_namereg_unregister(core, name);
+ return NULL;
+ }
+
+ c->core = core;
+ c->name = pa_xstrdup(data->name);
+ c->proplist = pa_proplist_copy(data->proplist);
+ c->driver = pa_xstrdup(data->driver);
+ c->module = data->module;
+
+ c->sinks = pa_idxset_new(NULL, NULL);
+ c->sources = pa_idxset_new(NULL, NULL);
+
+ c->configs = data->configs;
+ data->configs = NULL;
+ c->active_config = data->active_config;
+ data->active_config = NULL;
+
+ c->userdata = NULL;
+ c->set_config = NULL;
+
+ pa_assert_se(pa_idxset_put(core->cards, c, &c->index) >= 0);
+
+ pa_log_info("Created %u \"%s\"", c->index, c->name);
+ pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_NEW, c->index);
+
+ pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_PUT], c);
+ return c;
+}
+
+void pa_card_free(pa_card *c) {
+ pa_core *core;
+ pa_card_config *config;
+
+ pa_assert(c);
+ pa_assert(c->core);
+
+ core = c->core;
+
+ pa_hook_fire(&core->hooks[PA_CORE_HOOK_CARD_UNLINK], c);
+
+ pa_namereg_unregister(core, c->name);
+
+ pa_idxset_remove_by_data(c->core->cards, c, NULL);
+
+ pa_log_info("Freed %u \"%s\"", c->index, c->name);
+
+ pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
+
+ pa_assert(pa_idxset_isempty(c->sinks));
+ pa_idxset_free(c->sinks, NULL, NULL);
+ pa_assert(pa_idxset_isempty(c->sources));
+ pa_idxset_free(c->sources, NULL, NULL);
+
+ while ((config = pa_hashmap_steal_first(c->configs)))
+ pa_card_config_free(config);
+
+ pa_hashmap_free(c->configs, NULL, NULL);
+
+ pa_proplist_free(c->proplist);
+ pa_xfree(c->driver);
+ pa_xfree(c->name);
+ pa_xfree(c);
+
+ pa_core_check_idle(core);
+}
+
+int pa_card_set_config(pa_card *c, const char *name) {
+ pa_card_config *config;
+ pa_assert(c);
+
+ if (!c->set_config) {
+ pa_log_warn("set_config() operation not implemented for card %u", c->index);
+ return -1;
+ }
+
+ if (!c->configs)
+ return -1;
+
+ if (!(config = pa_hashmap_get(c->configs, name)))
+ return -1;
+
+ if (c->set_config(c, config) < 0)
+ return -1;
+
+ pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
+
+ return 0;
+}
diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
new file mode 100644
index 00000000..40e4a3ee
--- /dev/null
+++ b/src/pulsecore/card.h
@@ -0,0 +1,91 @@
+#ifndef foopulsecardhfoo
+#define foopulsecardhfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 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
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+typedef struct pa_card pa_card;
+
+#include <pulse/proplist.h>
+#include <pulsecore/core.h>
+#include <pulsecore/module.h>
+#include <pulsecore/idxset.h>
+
+typedef struct pa_card_config {
+ char *name;
+
+ pa_bool_t optical_sink:1;
+ pa_bool_t optical_source:1;
+
+ unsigned n_sinks;
+ unsigned n_sources;
+
+ unsigned max_sink_channels;
+ unsigned max_source_channels;
+} pa_card_config;
+
+struct pa_card {
+ uint32_t index;
+ pa_core *core;
+
+ char *name;
+
+ pa_proplist *proplist;
+ pa_module *module;
+ char *driver;
+
+ pa_idxset *sinks;
+ pa_idxset *sources;
+
+ pa_hashmap *configs;
+ pa_card_config *active_config;
+
+ void *userdata;
+
+ int (*set_config)(pa_card *c, pa_card_config *config);
+};
+
+typedef struct pa_card_new_data {
+ char *name;
+
+ pa_proplist *proplist;
+ const char *driver;
+ pa_module *module;
+
+ pa_hashmap *configs;
+ pa_card_config *active_config;
+
+ pa_bool_t namereg_fail:1;
+} pa_card_new_data;
+
+pa_card_config *pa_card_config_new(const char *name);
+void pa_card_config_free(pa_card_config *c);
+
+pa_card_new_data *pa_card_new_data_init(pa_card_new_data *data);
+void pa_card_new_data_set_name(pa_card_new_data *data, const char *name);
+void pa_card_new_data_done(pa_card_new_data *data);
+
+pa_card *pa_card_new(pa_core *c, pa_card_new_data *data);
+void pa_card_free(pa_card *c);
+
+int pa_card_set_config(pa_card *c, const char *name);
+
+#endif
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index 07d55d07..93d6bbe6 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -80,6 +80,7 @@ static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
+static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
@@ -137,6 +138,7 @@ static const struct command commands[] = {
{ "list-clients", pa_cli_command_clients, "List loaded clients", 1 },
{ "list-sink-inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 },
{ "list-source-outputs", pa_cli_command_source_outputs, "List source outputs", 1 },
+ { "list-cards", pa_cli_command_cards, "List cards", 1 },
{ "stat", pa_cli_command_stat, "Show memory block statistics", 1 },
{ "info", pa_cli_command_info, "Show comprehensive status", 1 },
{ "ls", pa_cli_command_info, NULL, 1 },
@@ -254,6 +256,20 @@ static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, p
return 0;
}
+static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
+ char *s;
+
+ pa_core_assert_ref(c);
+ pa_assert(t);
+ pa_assert(buf);
+ pa_assert(fail);
+
+ pa_assert_se(s = pa_card_list_to_string(c));
+ pa_strbuf_puts(buf, s);
+ pa_xfree(s);
+ return 0;
+}
+
static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
char *s;
@@ -382,6 +398,7 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
pa_cli_command_sinks(c, t, buf, fail);
pa_cli_command_sources(c, t, buf, fail);
pa_cli_command_clients(c, t, buf, fail);
+ pa_cli_command_cards(c, t, buf, fail);
pa_cli_command_sink_inputs(c, t, buf, fail);
pa_cli_command_source_outputs(c, t, buf, fail);
pa_cli_command_scache_list(c, t, buf, fail);
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 362a9791..5d78ce64 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -97,6 +97,38 @@ char *pa_client_list_to_string(pa_core *c) {
return pa_strbuf_tostring_free(s);
}
+char *pa_card_list_to_string(pa_core *c) {
+ pa_strbuf *s;
+ pa_card *card;
+ uint32_t idx = PA_IDXSET_INVALID;
+ pa_assert(c);
+
+ s = pa_strbuf_new();
+
+ pa_strbuf_printf(s, "%u card(s) available in.\n", pa_idxset_size(c->cards));
+
+ for (card = pa_idxset_first(c->cards, &idx); card; card = pa_idxset_next(c->cards, &idx)) {
+ char *t;
+ pa_strbuf_printf(
+ s,
+ " index: %u\n"
+ "\tname: <%s>\n"
+ "\tdriver: <%s>\n",
+ card->index,
+ card->name,
+ card->driver);
+
+ if (card->module)
+ pa_strbuf_printf(s, "\towner module: %u\n", card->module->index);
+
+ t = pa_proplist_to_string(card->proplist);
+ pa_strbuf_printf(s, "\tproperties:\n%s", t);
+ pa_xfree(t);
+ }
+
+ return pa_strbuf_tostring_free(s);
+}
+
char *pa_sink_list_to_string(pa_core *c) {
pa_strbuf *s;
pa_sink *sink;
@@ -174,6 +206,8 @@ char *pa_sink_list_to_string(pa_core *c) {
pa_sink_used_by(sink),
pa_sink_linked_by(sink));
+ if (sink->card)
+ pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name);
if (sink->module)
pa_strbuf_printf(s, "\tmodule: %u\n", sink->module->index);
@@ -260,6 +294,8 @@ char *pa_source_list_to_string(pa_core *c) {
if (source->monitor_of)
pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index);
+ if (source->card)
+ pa_strbuf_printf(s, "\tcard: %u <%s>\n", source->card->index, source->card->name);
if (source->module)
pa_strbuf_printf(s, "\tmodule: %u\n", source->module->index);
@@ -508,7 +544,7 @@ char *pa_full_status_string(pa_core *c) {
s = pa_strbuf_new();
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < 9; i++) {
char *t = NULL;
switch (i) {
@@ -528,12 +564,15 @@ char *pa_full_status_string(pa_core *c) {
t = pa_client_list_to_string(c);
break;
case 5:
- t = pa_module_list_to_string(c);
+ t = pa_card_list_to_string(c);
break;
case 6:
- t = pa_scache_list_to_string(c);
+ t = pa_module_list_to_string(c);
break;
case 7:
+ t = pa_scache_list_to_string(c);
+ break;
+ case 8:
t = pa_autoload_list_to_string(c);
break;
}
diff --git a/src/pulsecore/cli-text.h b/src/pulsecore/cli-text.h
index f4cb97a5..167565e5 100644
--- a/src/pulsecore/cli-text.h
+++ b/src/pulsecore/cli-text.h
@@ -31,6 +31,7 @@ char *pa_sink_input_list_to_string(pa_core *c);
char *pa_source_output_list_to_string(pa_core *c);
char *pa_sink_list_to_string(pa_core *core);
char *pa_source_list_to_string(pa_core *c);
+char *pa_card_list_to_string(pa_core *c);
char *pa_client_list_to_string(pa_core *c);
char *pa_module_list_to_string(pa_core *c);
char *pa_scache_list_to_string(pa_core *c);
@@ -39,4 +40,3 @@ char *pa_autoload_list_to_string(pa_core *c);
char *pa_full_status_string(pa_core *c);
#endif
-
diff --git a/src/pulsecore/cli.c b/src/pulsecore/cli.c
index 67bf1e73..25a4f748 100644
--- a/src/pulsecore/cli.c
+++ b/src/pulsecore/cli.c
@@ -67,20 +67,33 @@ static void client_kill(pa_client *c);
pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) {
char cname[256];
pa_cli *c;
+ pa_client_new_data data;
+ pa_client *client;
+
pa_assert(io);
+ pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
+
+ pa_client_new_data_init(&data);
+ data.driver = __FILE__;
+ data.module = m;
+ pa_proplist_sets(data.proplist, PA_PROP_APPLICATION_NAME, cname);
+ client = pa_client_new(core, &data);
+ pa_client_new_data_done(&data);
+
+ if (!client)
+ return NULL;
+
c = pa_xnew(pa_cli, 1);
c->core = core;
+ c->client = client;
pa_assert_se(c->line = pa_ioline_new(io));
c->userdata = NULL;
c->eof_callback = NULL;
- pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
- pa_assert_se(c->client = pa_client_new(core, __FILE__, cname));
c->client->kill = client_kill;
c->client->userdata = c;
- c->client->module = m;
pa_ioline_set_callback(c->line, line_callback, c);
pa_ioline_puts(c->line, "Welcome to PulseAudio! Use \"help\" for usage information.\n"PROMPT);
diff --git a/src/pulsecore/client.c b/src/pulsecore/client.c
index ab6e5df4..1e65fcd9 100644
--- a/src/pulsecore/client.c
+++ b/src/pulsecore/client.c
@@ -37,27 +37,49 @@
#include "client.h"
-pa_client *pa_client_new(pa_core *core, const char *driver, const char *name) {
+pa_client_new_data* pa_client_new_data_init(pa_client_new_data *data) {
+ pa_assert(data);
+
+ memset(data, 0, sizeof(*data));
+ data->proplist = pa_proplist_new();
+
+ return data;
+}
+
+void pa_client_new_data_done(pa_client_new_data *data) {
+ pa_assert(data);
+
+ pa_proplist_free(data->proplist);
+}
+
+pa_client *pa_client_new(pa_core *core, pa_client_new_data *data) {
pa_client *c;
pa_core_assert_ref(core);
+ pa_assert(data);
+
+ if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_NEW], data) < 0)
+ return NULL;
c = pa_xnew(pa_client, 1);
c->core = core;
- c->proplist = pa_proplist_new();
- if (name)
- pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
- c->driver = pa_xstrdup(driver);
- c->module = NULL;
+ c->proplist = pa_proplist_copy(data->proplist);
+ c->driver = pa_xstrdup(data->driver);
+ c->module = data->module;
+
+ c->sink_inputs = pa_idxset_new(NULL, NULL);
+ c->source_outputs = pa_idxset_new(NULL, NULL);
- c->kill = NULL;
c->userdata = NULL;
+ c->kill = NULL;
pa_assert_se(pa_idxset_put(core->clients, c, &c->index) >= 0);
- pa_log_info("Created %u \"%s\"", c->index, pa_strnull(name));
+ pa_log_info("Created %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_NEW, c->index);
+ pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_PUT], c);
+
pa_core_check_idle(core);
return c;
@@ -70,10 +92,19 @@ void pa_client_free(pa_client *c) {
pa_assert(c->core);
core = c->core;
+
+ pa_hook_fire(&core->hooks[PA_CORE_HOOK_CLIENT_UNLINK], c);
+
pa_idxset_remove_by_data(c->core->clients, c, NULL);
pa_log_info("Freed %u \"%s\"", c->index, pa_strnull(pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)));
pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
+
+ pa_assert(pa_idxset_isempty(c->sink_inputs));
+ pa_idxset_free(c->sink_inputs, NULL, NULL);
+ pa_assert(pa_idxset_isempty(c->source_outputs));
+ pa_idxset_free(c->source_outputs, NULL, NULL);
+
pa_proplist_free(c->proplist);
pa_xfree(c->driver);
pa_xfree(c);
diff --git a/src/pulsecore/client.h b/src/pulsecore/client.h
index 28d1fe5f..48e9bc7a 100644
--- a/src/pulsecore/client.h
+++ b/src/pulsecore/client.h
@@ -42,11 +42,24 @@ struct pa_client {
pa_module *module;
char *driver;
- void (*kill)(pa_client *c);
+ pa_idxset *sink_inputs;
+ pa_idxset *source_outputs;
+
void *userdata;
+
+ void (*kill)(pa_client *c);
};
-pa_client *pa_client_new(pa_core *c, const char *driver, const char *name);
+typedef struct pa_client_new_data {
+ pa_proplist *proplist;
+ const char *driver;
+ pa_module *module;
+} pa_client_new_data;
+
+pa_client_new_data *pa_client_new_data_init(pa_client_new_data *data);
+void pa_client_new_data_done(pa_client_new_data *data);
+
+pa_client *pa_client_new(pa_core *c, pa_client_new_data *data);
/* This function should be called only by the code that created the client */
void pa_client_free(pa_client *c);
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 5761bbc7..20764325 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -97,6 +97,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) {
c->sources = pa_idxset_new(NULL, NULL);
c->source_outputs = pa_idxset_new(NULL, NULL);
c->sink_inputs = pa_idxset_new(NULL, NULL);
+ c->cards = pa_idxset_new(NULL, NULL);
c->default_source_name = c->default_sink_name = NULL;
@@ -167,6 +168,9 @@ static void core_free(pa_object *o) {
pa_assert(pa_idxset_isempty(c->clients));
pa_idxset_free(c->clients, NULL, NULL);
+ pa_assert(pa_idxset_isempty(c->cards));
+ pa_idxset_free(c->cards, NULL, NULL);
+
pa_assert(pa_idxset_isempty(c->sinks));
pa_idxset_free(c->sinks, NULL, NULL);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index f796fb93..87ea4ab6 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -76,6 +76,12 @@ typedef enum pa_core_hook {
PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_POST,
PA_CORE_HOOK_SOURCE_OUTPUT_STATE_CHANGED,
PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED,
+ PA_CORE_HOOK_CLIENT_NEW,
+ PA_CORE_HOOK_CLIENT_PUT,
+ PA_CORE_HOOK_CLIENT_UNLINK,
+ PA_CORE_HOOK_CARD_NEW,
+ PA_CORE_HOOK_CARD_PUT,
+ PA_CORE_HOOK_CARD_UNLINK,
PA_CORE_HOOK_MAX
} pa_core_hook_t;
@@ -93,7 +99,7 @@ struct pa_core {
pa_mainloop_api *mainloop;
/* idxset of all kinds of entities */
- pa_idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset;
+ pa_idxset *clients, *cards, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *autoload_idxset;
/* Some hashmaps for all sorts of entities */
pa_hashmap *namereg, *autoload_hashmap, *shared;
diff --git a/src/pulsecore/namereg.c b/src/pulsecore/namereg.c
index ecd8def8..c1a434ae 100644
--- a/src/pulsecore/namereg.c
+++ b/src/pulsecore/namereg.c
@@ -109,7 +109,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t
if (!*name)
return NULL;
- if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE) &&
+ if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) &&
!pa_namereg_is_valid_name(name)) {
if (fail)
diff --git a/src/pulsecore/namereg.h b/src/pulsecore/namereg.h
index f4581006..8ce548a7 100644
--- a/src/pulsecore/namereg.h
+++ b/src/pulsecore/namereg.h
@@ -30,7 +30,8 @@
typedef enum pa_namereg_type {
PA_NAMEREG_SINK,
PA_NAMEREG_SOURCE,
- PA_NAMEREG_SAMPLE
+ PA_NAMEREG_SAMPLE,
+ PA_NAMEREG_CARD
} pa_namereg_type_t;
void pa_namereg_free(pa_core *c);
diff --git a/src/pulsecore/play-memblockq.c b/src/pulsecore/play-memblockq.c
index 86edfe98..758c0dee 100644
--- a/src/pulsecore/play-memblockq.c
+++ b/src/pulsecore/play-memblockq.c
@@ -109,7 +109,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT)
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) {
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 460119a9..6524b684 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -1238,7 +1238,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
pa_log_debug("Requesting rewind due to end of underrun.");
- pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE, FALSE);
}
/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
@@ -1377,7 +1377,9 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev
void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esound_options *o) {
connection *c;
- char cname[256], pname[128];
+ char pname[128];
+ pa_client_new_data data;
+ pa_client *client;
pa_assert(p);
pa_assert(io);
@@ -1389,6 +1391,18 @@ void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esou
return;
}
+ pa_client_new_data_init(&data);
+ data.module = o->module;
+ data.driver = __FILE__;
+ pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
+ pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "EsounD client (%s)", pname);
+ pa_proplist_sets(data.proplist, "esound-protocol.peer", pname);
+ client = pa_client_new(p->core, &data);
+ pa_client_new_data_done(&data);
+
+ if (!client)
+ return;
+
c = pa_msgobject_new(connection);
c->parent.parent.free = connection_free;
c->parent.process_msg = connection_process_msg;
@@ -1396,11 +1410,7 @@ void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esou
c->io = io;
pa_iochannel_set_callback(c->io, io_callback, c);
- pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
- pa_snprintf(cname, sizeof(cname), "EsounD client (%s)", pname);
- c->client = pa_client_new(p->core, __FILE__, cname);
- pa_proplist_sets(c->client->proplist, "esound-protocol.peer", pname);
- c->client->module = o->module;
+ c->client = client;
c->client->kill = client_kill_cb;
c->client->userdata = c;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 3c1e5761..d99e212f 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -1240,7 +1240,7 @@ static void handle_seek(playback_stream *s, int64_t indexw) {
pa_log_debug("Requesting rewind due to end of underrun.");
pa_sink_input_request_rewind(s->sink_input,
(size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for),
- FALSE, TRUE);
+ FALSE, TRUE, FALSE);
}
} else {
@@ -1253,7 +1253,7 @@ static void handle_seek(playback_stream *s, int64_t indexw) {
* let's have it usk us again */
pa_log_debug("Requesting rewind due to rewrite.");
- pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE);
+ pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE);
}
}
@@ -4214,7 +4214,9 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev
void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) {
pa_native_connection *c;
- char cname[256], pname[128];
+ char pname[128];
+ pa_client *client;
+ pa_client_new_data data;
pa_assert(p);
pa_assert(io);
@@ -4226,6 +4228,18 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati
return;
}
+ pa_client_new_data_init(&data);
+ data.module = o->module;
+ data.driver = __FILE__;
+ pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
+ pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname);
+ pa_proplist_sets(data.proplist, "native-protocol.peer", pname);
+ client = pa_client_new(p->core, &data);
+ pa_client_new_data_done(&data);
+
+ if (!client)
+ return;
+
c = pa_msgobject_new(pa_native_connection);
c->parent.parent.free = native_connection_free;
c->parent.process_msg = native_connection_process_msg;
@@ -4257,13 +4271,9 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati
c->is_local = pa_iochannel_socket_is_local(io);
c->version = 8;
- pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
- pa_snprintf(cname, sizeof(cname), "Native client (%s)", pname);
- c->client = pa_client_new(p->core, __FILE__, cname);
- pa_proplist_sets(c->client->proplist, "native-protocol.peer", pname);
+ c->client = client;
c->client->kill = client_kill_cb;
c->client->userdata = c;
- c->client->module = o->module;
c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool);
pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
diff --git a/src/pulsecore/protocol-simple.c b/src/pulsecore/protocol-simple.c
index 743bf2ee..a754669c 100644
--- a/src/pulsecore/protocol-simple.c
+++ b/src/pulsecore/protocol-simple.c
@@ -323,7 +323,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
if (pa_memblockq_is_readable(c->input_memblockq) && c->playback.underrun) {
pa_log_debug("Requesting rewind due to end of underrun.");
- pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(c->sink_input, 0, FALSE, TRUE, FALSE);
}
/* pa_log("got data, %u", pa_memblockq_get_length(c->input_memblockq)); */
@@ -476,7 +476,8 @@ static void io_callback(pa_iochannel*io, void *userdata) {
void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simple_options *o) {
connection *c = NULL;
- char cname[256], pname[128];
+ char pname[128];
+ pa_client_new_data client_data;
pa_assert(p);
pa_assert(io);
@@ -505,11 +506,18 @@ void pa_simple_protocol_connect(pa_simple_protocol *p, pa_iochannel *io, pa_simp
c->playback.underrun = TRUE;
pa_atomic_store(&c->playback.missing, 0);
+ pa_client_new_data_init(&client_data);
+ client_data.module = o->module;
+ client_data.driver = __FILE__;
pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname));
- pa_snprintf(cname, sizeof(cname), "Simple client (%s)", pname);
- pa_assert_se(c->client = pa_client_new(p->core, __FILE__, cname));
- pa_proplist_sets(c->client->proplist, "simple-protocol.peer", pname);
- c->client->module = o->module;
+ pa_proplist_setf(client_data.proplist, PA_PROP_APPLICATION_NAME, "Simple client (%s)", pname);
+ pa_proplist_sets(client_data.proplist, "simple-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;
diff --git a/src/pulsecore/shared.c b/src/pulsecore/shared.c
index 4c1ad80a..d6e42dd8 100644
--- a/src/pulsecore/shared.c
+++ b/src/pulsecore/shared.c
@@ -115,7 +115,7 @@ void pa_shared_cleanup(pa_core *c) {
pa_strbuf *s = pa_strbuf_new();
pa_shared_dump(c, s);
- pa_log_debug(pa_strbuf_tostring(s));
+ pa_log_debug("%s", pa_strbuf_tostring(s));
pa_strbuf_free(s);
pa_assert(pa_hashmap_isempty(c->shared));
}
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 33490cc6..185350fa 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -265,6 +265,7 @@ pa_sink_input* pa_sink_input_new(
i->thread_info.requested_sink_latency = (pa_usec_t) -1;
i->thread_info.rewrite_nbytes = 0;
i->thread_info.rewrite_flush = FALSE;
+ i->thread_info.dont_rewind_render = FALSE;
i->thread_info.underrun_for = (uint64_t) -1;
i->thread_info.playing_for = 0;
i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
@@ -282,6 +283,9 @@ pa_sink_input* pa_sink_input_new(
pa_assert_se(pa_idxset_put(core->sink_inputs, pa_sink_input_ref(i), &i->index) == 0);
pa_assert_se(pa_idxset_put(i->sink->inputs, i, NULL) == 0);
+ if (i->client)
+ pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0);
+
pa_log_info("Created input %u \"%s\" on %s with sample spec %s and channel map %s",
i->index,
pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)),
@@ -371,6 +375,9 @@ void pa_sink_input_unlink(pa_sink_input *i) {
if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
pa_sink_input_unref(i);
+ if (i->client)
+ pa_idxset_remove_by_data(i->client->sink_inputs, i, NULL);
+
while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
pa_assert(o != p);
pa_source_output_kill(o);
@@ -658,7 +665,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam
lbq = pa_memblockq_get_length(i->thread_info.render_memblockq);
- if (nbytes > 0) {
+ if (nbytes > 0 && !i->thread_info.dont_rewind_render) {
pa_log_debug("Have to rewind %lu bytes on render memblockq.", (unsigned long) nbytes);
pa_memblockq_rewind(i->thread_info.render_memblockq, nbytes);
}
@@ -714,6 +721,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam
i->thread_info.rewrite_nbytes = 0;
i->thread_info.rewrite_flush = FALSE;
+ i->thread_info.dont_rewind_render = FALSE;
}
/* Called from thread context */
@@ -1091,7 +1099,7 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state
/* This will tell the implementing sink input driver to rewind
* so that the unplayed already mixed data is not lost */
- pa_sink_input_request_rewind(i, 0, TRUE, TRUE);
+ pa_sink_input_request_rewind(i, 0, TRUE, TRUE, FALSE);
} else if (uncorking) {
@@ -1102,7 +1110,7 @@ void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state
/* OK, we're being uncorked. Make sure we're not rewound when
* the hw buffer is remixed and request a remix. */
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
}
@@ -1115,12 +1123,12 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
case PA_SINK_INPUT_MESSAGE_SET_VOLUME:
i->thread_info.volume = *((pa_cvolume*) userdata);
- pa_sink_input_request_rewind(i, 0, TRUE, FALSE);
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
return 0;
case PA_SINK_INPUT_MESSAGE_SET_MUTE:
i->thread_info.muted = PA_PTR_TO_UINT(userdata);
- pa_sink_input_request_rewind(i, 0, TRUE, FALSE);
+ pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
return 0;
case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
@@ -1195,7 +1203,7 @@ pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) {
}
/* Called from IO context */
-void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush) {
+void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sample spec */, pa_bool_t rewrite, pa_bool_t flush, pa_bool_t dont_rewind_render) {
size_t lbq;
/* If 'rewrite' is TRUE the sink is rewound as far as requested
@@ -1206,7 +1214,9 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam
* If 'rewrite' is FALSE the sink is rewound as far as requested
* and possible and the already rendered data is dropped so that
* in the next iteration we read new data from the
- * implementor. This implies 'flush' is TRUE. */
+ * implementor. This implies 'flush' is TRUE. If
+ * dont_rewind_render is TRUE then the render memblockq is not
+ * rewound. */
pa_sink_input_assert_ref(i);
@@ -1219,6 +1229,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam
return;
pa_assert(rewrite || flush);
+ pa_assert(!dont_rewind_render || !rewrite);
/* Calculate how much we can rewind locally without having to
* touch the sink */
@@ -1253,6 +1264,10 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam
i->thread_info.rewrite_flush ||
(flush && i->thread_info.rewrite_nbytes != 0);
+ i->thread_info.dont_rewind_render =
+ i->thread_info.dont_rewind_render ||
+ dont_rewind_render;
+
if (nbytes != (size_t) -1) {
/* Transform to sink domain */
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 8cfe32bc..3d2a8c0d 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -179,8 +179,9 @@ struct pa_sink_input {
/* We maintain a history of resampled audio data here. */
pa_memblockq *render_memblockq;
+ /* 0: rewrite nothing, (size_t) -1: rewrite everything, otherwise how many bytes to rewrite */
size_t rewrite_nbytes;
- pa_bool_t rewrite_flush;
+ pa_bool_t rewrite_flush, dont_rewind_render;
uint64_t underrun_for, playing_for;
pa_sink_input *sync_prev, *sync_next;
@@ -277,7 +278,7 @@ fully -- or at all. If the request for a rewrite was successful, the
sink driver will call ->rewind() and pass the number of bytes that
could be rewound in the HW device. This functionality is required for
implementing the "zero latency" write-through functionality. */
-void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, pa_bool_t rewrite, pa_bool_t flush);
+void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes, pa_bool_t rewrite, pa_bool_t flush, pa_bool_t dont_rewind_render);
void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 809e8273..d1d68cdd 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -183,6 +183,7 @@ pa_sink* pa_sink_new(
s->proplist = pa_proplist_copy(data->proplist);
s->driver = pa_xstrdup(data->driver);
s->module = data->module;
+ s->card = data->card;
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
@@ -225,6 +226,9 @@ pa_sink* pa_sink_new(
pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
+ if (s->card)
+ pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
+
pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s",
s->index,
s->name,
@@ -237,6 +241,7 @@ pa_sink* pa_sink_new(
source_data.name = pa_sprintf_malloc("%s.monitor", name);
source_data.driver = data->driver;
source_data.module = data->module;
+ source_data.card = data->card;
dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
@@ -360,6 +365,9 @@ void pa_sink_unlink(pa_sink* s) {
pa_namereg_unregister(s->core, s->name);
pa_idxset_remove_by_data(s->core->sinks, s, NULL);
+ if (s->card)
+ pa_idxset_remove_by_data(s->card->sinks, s, NULL);
+
while ((i = pa_idxset_first(s->inputs, NULL))) {
pa_assert(i != j);
pa_sink_input_kill(i);
@@ -644,7 +652,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
pa_assert(length > 0);
- n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, &length, info, MAX_MIX_CHANNELS) : 0;
+ n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
if (n == 0) {
@@ -687,8 +695,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
result->index = 0;
}
- if (s->thread_info.state == PA_SINK_RUNNING)
- inputs_drop(s, info, n, result);
+ inputs_drop(s, info, n, result);
pa_sink_unref(s);
}
@@ -718,7 +725,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
pa_assert(length > 0);
- n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, &length, info, MAX_MIX_CHANNELS) : 0;
+ n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
if (n == 0) {
if (target->length > length)
@@ -767,8 +774,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
pa_memblock_release(target->memblock);
}
- if (s->thread_info.state == PA_SINK_RUNNING)
- inputs_drop(s, info, n, target);
+ inputs_drop(s, info, n, target);
pa_sink_unref(s);
}
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index fb5e1e89..507c1603 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -38,6 +38,7 @@ typedef struct pa_sink pa_sink;
#include <pulsecore/refcnt.h>
#include <pulsecore/msgobject.h>
#include <pulsecore/rtpoll.h>
+#include <pulsecore/card.h>
#define PA_MAX_INPUTS_PER_SINK 32
@@ -70,6 +71,7 @@ struct pa_sink {
pa_proplist *proplist;
pa_module *module; /* may be NULL */
+ pa_card *card; /* may be NULL */
pa_sample_spec sample_spec;
pa_channel_map channel_map;
@@ -187,6 +189,7 @@ typedef struct pa_sink_new_data {
const char *driver;
pa_module *module;
+ pa_card *card;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c
index c30c16eb..b78afca8 100644
--- a/src/pulsecore/sound-file-stream.c
+++ b/src/pulsecore/sound-file-stream.c
@@ -133,7 +133,7 @@ static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t s
* we are heard right-away. */
if (PA_SINK_INPUT_IS_LINKED(state) &&
i->thread_info.state == PA_SINK_INPUT_INIT)
- pa_sink_input_request_rewind(i, 0, FALSE, TRUE);
+ pa_sink_input_request_rewind(i, 0, FALSE, TRUE, TRUE);
}
/* Called from IO thread context */
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index e3d0d8b2..b1c65d1c 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -223,6 +223,9 @@ pa_source_output* pa_source_output_new(
pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
+ if (o->client)
+ pa_assert_se(pa_idxset_put(o->client->source_outputs, o, NULL) >= 0);
+
if (o->direct_on_input)
pa_assert_se(pa_idxset_put(o->direct_on_input->direct_outputs, o, NULL) == 0);
@@ -290,6 +293,9 @@ void pa_source_output_unlink(pa_source_output*o) {
if (pa_idxset_remove_by_data(o->source->outputs, o, NULL))
pa_source_output_unref(o);
+ if (o->client)
+ pa_idxset_remove_by_data(o->client->source_outputs, o, NULL);
+
update_n_corked(o, PA_SOURCE_OUTPUT_UNLINKED);
o->state = PA_SOURCE_OUTPUT_UNLINKED;
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index e65c5ce7..676a6b40 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -174,6 +174,7 @@ pa_source* pa_source_new(
s->proplist = pa_proplist_copy(data->proplist);
s->driver = pa_xstrdup(data->driver);
s->module = data->module;
+ s->card = data->card;
s->sample_spec = data->sample_spec;
s->channel_map = data->channel_map;
@@ -212,6 +213,9 @@ pa_source* pa_source_new(
pa_assert_se(pa_idxset_put(core->sources, s, &s->index) >= 0);
+ if (s->card)
+ pa_assert_se(pa_idxset_put(s->card->sources, s, NULL) >= 0);
+
pa_log_info("Created source %u \"%s\" with sample spec %s and channel map %s",
s->index,
s->name,
@@ -314,6 +318,9 @@ void pa_source_unlink(pa_source *s) {
pa_namereg_unregister(s->core, s->name);
pa_idxset_remove_by_data(s->core->sources, s, NULL);
+ if (s->card)
+ pa_idxset_remove_by_data(s->card->sinks, s, NULL);
+
while ((o = pa_idxset_first(s->outputs, NULL))) {
pa_assert(o != j);
pa_source_output_kill(o);
@@ -429,9 +436,6 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
pa_assert(PA_SOURCE_IS_OPENED(s->thread_info.state));
pa_assert(chunk);
- if (s->thread_info.state != PA_SOURCE_RUNNING)
- return;
-
if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
pa_memchunk vchunk = *chunk;
@@ -470,9 +474,6 @@ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *
pa_assert(o->thread_info.direct_on_input);
pa_assert(chunk);
- if (s->thread_info.state != PA_SOURCE_RUNNING)
- return;
-
if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&s->thread_info.soft_volume)) {
pa_memchunk vchunk = *chunk;
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index fd8c4bd6..48240996 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -41,6 +41,7 @@ typedef struct pa_source pa_source;
#include <pulsecore/msgobject.h>
#include <pulsecore/rtpoll.h>
#include <pulsecore/source-output.h>
+#include <pulsecore/card.h>
#define PA_MAX_OUTPUTS_PER_SOURCE 32
@@ -73,6 +74,7 @@ struct pa_source {
pa_proplist *proplist;
pa_module *module; /* may be NULL */
+ pa_card *card; /* may be NULL */
pa_sample_spec sample_spec;
pa_channel_map channel_map;
@@ -174,6 +176,7 @@ typedef struct pa_source_new_data {
const char *driver;
pa_module *module;
+ pa_card *card;
pa_sample_spec sample_spec;
pa_channel_map channel_map;