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;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/idxset.c
									
										
									
									
									
								
							
							
						
						
									
										19
									
								
								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