mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-03 09:01:50 -05:00
cleanup
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@18 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
78f386ad45
commit
b24546bede
19 changed files with 261 additions and 277 deletions
|
|
@ -26,7 +26,7 @@ pkglib_LTLIBRARIES=libprotocol-simple.la module-simple-protocol-tcp.la \
|
||||||
|
|
||||||
polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \
|
polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \
|
||||||
memblock.c sample.c memblockq.c client.c \
|
memblock.c sample.c memblockq.c client.c \
|
||||||
core.c main.c outputstream.c inputstream.c source.c sink.c \
|
core.c main.c sourceoutput.c sinkinput.c source.c sink.c \
|
||||||
module.c
|
module.c
|
||||||
polypaudio_INCLUDES = $(INCLTDL)
|
polypaudio_INCLUDES = $(INCLTDL)
|
||||||
polypaudio_LDADD = $(LIBLTDL)
|
polypaudio_LDADD = $(LIBLTDL)
|
||||||
|
|
|
||||||
16
src/client.c
16
src/client.c
|
|
@ -12,11 +12,12 @@ struct client *client_new(struct core *core, const char *protocol_name, char *na
|
||||||
|
|
||||||
c = malloc(sizeof(struct client));
|
c = malloc(sizeof(struct client));
|
||||||
assert(c);
|
assert(c);
|
||||||
c->protocol_name = protocol_name;
|
|
||||||
c->name = name ? strdup(name) : NULL;
|
c->name = name ? strdup(name) : NULL;
|
||||||
c->kill = NULL;
|
|
||||||
c->kill_userdata = NULL;
|
|
||||||
c->core = core;
|
c->core = core;
|
||||||
|
c->protocol_name = protocol_name;
|
||||||
|
|
||||||
|
c->kill = NULL;
|
||||||
|
c->userdata = NULL;
|
||||||
|
|
||||||
r = idxset_put(core->clients, c, &c->index);
|
r = idxset_put(core->clients, c, &c->index);
|
||||||
assert(c->index != IDXSET_INVALID && r >= 0);
|
assert(c->index != IDXSET_INVALID && r >= 0);
|
||||||
|
|
@ -35,14 +36,9 @@ void client_free(struct client *c) {
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_set_kill_callback(struct client *c, void (*kill)(struct client *c, void *userdata), void *userdata) {
|
|
||||||
assert(c && kill);
|
|
||||||
c->kill = kill;
|
|
||||||
c->kill_userdata = userdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
void client_kill(struct client *c) {
|
void client_kill(struct client *c) {
|
||||||
assert(c);
|
assert(c);
|
||||||
c->kill(c, c->kill_userdata);
|
if (c->kill)
|
||||||
|
c->kill(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
src/client.h
13
src/client.h
|
|
@ -4,15 +4,15 @@
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
struct client {
|
struct client {
|
||||||
char *name;
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
|
||||||
|
char *name;
|
||||||
|
struct core *core;
|
||||||
const char *protocol_name;
|
const char *protocol_name;
|
||||||
|
|
||||||
void *kill_userdata;
|
void (*kill)(struct client *c);
|
||||||
void (*kill)(struct client *c, void *userdata);
|
|
||||||
|
|
||||||
struct core *core;
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct client *client_new(struct core *c, const char *protocol_name, char *name);
|
struct client *client_new(struct core *c, const char *protocol_name, char *name);
|
||||||
|
|
@ -20,11 +20,6 @@ struct client *client_new(struct core *c, const char *protocol_name, char *name)
|
||||||
/* This function should be called only by the code that created the client */
|
/* This function should be called only by the code that created the client */
|
||||||
void client_free(struct client *c);
|
void client_free(struct client *c);
|
||||||
|
|
||||||
/* The registrant of the client should call this function to set a
|
|
||||||
* callback function which is called when destruction of the client is
|
|
||||||
* requested */
|
|
||||||
void client_set_kill_callback(struct client *c, void (*kill)(struct client *c, void *userdata), void *userdata);
|
|
||||||
|
|
||||||
/* Code that didn't create the client should call this function to
|
/* Code that didn't create the client should call this function to
|
||||||
* request destruction of the client */
|
* request destruction of the client */
|
||||||
void client_kill(struct client *c);
|
void client_kill(struct client *c);
|
||||||
|
|
|
||||||
12
src/core.c
12
src/core.c
|
|
@ -16,8 +16,8 @@ struct core* core_new(struct mainloop *m) {
|
||||||
c->clients = idxset_new(NULL, NULL);
|
c->clients = idxset_new(NULL, NULL);
|
||||||
c->sinks = idxset_new(NULL, NULL);
|
c->sinks = idxset_new(NULL, NULL);
|
||||||
c->sources = idxset_new(NULL, NULL);
|
c->sources = idxset_new(NULL, NULL);
|
||||||
c->output_streams = idxset_new(NULL, NULL);
|
c->source_outputs = idxset_new(NULL, NULL);
|
||||||
c->input_streams = idxset_new(NULL, NULL);
|
c->sink_inputs = idxset_new(NULL, NULL);
|
||||||
|
|
||||||
c->default_source_index = c->default_sink_index = IDXSET_INVALID;
|
c->default_source_index = c->default_sink_index = IDXSET_INVALID;
|
||||||
|
|
||||||
|
|
@ -41,11 +41,11 @@ void core_free(struct core *c) {
|
||||||
assert(idxset_isempty(c->sources));
|
assert(idxset_isempty(c->sources));
|
||||||
idxset_free(c->sources, NULL, NULL);
|
idxset_free(c->sources, NULL, NULL);
|
||||||
|
|
||||||
assert(idxset_isempty(c->output_streams));
|
assert(idxset_isempty(c->source_outputs));
|
||||||
idxset_free(c->output_streams, NULL, NULL);
|
idxset_free(c->source_outputs, NULL, NULL);
|
||||||
|
|
||||||
assert(idxset_isempty(c->input_streams));
|
assert(idxset_isempty(c->sink_inputs));
|
||||||
idxset_free(c->input_streams, NULL, NULL);
|
idxset_free(c->sink_inputs, NULL, NULL);
|
||||||
|
|
||||||
free(c);
|
free(c);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
struct core {
|
struct core {
|
||||||
struct mainloop *mainloop;
|
struct mainloop *mainloop;
|
||||||
|
|
||||||
struct idxset *clients, *sinks, *sources, *output_streams, *input_streams, *modules;
|
struct idxset *clients, *sinks, *sources, *sink_inputs, *source_outputs, *modules;
|
||||||
|
|
||||||
uint32_t default_source_index, default_sink_index;
|
uint32_t default_source_index, default_sink_index;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
21
src/idxset.c
21
src/idxset.c
|
|
@ -291,9 +291,7 @@ void* idxset_rrobin(struct idxset *s, uint32_t *index) {
|
||||||
if (!e)
|
if (!e)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (index)
|
*index = e->index;
|
||||||
*index = e->index;
|
|
||||||
|
|
||||||
return e->data;
|
return e->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -308,6 +306,22 @@ void* idxset_first(struct idxset *s, uint32_t *index) {
|
||||||
return s->iterate_list_head->data;
|
return s->iterate_list_head->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *idxset_next(struct idxset *s, uint32_t *index) {
|
||||||
|
struct idxset_entry **a, *e = NULL;
|
||||||
|
assert(s && index);
|
||||||
|
|
||||||
|
if ((a = array_index(s, *index)) && *a)
|
||||||
|
e = (*a)->iterate_next;
|
||||||
|
|
||||||
|
if (e) {
|
||||||
|
*index = e->index;
|
||||||
|
return e->data;
|
||||||
|
} else {
|
||||||
|
*index = IDXSET_INVALID;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) {
|
int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata) {
|
||||||
struct idxset_entry *e;
|
struct idxset_entry *e;
|
||||||
|
|
@ -341,3 +355,4 @@ int idxset_isempty(struct idxset *s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
return s->n_entries == 0;
|
return s->n_entries == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,12 @@ void* idxset_rrobin(struct idxset *s, uint32_t *index);
|
||||||
|
|
||||||
/* Return the oldest entry in the idxset */
|
/* Return the oldest entry in the idxset */
|
||||||
void* idxset_first(struct idxset *s, uint32_t *index);
|
void* idxset_first(struct idxset *s, uint32_t *index);
|
||||||
|
void *idxset_next(struct idxset *s, uint32_t *index);
|
||||||
|
|
||||||
int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata);
|
int idxset_foreach(struct idxset*s, int (*func)(void *p, uint32_t index, int *del, void*userdata), void *userdata);
|
||||||
|
|
||||||
unsigned idxset_ncontents(struct idxset*s);
|
unsigned idxset_ncontents(struct idxset*s);
|
||||||
int idxset_isempty(struct idxset *s);
|
int idxset_isempty(struct idxset *s);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@ static void do_write(struct userdata *u) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_callback(struct sink*s, void *userdata) {
|
static void notify_cb(struct sink*s) {
|
||||||
struct userdata *u = userdata;
|
struct userdata *u = s->userdata;
|
||||||
assert(u);
|
assert(s && u);
|
||||||
|
|
||||||
if (iochannel_is_writable(u->io))
|
if (iochannel_is_writable(u->io))
|
||||||
mainloop_source_enable(u->mainloop_source, 1);
|
mainloop_source_enable(u->mainloop_source, 1);
|
||||||
|
|
@ -77,7 +77,7 @@ int module_init(struct core *c, struct module*m) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
char *p;
|
char *p;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
const static struct sample_spec ss = {
|
static const struct sample_spec ss = {
|
||||||
.format = SAMPLE_S16NE,
|
.format = SAMPLE_S16NE,
|
||||||
.rate = 44100,
|
.rate = 44100,
|
||||||
.channels = 2,
|
.channels = 2,
|
||||||
|
|
@ -110,7 +110,8 @@ int module_init(struct core *c, struct module*m) {
|
||||||
u->core = c;
|
u->core = c;
|
||||||
u->sink = sink_new(c, "fifo", &ss);
|
u->sink = sink_new(c, "fifo", &ss);
|
||||||
assert(u->sink);
|
assert(u->sink);
|
||||||
sink_set_notify_callback(u->sink, notify_callback, u);
|
u->sink->notify = notify_cb;
|
||||||
|
u->sink->userdata = u;
|
||||||
|
|
||||||
u->io = iochannel_new(c->mainloop, -1, fd);
|
u->io = iochannel_new(c->mainloop, -1, fd);
|
||||||
assert(u->io);
|
assert(u->io);
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,18 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "inputstream.h"
|
#include "sinkinput.h"
|
||||||
#include "outputstream.h"
|
#include "sourceoutput.h"
|
||||||
#include "protocol-simple.h"
|
#include "protocol-simple.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
|
||||||
struct connection {
|
struct connection {
|
||||||
struct protocol_simple *protocol;
|
struct protocol_simple *protocol;
|
||||||
struct iochannel *io;
|
struct iochannel *io;
|
||||||
struct input_stream *istream;
|
struct sink_input *sink_input;
|
||||||
struct output_stream *ostream;
|
struct source_output *source_output;
|
||||||
struct client *client;
|
struct client *client;
|
||||||
|
struct memblockq *input_memblockq, *output_memblockq;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct protocol_simple {
|
struct protocol_simple {
|
||||||
|
|
@ -31,14 +32,18 @@ static void free_connection(void *data, void *userdata) {
|
||||||
struct connection *c = data;
|
struct connection *c = data;
|
||||||
assert(data);
|
assert(data);
|
||||||
|
|
||||||
if (c->istream)
|
if (c->sink_input)
|
||||||
input_stream_free(c->istream);
|
sink_input_free(c->sink_input);
|
||||||
if (c->ostream)
|
if (c->source_output)
|
||||||
output_stream_free(c->ostream);
|
source_output_free(c->source_output);
|
||||||
|
if (c->client)
|
||||||
client_free(c->client);
|
client_free(c->client);
|
||||||
|
if (c->io)
|
||||||
iochannel_free(c->io);
|
iochannel_free(c->io);
|
||||||
|
if (c->input_memblockq)
|
||||||
|
memblockq_free(c->input_memblockq);
|
||||||
|
if (c->output_memblockq)
|
||||||
|
memblockq_free(c->output_memblockq);
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,24 +53,6 @@ static void destroy_connection(struct connection *c) {
|
||||||
free_connection(c, NULL);
|
free_connection(c, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void istream_kill_cb(struct input_stream *i, void *userdata) {
|
|
||||||
struct connection *c = userdata;
|
|
||||||
assert(i && c);
|
|
||||||
destroy_connection(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ostream_kill_cb(struct output_stream *o, void *userdata) {
|
|
||||||
struct connection *c = userdata;
|
|
||||||
assert(o && c);
|
|
||||||
destroy_connection(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void client_kill_cb(struct client *client, void*userdata) {
|
|
||||||
struct connection *c= userdata;
|
|
||||||
assert(client && c);
|
|
||||||
destroy_connection(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_read(struct connection *c) {
|
static int do_read(struct connection *c) {
|
||||||
struct memchunk chunk;
|
struct memchunk chunk;
|
||||||
ssize_t r;
|
ssize_t r;
|
||||||
|
|
@ -73,7 +60,7 @@ static int do_read(struct connection *c) {
|
||||||
if (!iochannel_is_readable(c->io))
|
if (!iochannel_is_readable(c->io))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!c->istream || !memblockq_is_writable(c->istream->memblockq, BUFSIZE))
|
if (!c->sink_input || !memblockq_is_writable(c->input_memblockq, BUFSIZE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
chunk.memblock = memblock_new(BUFSIZE);
|
chunk.memblock = memblock_new(BUFSIZE);
|
||||||
|
|
@ -91,9 +78,10 @@ static int do_read(struct connection *c) {
|
||||||
chunk.length = r;
|
chunk.length = r;
|
||||||
chunk.index = 0;
|
chunk.index = 0;
|
||||||
|
|
||||||
memblockq_push(c->istream->memblockq, &chunk, 0);
|
assert(c->input_memblockq);
|
||||||
input_stream_notify_sink(c->istream);
|
memblockq_push(c->input_memblockq, &chunk, 0);
|
||||||
memblock_unref(chunk.memblock);
|
memblock_unref(chunk.memblock);
|
||||||
|
sink_notify(c->sink_input->sink);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,10 +92,11 @@ static int do_write(struct connection *c) {
|
||||||
if (!iochannel_is_writable(c->io))
|
if (!iochannel_is_writable(c->io))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!c->ostream)
|
if (!c->source_output)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memblockq_peek(c->ostream->memblockq, &chunk);
|
assert(c->output_memblockq);
|
||||||
|
memblockq_peek(c->output_memblockq, &chunk);
|
||||||
assert(chunk.memblock && chunk.length);
|
assert(chunk.memblock && chunk.length);
|
||||||
|
|
||||||
if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) {
|
if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) {
|
||||||
|
|
@ -116,11 +105,63 @@ static int do_write(struct connection *c) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
memblockq_drop(c->ostream->memblockq, r);
|
memblockq_drop(c->output_memblockq, r);
|
||||||
memblock_unref(chunk.memblock);
|
memblock_unref(chunk.memblock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*** sink_input callbacks ***/
|
||||||
|
|
||||||
|
static int sink_input_peek_cb(struct sink_input *i, struct memchunk *chunk, uint8_t *volume) {
|
||||||
|
struct connection*c = i->userdata;
|
||||||
|
assert(i && c && chunk && volume);
|
||||||
|
|
||||||
|
if (memblockq_peek(c->input_memblockq, chunk) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*volume = 0xFF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sink_input_drop_cb(struct sink_input *i, size_t length) {
|
||||||
|
struct connection*c = i->userdata;
|
||||||
|
assert(i && c && length);
|
||||||
|
|
||||||
|
memblockq_drop(c->input_memblockq, length);
|
||||||
|
|
||||||
|
if (do_read(c) < 0)
|
||||||
|
destroy_connection(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sink_input_kill_cb(struct sink_input *i) {
|
||||||
|
assert(i && i->userdata);
|
||||||
|
destroy_connection((struct connection *) i->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** source_output callbacks ***/
|
||||||
|
|
||||||
|
static void source_output_push_cb(struct source_output *o, struct memchunk *chunk) {
|
||||||
|
struct connection *c = o->userdata;
|
||||||
|
assert(o && c && chunk);
|
||||||
|
|
||||||
|
memblockq_push(c->output_memblockq, chunk, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void source_output_kill_cb(struct source_output *o) {
|
||||||
|
assert(o && o->userdata);
|
||||||
|
destroy_connection((struct connection *) o->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*** client callbacks ***/
|
||||||
|
|
||||||
|
static void client_kill_cb(struct client *c) {
|
||||||
|
assert(c && c->userdata);
|
||||||
|
destroy_connection((struct connection *) c->userdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** iochannel callbacks ***/
|
||||||
|
|
||||||
static void io_callback(struct iochannel*io, void *userdata) {
|
static void io_callback(struct iochannel*io, void *userdata) {
|
||||||
struct connection *c = userdata;
|
struct connection *c = userdata;
|
||||||
assert(io && c && c->io == io);
|
assert(io && c && c->io == io);
|
||||||
|
|
@ -129,13 +170,7 @@ static void io_callback(struct iochannel*io, void *userdata) {
|
||||||
destroy_connection(c);
|
destroy_connection(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void istream_notify_cb(struct input_stream *i, void *userdata) {
|
/*** socket_server callbacks */
|
||||||
struct connection*c = userdata;
|
|
||||||
assert(i && c && c->istream == i);
|
|
||||||
|
|
||||||
if (do_read(c) < 0)
|
|
||||||
destroy_connection(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) {
|
static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) {
|
||||||
struct protocol_simple *p = userdata;
|
struct protocol_simple *p = userdata;
|
||||||
|
|
@ -145,39 +180,53 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us
|
||||||
c = malloc(sizeof(struct connection));
|
c = malloc(sizeof(struct connection));
|
||||||
assert(c);
|
assert(c);
|
||||||
c->io = io;
|
c->io = io;
|
||||||
c->istream = NULL;
|
c->sink_input = NULL;
|
||||||
c->ostream = NULL;
|
c->source_output = NULL;
|
||||||
|
c->input_memblockq = c->output_memblockq = NULL;
|
||||||
c->protocol = p;
|
c->protocol = p;
|
||||||
|
|
||||||
c->client = client_new(p->core, "SIMPLE", "Client");
|
c->client = client_new(p->core, "SIMPLE", "Client");
|
||||||
assert(c->client);
|
assert(c->client);
|
||||||
client_set_kill_callback(c->client, client_kill_cb, c);
|
c->client->kill = client_kill_cb;
|
||||||
|
c->client->userdata = c;
|
||||||
|
|
||||||
if (p->mode & PROTOCOL_SIMPLE_RECORD) {
|
if (p->mode & PROTOCOL_SIMPLE_RECORD) {
|
||||||
struct source *source;
|
struct source *source;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
if (!(source = core_get_default_source(p->core))) {
|
if (!(source = core_get_default_source(p->core))) {
|
||||||
fprintf(stderr, "Failed to get default source.\n");
|
fprintf(stderr, "Failed to get default source.\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->ostream = output_stream_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name);
|
c->source_output = source_output_new(source, &DEFAULT_SAMPLE_SPEC, c->client->name);
|
||||||
assert(c->ostream);
|
assert(c->source_output);
|
||||||
output_stream_set_kill_callback(c->ostream, ostream_kill_cb, c);
|
c->source_output->push = source_output_push_cb;
|
||||||
|
c->source_output->kill = source_output_kill_cb;
|
||||||
|
c->source_output->userdata = c;
|
||||||
|
|
||||||
|
l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC);
|
||||||
|
c->output_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) {
|
if (p->mode & PROTOCOL_SIMPLE_PLAYBACK) {
|
||||||
struct sink *sink;
|
struct sink *sink;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
if (!(sink = core_get_default_sink(p->core))) {
|
if (!(sink = core_get_default_sink(p->core))) {
|
||||||
fprintf(stderr, "Failed to get default sink.\n");
|
fprintf(stderr, "Failed to get default sink.\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
c->istream = input_stream_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name);
|
c->sink_input = sink_input_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name);
|
||||||
assert(c->istream);
|
assert(c->sink_input);
|
||||||
input_stream_set_kill_callback(c->istream, istream_kill_cb, c);
|
c->sink_input->peek = sink_input_peek_cb;
|
||||||
input_stream_set_notify_callback(c->istream, istream_notify_cb, c);
|
c->sink_input->drop = sink_input_drop_cb;
|
||||||
|
c->sink_input->kill = sink_input_kill_cb;
|
||||||
|
c->sink_input->userdata = c;
|
||||||
|
|
||||||
|
l = 5*bytes_per_second(&DEFAULT_SAMPLE_SPEC);
|
||||||
|
c->input_memblockq = memblockq_new(l, sample_size(&DEFAULT_SAMPLE_SPEC), l/2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -187,13 +236,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (c) {
|
if (c) {
|
||||||
if (c->client)
|
free_connection(c, NULL);
|
||||||
client_free(c->client);
|
|
||||||
if (c->istream)
|
|
||||||
input_stream_free(c->istream);
|
|
||||||
if (c->ostream)
|
|
||||||
output_stream_free(c->ostream);
|
|
||||||
|
|
||||||
iochannel_free(c->io);
|
iochannel_free(c->io);
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
15
src/sample.c
15
src/sample.c
|
|
@ -60,9 +60,9 @@ size_t bytes_per_second(struct sample_spec *spec) {
|
||||||
return spec->rate*sample_size(spec);
|
return spec->rate*sample_size(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec) {
|
size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec, uint8_t volume) {
|
||||||
unsigned c, d;
|
unsigned c, d;
|
||||||
assert(chunks && target && spec);
|
assert(channels && data && length && spec);
|
||||||
assert(spec->format == SAMPLE_S16NE);
|
assert(spec->format == SAMPLE_S16NE);
|
||||||
|
|
||||||
for (d = 0;; d += sizeof(int16_t)) {
|
for (d = 0;; d += sizeof(int16_t)) {
|
||||||
|
|
@ -81,7 +81,7 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si
|
||||||
if (volume == 0)
|
if (volume == 0)
|
||||||
v = 0;
|
v = 0;
|
||||||
else {
|
else {
|
||||||
v = *((int16_t*) (channels[c].chunk->memblock->data + channels[c].chunk->index + d));
|
v = *((int16_t*) (channels[c].chunk.memblock->data + channels[c].chunk.index + d));
|
||||||
|
|
||||||
if (volume != 0xFF)
|
if (volume != 0xFF)
|
||||||
v = v*volume/0xFF;
|
v = v*volume/0xFF;
|
||||||
|
|
@ -90,8 +90,15 @@ size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, si
|
||||||
sum += v;
|
sum += v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (volume == 0)
|
||||||
|
sum = 0;
|
||||||
|
else if (volume != 0xFF)
|
||||||
|
sum = sum*volume/0xFF;
|
||||||
|
|
||||||
if (sum < -0x8000) sum = -0x8000;
|
if (sum < -0x8000) sum = -0x8000;
|
||||||
if (sum > 0x7FFF) sum = 0x7FFF;
|
if (sum > 0x7FFF) sum = 0x7FFF;
|
||||||
*(data++) = sum;
|
|
||||||
|
*((int16_t*) data) = sum;
|
||||||
|
data += sizeof(int16_t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ struct mix_info {
|
||||||
void *userdata;
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec) {
|
size_t mix_chunks(struct mix_info channels[], unsigned nchannels, void *data, size_t length, struct sample_spec *spec, uint8_t volume);
|
||||||
|
|
||||||
size_t bytes_per_second(struct sample_spec *spec);
|
size_t bytes_per_second(struct sample_spec *spec);
|
||||||
size_t sample_size(struct sample_spec *spec);
|
size_t sample_size(struct sample_spec *spec);
|
||||||
|
|
|
||||||
47
src/sink.c
47
src/sink.c
|
|
@ -4,7 +4,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "sink.h"
|
#include "sink.h"
|
||||||
#include "inputstream.h"
|
#include "sinkinput.h"
|
||||||
|
|
||||||
|
#define MAX_MIX_CHANNELS 32
|
||||||
|
|
||||||
struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) {
|
struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec) {
|
||||||
struct sink *s;
|
struct sink *s;
|
||||||
|
|
@ -16,9 +18,6 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
s->name = name ? strdup(name) : NULL;
|
s->name = name ? strdup(name) : NULL;
|
||||||
r = idxset_put(core->sinks, s, &s->index);
|
|
||||||
assert(s->index != IDXSET_INVALID && r >= 0);
|
|
||||||
|
|
||||||
s->core = core;
|
s->core = core;
|
||||||
s->sample_spec = *spec;
|
s->sample_spec = *spec;
|
||||||
s->inputs = idxset_new(NULL, NULL);
|
s->inputs = idxset_new(NULL, NULL);
|
||||||
|
|
@ -34,7 +33,10 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s
|
||||||
s->volume = 0xFF;
|
s->volume = 0xFF;
|
||||||
|
|
||||||
s->notify = NULL;
|
s->notify = NULL;
|
||||||
s->notify_userdata = NULL;
|
s->userdata = NULL;
|
||||||
|
|
||||||
|
r = idxset_put(core->sinks, s, &s->index);
|
||||||
|
assert(s->index != IDXSET_INVALID && r >= 0);
|
||||||
|
|
||||||
fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name);
|
fprintf(stderr, "sink: created %u \"%s\".\n", s->index, s->name);
|
||||||
|
|
||||||
|
|
@ -46,15 +48,14 @@ void sink_free(struct sink *s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
while ((i = idxset_first(s->inputs, NULL))) {
|
while ((i = idxset_first(s->inputs, NULL))) {
|
||||||
assert(i != j && i->kill);
|
assert(i != j);
|
||||||
i->kill(i);
|
sink_input_kill(i);
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
idxset_free(s->inputs, NULL, NULL);
|
idxset_free(s->inputs, NULL, NULL);
|
||||||
|
|
||||||
idxset_remove_by_data(s->core->sinks, s, NULL);
|
|
||||||
source_free(s->monitor_source);
|
source_free(s->monitor_source);
|
||||||
|
idxset_remove_by_data(s->core->sinks, s, NULL);
|
||||||
|
|
||||||
fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name);
|
fprintf(stderr, "sink: freed %u \"%s\"\n", s->index, s->name);
|
||||||
|
|
||||||
|
|
@ -66,24 +67,17 @@ void sink_notify(struct sink*s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (s->notify)
|
if (s->notify)
|
||||||
s->notify(s, s->notify_userdata);
|
s->notify(s);
|
||||||
}
|
|
||||||
|
|
||||||
void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) {
|
|
||||||
assert(s && notify_callback);
|
|
||||||
|
|
||||||
s->notify = notify_callback;
|
|
||||||
s->notify_userdata = userdata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) {
|
static unsigned fill_mix_info(struct sink *s, struct mix_info *info, unsigned maxinfo) {
|
||||||
uint32_t index = IDXSET_ANY;
|
uint32_t index = IDXSET_INVALID;
|
||||||
struct sink_input *i;
|
struct sink_input *i;
|
||||||
unsigned n;
|
unsigned n = 0;
|
||||||
|
|
||||||
assert(s && info);
|
assert(s && info);
|
||||||
|
|
||||||
while (maxinfo > 0 && i = idxset_rrobin(s->inputs, &index)) {
|
for (i = idxset_first(s->inputs, &index); maxinfo > 0 && i; i = idxset_next(s->inputs, &index)) {
|
||||||
assert(i->peek);
|
assert(i->peek);
|
||||||
if (i->peek(i, &info->chunk, &info->volume) < 0)
|
if (i->peek(i, &info->chunk, &info->volume) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -125,7 +119,7 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) {
|
||||||
|
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
struct sink_info *i = info[0].userdata;
|
struct sink_info *i = info[0].userdata;
|
||||||
assert(i && b);
|
assert(i);
|
||||||
*result = info[0].chunk;
|
*result = info[0].chunk;
|
||||||
memblock_ref(result->memblock);
|
memblock_ref(result->memblock);
|
||||||
|
|
||||||
|
|
@ -137,7 +131,7 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) {
|
||||||
result->memblock = memblock_new(length);
|
result->memblock = memblock_new(length);
|
||||||
assert(result->memblock);
|
assert(result->memblock);
|
||||||
|
|
||||||
result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec);
|
result->length = l = mix_chunks(info, n, result->memblock->data, length, &s->sample_spec, s->volume);
|
||||||
result->index = 0;
|
result->index = 0;
|
||||||
|
|
||||||
assert(l);
|
assert(l);
|
||||||
|
|
@ -160,7 +154,7 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re
|
||||||
|
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
struct sink_info *i = info[0].userdata;
|
struct sink_info *i = info[0].userdata;
|
||||||
assert(i && b);
|
assert(i);
|
||||||
|
|
||||||
l = target->length;
|
l = target->length;
|
||||||
if (l > info[0].chunk.length)
|
if (l > info[0].chunk.length)
|
||||||
|
|
@ -170,15 +164,10 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re
|
||||||
memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l);
|
memcpy(target->data, info[0].chunk.memblock->data + info[0].chunk.index, l);
|
||||||
result->length = target->length = l;
|
result->length = target->length = l;
|
||||||
result->index = 0;
|
result->index = 0;
|
||||||
|
|
||||||
if (result->length > length)
|
|
||||||
result->length = length;
|
|
||||||
|
|
||||||
l = result->length;
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
result->memblock = target;
|
result->memblock = target;
|
||||||
result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec);
|
result->length = l = mix_chunks(info, n, target->data, target->length, &s->sample_spec, s->volume);
|
||||||
result->index = 0;
|
result->index = 0;
|
||||||
assert(l);
|
assert(l);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/sink.h
18
src/sink.h
|
|
@ -10,21 +10,10 @@ struct sink;
|
||||||
#include "idxset.h"
|
#include "idxset.h"
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
|
|
||||||
|
|
||||||
struct sink_input {
|
|
||||||
int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume);
|
|
||||||
void (*drop) (struct sink_input *i, size_t length);
|
|
||||||
void (*kill) (struct sink_input *i);
|
|
||||||
|
|
||||||
void *userdata;
|
|
||||||
int index;
|
|
||||||
struct sink *sink;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sink {
|
struct sink {
|
||||||
char *name;
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
|
||||||
|
char *name;
|
||||||
struct core *core;
|
struct core *core;
|
||||||
struct sample_spec sample_spec;
|
struct sample_spec sample_spec;
|
||||||
struct idxset *inputs;
|
struct idxset *inputs;
|
||||||
|
|
@ -33,8 +22,8 @@ struct sink {
|
||||||
|
|
||||||
uint8_t volume;
|
uint8_t volume;
|
||||||
|
|
||||||
void (*notify)(struct sink*sink, void *userdata);
|
void (*notify)(struct sink*sink);
|
||||||
void *notify_userdata;
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec);
|
struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec);
|
||||||
|
|
@ -44,6 +33,5 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result);
|
||||||
int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result);
|
int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *result);
|
||||||
|
|
||||||
void sink_notify(struct sink*s);
|
void sink_notify(struct sink*s);
|
||||||
void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2,81 +2,47 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "inputstream.h"
|
#include "sinkinput.h"
|
||||||
|
|
||||||
struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name) {
|
struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name) {
|
||||||
struct input_stream *i;
|
struct sink_input *i;
|
||||||
int r;
|
int r;
|
||||||
assert(s && spec);
|
assert(s && spec);
|
||||||
|
|
||||||
i = malloc(sizeof(struct input_stream));
|
i = malloc(sizeof(struct sink_input));
|
||||||
assert(i);
|
assert(i);
|
||||||
i->name = name ? strdup(name) : NULL;
|
i->name = name ? strdup(name) : NULL;
|
||||||
i->sink = s;
|
i->sink = s;
|
||||||
i->spec = *spec;
|
i->spec = *spec;
|
||||||
|
|
||||||
|
i->peek = NULL;
|
||||||
|
i->drop = NULL;
|
||||||
i->kill = NULL;
|
i->kill = NULL;
|
||||||
i->kill_userdata = NULL;
|
i->userdata = NULL;
|
||||||
i->notify = NULL;
|
|
||||||
i->notify_userdata = NULL;
|
|
||||||
|
|
||||||
i->memblockq = memblockq_new(bytes_per_second(spec)/2, sample_size(spec), (size_t) -1);
|
|
||||||
assert(i->memblockq);
|
|
||||||
|
|
||||||
assert(s->core);
|
assert(s->core);
|
||||||
r = idxset_put(s->core->input_streams, i, &i->index);
|
r = idxset_put(s->core->sink_inputs, i, &i->index);
|
||||||
assert(r == 0 && i->index != IDXSET_INVALID);
|
assert(r == 0 && i->index != IDXSET_INVALID);
|
||||||
r = idxset_put(s->input_streams, i, NULL);
|
r = idxset_put(s->inputs, i, NULL);
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_stream_free(struct input_stream* i) {
|
void sink_input_free(struct sink_input* i) {
|
||||||
assert(i);
|
assert(i);
|
||||||
|
|
||||||
memblockq_free(i->memblockq);
|
|
||||||
|
|
||||||
assert(i->sink && i->sink->core);
|
assert(i->sink && i->sink->core);
|
||||||
idxset_remove_by_data(i->sink->core->input_streams, i, NULL);
|
idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL);
|
||||||
idxset_remove_by_data(i->sink->input_streams, i, NULL);
|
idxset_remove_by_data(i->sink->inputs, i, NULL);
|
||||||
|
|
||||||
free(i->name);
|
free(i->name);
|
||||||
free(i);
|
free(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_stream_notify_sink(struct input_stream *i) {
|
void sink_input_kill(struct sink_input*i) {
|
||||||
assert(i);
|
|
||||||
|
|
||||||
if (!memblockq_is_readable(i->memblockq))
|
|
||||||
return;
|
|
||||||
|
|
||||||
sink_notify(i->sink);
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata) {
|
|
||||||
assert(i && kill);
|
|
||||||
i->kill = kill;
|
|
||||||
i->kill_userdata = userdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void input_stream_kill(struct input_stream*i) {
|
|
||||||
assert(i);
|
assert(i);
|
||||||
|
|
||||||
if (i->kill)
|
if (i->kill)
|
||||||
i->kill(i, i->kill_userdata);
|
i->kill(i);
|
||||||
}
|
|
||||||
|
|
||||||
void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata) {
|
|
||||||
assert(i && notify);
|
|
||||||
|
|
||||||
i->notify = notify;
|
|
||||||
i->notify_userdata = userdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_stream_notify(struct input_stream *i) {
|
|
||||||
assert(i);
|
|
||||||
if (i->notify)
|
|
||||||
i->notify(i, i->notify_userdata);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef fooinputstreamhfoo
|
#ifndef foosinkinputhfoo
|
||||||
#define fooinputstreamhfoo
|
#define foosinkinputhfoo
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
|
@ -7,44 +7,26 @@
|
||||||
#include "sample.h"
|
#include "sample.h"
|
||||||
#include "memblockq.h"
|
#include "memblockq.h"
|
||||||
|
|
||||||
struct input_stream {
|
struct sink_input {
|
||||||
char *name;
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
|
||||||
|
char *name;
|
||||||
struct sink *sink;
|
struct sink *sink;
|
||||||
struct sample_spec spec;
|
struct sample_spec spec;
|
||||||
|
|
||||||
struct memblockq *memblockq;
|
int (*peek) (struct sink_input *i, struct memchunk *chunk, uint8_t *volume);
|
||||||
|
void (*drop) (struct sink_input *i, size_t length);
|
||||||
|
void (*kill) (struct sink_input *i);
|
||||||
|
|
||||||
void (*kill)(struct input_stream* i, void *userdata);
|
void *userdata;
|
||||||
void *kill_userdata;
|
|
||||||
|
|
||||||
void (*notify)(struct input_stream*i, void *userdata);
|
|
||||||
void *notify_userdata;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec, const char *name);
|
struct sink_input* sink_input_new(struct sink *s, struct sample_spec *spec, const char *name);
|
||||||
void input_stream_free(struct input_stream* i);
|
void sink_input_free(struct sink_input* i);
|
||||||
|
|
||||||
/* This function notifies the attached sink that new data is available
|
|
||||||
* in the memblockq */
|
|
||||||
void input_stream_notify_sink(struct input_stream *i);
|
|
||||||
|
|
||||||
|
|
||||||
/* The registrant of the input stream should call this function to set a
|
|
||||||
* callback function which is called when destruction of the input stream is
|
|
||||||
* requested */
|
|
||||||
void input_stream_set_kill_callback(struct input_stream *i, void (*kill)(struct input_stream*i, void *userdata), void *userdata);
|
|
||||||
|
|
||||||
/* Code that didn't create the input stream should call this function to
|
/* Code that didn't create the input stream should call this function to
|
||||||
* request destruction of it */
|
* request destruction of it */
|
||||||
void input_stream_kill(struct input_stream *i);
|
void sink_input_kill(struct sink_input *i);
|
||||||
|
|
||||||
/* Notify the code that created this input stream that some data has
|
|
||||||
* been removed from the memblockq */
|
|
||||||
void input_stream_set_notify_callback(struct input_stream *i, void (*notify)(struct input_stream*i, void *userdata), void *userdata);
|
|
||||||
|
|
||||||
void input_stream_notify(struct input_stream *i);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
35
src/source.c
35
src/source.c
|
|
@ -4,7 +4,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "outputstream.h"
|
#include "sourceoutput.h"
|
||||||
|
|
||||||
struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec) {
|
struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec) {
|
||||||
struct source *s;
|
struct source *s;
|
||||||
|
|
@ -15,31 +15,31 @@ struct source* source_new(struct core *core, const char *name, const struct samp
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
s->name = name ? strdup(name) : NULL;
|
s->name = name ? strdup(name) : NULL;
|
||||||
r = idxset_put(core->sources, s, &s->index);
|
|
||||||
assert(s->index != IDXSET_INVALID && r >= 0);
|
|
||||||
|
|
||||||
s->core = core;
|
s->core = core;
|
||||||
s->sample_spec = *spec;
|
s->sample_spec = *spec;
|
||||||
s->output_streams = idxset_new(NULL, NULL);
|
s->outputs = idxset_new(NULL, NULL);
|
||||||
|
|
||||||
s->link_change_callback = NULL;
|
s->notify = NULL;
|
||||||
s->userdata = NULL;
|
s->userdata = NULL;
|
||||||
|
|
||||||
|
r = idxset_put(core->sources, s, &s->index);
|
||||||
|
assert(s->index != IDXSET_INVALID && r >= 0);
|
||||||
|
|
||||||
fprintf(stderr, "source: created %u \"%s\"\n", s->index, s->name);
|
fprintf(stderr, "source: created %u \"%s\"\n", s->index, s->name);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void source_free(struct source *s) {
|
void source_free(struct source *s) {
|
||||||
struct output_stream *o, *j = NULL;
|
struct source_output *o, *j = NULL;
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
while ((o = idxset_first(s->output_streams, NULL))) {
|
while ((o = idxset_first(s->outputs, NULL))) {
|
||||||
assert(o != j);
|
assert(o != j);
|
||||||
output_stream_free(o);
|
source_output_kill(o);
|
||||||
j = o;
|
j = o;
|
||||||
}
|
}
|
||||||
idxset_free(s->output_streams, NULL, NULL);
|
idxset_free(s->outputs, NULL, NULL);
|
||||||
|
|
||||||
idxset_remove_by_data(s->core->sources, s, NULL);
|
idxset_remove_by_data(s->core->sources, s, NULL);
|
||||||
|
|
||||||
|
|
@ -49,17 +49,24 @@ void source_free(struct source *s) {
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void source_notify(struct source*s) {
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
if (s->notify)
|
||||||
|
s->notify(s);
|
||||||
|
}
|
||||||
|
|
||||||
static int do_post(void *p, uint32_t index, int *del, void*userdata) {
|
static int do_post(void *p, uint32_t index, int *del, void*userdata) {
|
||||||
struct memchunk *chunk = userdata;
|
struct memchunk *chunk = userdata;
|
||||||
struct output_stream *o = p;
|
struct source_output *o = p;
|
||||||
assert(o && o->memblockq && index && del && chunk);
|
assert(o && o->push && index && del && chunk);
|
||||||
|
|
||||||
memblockq_push(o->memblockq, chunk, 0);
|
o->push(o, chunk);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void source_post(struct source*s, struct memchunk *chunk) {
|
void source_post(struct source*s, struct memchunk *chunk) {
|
||||||
assert(s && chunk);
|
assert(s && chunk);
|
||||||
|
|
||||||
idxset_foreach(s->output_streams, do_post, chunk);
|
idxset_foreach(s->outputs, do_post, chunk);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ struct source;
|
||||||
#include "memblock.h"
|
#include "memblock.h"
|
||||||
|
|
||||||
struct source {
|
struct source {
|
||||||
char *name;
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
|
||||||
|
char *name;
|
||||||
struct core *core;
|
struct core *core;
|
||||||
struct sample_spec sample_spec;
|
struct sample_spec sample_spec;
|
||||||
struct idxset *output_streams;
|
struct idxset *outputs;
|
||||||
|
|
||||||
void (*link_change_callback)(struct source*source, void *userdata);
|
void (*notify)(struct source*source);
|
||||||
void *userdata;
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -27,4 +27,6 @@ void source_free(struct source *s);
|
||||||
/* Pass a new memory block to all output streams */
|
/* Pass a new memory block to all output streams */
|
||||||
void source_post(struct source*s, struct memchunk *b);
|
void source_post(struct source*s, struct memchunk *b);
|
||||||
|
|
||||||
|
void source_notify(struct source *s);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2,56 +2,46 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "outputstream.h"
|
#include "sourceoutput.h"
|
||||||
|
|
||||||
struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name) {
|
struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name) {
|
||||||
struct output_stream *o;
|
struct source_output *o;
|
||||||
int r;
|
int r;
|
||||||
assert(s && spec);
|
assert(s && spec);
|
||||||
|
|
||||||
o = malloc(sizeof(struct output_stream));
|
o = malloc(sizeof(struct source_output));
|
||||||
assert(o);
|
assert(o);
|
||||||
o->name = name ? strdup(name) : NULL;
|
o->name = name ? strdup(name) : NULL;
|
||||||
o->source = s;
|
o->source = s;
|
||||||
o->spec = *spec;
|
o->spec = *spec;
|
||||||
o->kill = NULL;
|
|
||||||
o->kill_userdata = NULL;
|
|
||||||
|
|
||||||
o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1);
|
o->push = NULL;
|
||||||
assert(o->memblockq);
|
o->kill = NULL;
|
||||||
|
o->userdata = NULL;
|
||||||
|
|
||||||
assert(s->core);
|
assert(s->core);
|
||||||
r = idxset_put(s->core->output_streams, o, &o->index);
|
r = idxset_put(s->core->source_outputs, o, &o->index);
|
||||||
assert(r == 0 && o->index != IDXSET_INVALID);
|
assert(r == 0 && o->index != IDXSET_INVALID);
|
||||||
r = idxset_put(s->output_streams, o, NULL);
|
r = idxset_put(s->outputs, o, NULL);
|
||||||
assert(r == 0);
|
assert(r == 0);
|
||||||
|
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_stream_free(struct output_stream* o) {
|
void source_output_free(struct source_output* o) {
|
||||||
assert(o);
|
assert(o);
|
||||||
|
|
||||||
memblockq_free(o->memblockq);
|
|
||||||
|
|
||||||
assert(o->source && o->source->core);
|
assert(o->source && o->source->core);
|
||||||
idxset_remove_by_data(o->source->core->output_streams, o, NULL);
|
idxset_remove_by_data(o->source->core->source_outputs, o, NULL);
|
||||||
idxset_remove_by_data(o->source->output_streams, o, NULL);
|
idxset_remove_by_data(o->source->outputs, o, NULL);
|
||||||
|
|
||||||
free(o->name);
|
free(o->name);
|
||||||
free(o);
|
free(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata) {
|
void source_output_kill(struct source_output*i) {
|
||||||
assert(i && kill);
|
|
||||||
i->kill = kill;
|
|
||||||
i->kill_userdata = userdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void output_stream_kill(struct output_stream*i) {
|
|
||||||
assert(i);
|
assert(i);
|
||||||
|
|
||||||
if (i->kill)
|
if (i->kill)
|
||||||
i->kill(i, i->kill_userdata);
|
i->kill(i);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,28 @@
|
||||||
#ifndef foooutputstreamhfoo
|
#ifndef foosourceoutputhfoo
|
||||||
#define foooutputstreamhfoo
|
#define foosourceoutputhfoo
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "sample.h"
|
#include "sample.h"
|
||||||
#include "memblockq.h"
|
#include "memblockq.h"
|
||||||
|
|
||||||
struct output_stream {
|
struct source_output {
|
||||||
char *name;
|
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
|
||||||
|
char *name;
|
||||||
struct source *source;
|
struct source *source;
|
||||||
struct sample_spec spec;
|
struct sample_spec spec;
|
||||||
|
|
||||||
struct memblockq *memblockq;
|
void (*push)(struct source_output *o, struct memchunk *chunk);
|
||||||
void (*kill)(struct output_stream* i, void *userdata);
|
void (*kill)(struct source_output* o);
|
||||||
void *kill_userdata;
|
|
||||||
|
void *userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct output_stream* output_stream_new(struct source *s, struct sample_spec *spec, const char *name);
|
struct source_output* source_output_new(struct source *s, struct sample_spec *spec, const char *name);
|
||||||
void output_stream_free(struct output_stream* o);
|
void source_output_free(struct source_output* o);
|
||||||
|
|
||||||
void output_stream_set_kill_callback(struct output_stream *i, void (*kill)(struct output_stream*i, void *userdata), void *userdata);
|
void source_output_kill(struct source_output*o);
|
||||||
void output_stream_kill(struct output_stream*i);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue