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,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
#endif
#include <stdlib.h>
-#include <limits.h>
#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <pulse/xmalloc.h>
#include <pulse/timeval.h>
pa_client *client;
pa_memblockq *input_memblockq, *output_memblockq;
- pa_bool_t dead;
+ bool dead;
struct {
pa_memblock *current_memblock;
size_t memblock_index;
pa_atomic_t missing;
- pa_bool_t underrun;
+ bool underrun;
} playback;
} connection;
-PA_DECLARE_CLASS(connection);
+PA_DEFINE_PRIVATE_CLASS(connection, pa_msgobject);
#define CONNECTION(o) (connection_cast(o))
-static PA_DEFINE_CHECK_TYPE(connection, pa_msgobject);
struct pa_simple_protocol {
PA_REFCNT_DECLARE;
enum {
CONNECTION_MESSAGE_REQUEST_DATA, /* data requested from sink input from the main loop */
CONNECTION_MESSAGE_POST_DATA, /* data from source output to main loop */
- CONNECTION_MESSAGE_UNLINK_CONNECTION /* Please drop a aconnection now */
+ CONNECTION_MESSAGE_UNLINK_CONNECTION /* Please drop the connection now */
};
#define PLAYBACK_BUFFER_SECONDS (.5)
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);
}
ssize_t r;
size_t l;
void *p;
- size_t space;
+ size_t space = 0;
connection_assert_ref(c);
}
if (!c->playback.current_memblock) {
- pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, 0));
+ pa_assert_se(c->playback.current_memblock = pa_memblock_new(c->protocol->core->mempool, (size_t) -1));
c->playback.memblock_index = 0;
space = pa_memblock_get_length(c->playback.current_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;
+ return 1;
}
static void do_work(connection *c) {
if (!c->sink_input && pa_iochannel_is_hungup(c->io))
goto fail;
- if (pa_iochannel_is_writable(c->io))
- if (do_write(c) < 0)
+ while (pa_iochannel_is_writable(c->io)) {
+ int r = do_write(c);
+ if (r < 0)
goto fail;
+ if (r == 0)
+ break;
+ }
return;
if (c->sink_input) {
/* If there is a sink input, we first drain what we already have read before shutting down the connection */
- c->dead = TRUE;
+ c->dead = true;
pa_iochannel_free(c->io);
c->io = NULL;
connection *c = CONNECTION(o);
connection_assert_ref(c);
+ if (!c->protocol)
+ return -1;
+
switch (code) {
case CONNECTION_MESSAGE_REQUEST_DATA:
do_work(c);
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)); */
if (pa_memblockq_peek(c->input_memblockq, chunk) < 0) {
- c->playback.underrun = TRUE;
+ c->playback.underrun = true;
if (c->dead && pa_sink_input_safe_to_remove(i))
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(c), CONNECTION_MESSAGE_UNLINK_CONNECTION, NULL, 0, NULL, NULL);
chunk->length = PA_MIN(length, chunk->length);
- c->playback.underrun = FALSE;
+ c->playback.underrun = false;
pa_memblockq_drop(c->input_memblockq, chunk->length);
m = pa_memblockq_pop_missing(c->input_memblockq);
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);
c->parent.parent.free = connection_free;
c->parent.process_msg = connection_process_msg;
c->io = io;
+ pa_iochannel_set_callback(c->io, io_callback, c);
+
c->sink_input = NULL;
c->source_output = NULL;
c->input_memblockq = c->output_memblockq = NULL;
c->options = pa_simple_options_ref(o);
c->playback.current_memblock = NULL;
c->playback.memblock_index = 0;
- c->dead = FALSE;
- c->playback.underrun = TRUE;
+ c->dead = false;
+ 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;
if (o->playback) {
pa_sink_input_new_data data;
+ pa_memchunk silence;
size_t l;
pa_sink *sink;
- if (!(sink = pa_namereg_get(c->protocol->core, o->default_sink, PA_NAMEREG_SINK, TRUE))) {
+ if (!(sink = pa_namereg_get(c->protocol->core, o->default_sink, PA_NAMEREG_SINK))) {
pa_log("Failed to get sink.");
goto fail;
}
data.driver = __FILE__;
data.module = o->module;
data.client = c->client;
- data.sink = sink;
+ pa_sink_input_new_data_set_sink(&data, sink, false);
pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
pa_sink_input_new_data_set_sample_spec(&data, &o->sample_spec);
- c->sink_input = pa_sink_input_new(p->core, &data, 0);
+ pa_sink_input_new(&c->sink_input, p->core, &data);
pa_sink_input_new_data_done(&data);
if (!c->sink_input) {
pa_sink_input_set_requested_latency(c->sink_input, DEFAULT_SINK_LATENCY);
l = (size_t) ((double) pa_bytes_per_second(&o->sample_spec)*PLAYBACK_BUFFER_SECONDS);
+ pa_sink_input_get_silence(c->sink_input, &silence);
c->input_memblockq = pa_memblockq_new(
+ "simple protocol connection input_memblockq",
0,
l,
l,
- pa_frame_size(&o->sample_spec),
+ &o->sample_spec,
(size_t) -1,
l/PLAYBACK_BUFFER_FRAGMENTS,
0,
- NULL);
+ &silence);
+ pa_memblock_unref(silence.memblock);
+
pa_iochannel_socket_set_rcvbuf(io, l);
- pa_atomic_store(&c->playback.missing, (int) pa_memblockq_missing(c->input_memblockq));
+ pa_atomic_store(&c->playback.missing, (int) pa_memblockq_pop_missing(c->input_memblockq));
pa_sink_input_put(c->sink_input);
}
size_t l;
pa_source *source;
- if (!(source = pa_namereg_get(c->protocol->core, o->default_source, PA_NAMEREG_SOURCE, TRUE))) {
+ if (!(source = pa_namereg_get(c->protocol->core, o->default_source, PA_NAMEREG_SOURCE))) {
pa_log("Failed to get source.");
goto fail;
}
data.driver = __FILE__;
data.module = o->module;
data.client = c->client;
- data.source = source;
+ pa_source_output_new_data_set_source(&data, source, false);
pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist);
pa_source_output_new_data_set_sample_spec(&data, &o->sample_spec);
- c->source_output = pa_source_output_new(p->core, &data, 0);
+ pa_source_output_new(&c->source_output, p->core, &data);
pa_source_output_new_data_done(&data);
if (!c->source_output) {
l = (size_t) (pa_bytes_per_second(&o->sample_spec)*RECORD_BUFFER_SECONDS);
c->output_memblockq = pa_memblockq_new(
+ "simple protocol connection output_memblockq",
0,
l,
0,
- pa_frame_size(&o->sample_spec),
+ &o->sample_spec,
1,
0,
0,
pa_source_output_put(c->source_output);
}
- pa_iochannel_set_callback(c->io, io_callback, c);
pa_idxset_put(p->connections, c, NULL);
return;
fail:
- if (c)
- connection_unlink(c);
+ connection_unlink(c);
}
void pa_simple_protocol_disconnect(pa_simple_protocol *p, pa_module *m) {
while ((c = pa_idxset_first(p->connections, NULL)))
connection_unlink(c);
- pa_idxset_free(p->connections, NULL, NULL);
+ pa_idxset_free(p->connections, NULL);
pa_assert_se(pa_shared_remove(p->core, "simple-protocol") >= 0);
o = pa_xnew0(pa_simple_options, 1);
PA_REFCNT_INIT(o);
+ o->record = false;
+ o->playback = true;
+
return o;
}
}
int pa_simple_options_parse(pa_simple_options *o, pa_core *c, pa_modargs *ma) {
- pa_bool_t enabled;
+ bool enabled;
pa_assert(o);
pa_assert(PA_REFCNT_VALUE(o) >= 1);
pa_xfree(o->default_sink);
o->default_sink = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
- enabled = FALSE;
+ enabled = o->record;
if (pa_modargs_get_value_boolean(ma, "record", &enabled) < 0) {
pa_log("record= expects a boolean argument.");
return -1;
}
o->record = enabled;
- enabled = TRUE;
+ enabled = o->playback;
if (pa_modargs_get_value_boolean(ma, "playback", &enabled) < 0) {
pa_log("playback= expects a boolean argument.");
return -1;