mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
oss output works
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@15 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
bfcde99a8f
commit
1a5060720d
12 changed files with 207 additions and 100 deletions
|
|
@ -20,8 +20,9 @@ AM_CFLAGS=-ansi -D_GNU_SOURCE
|
|||
|
||||
bin_PROGRAMS = polypaudio
|
||||
|
||||
pkglib_LTLIBRARIES=libprotocol-simple.la protocol-simple-tcp.la \
|
||||
libsocket-server.la sink-pipe.la libpstream.la libiochannel.la libpacket.la
|
||||
pkglib_LTLIBRARIES=libprotocol-simple.la module-simple-protocol-tcp.la \
|
||||
libsocket-server.la module-pipe-sink.la libpstream.la libiochannel.la \
|
||||
libpacket.la module-oss.la
|
||||
|
||||
polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \
|
||||
memblock.c sample.c memblockq.c client.c \
|
||||
|
|
@ -49,14 +50,14 @@ libiochannel_la_LDFLAGS = -avoid-version
|
|||
libpacket_la_SOURCES = packet.c
|
||||
libpacket_la_LDFLAGS = -avoid-version
|
||||
|
||||
protocol_simple_tcp_la_SOURCES = protocol-simple-tcp.c
|
||||
protocol_simple_tcp_la_LDFLAGS = -module -avoid-version
|
||||
protocol_simple_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la
|
||||
module_simple_protocol_tcp_la_SOURCES = module-simple-protocol-tcp.c
|
||||
module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version
|
||||
module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la
|
||||
|
||||
sink_pipe_la_SOURCES = sink-pipe.c
|
||||
sink_pipe_la_LDFLAGS = -module -avoid-version
|
||||
sink_pipe_la_LIBADD = libiochannel.la
|
||||
module_pipe_sink_la_SOURCES = module-pipe-sink.c
|
||||
module_pipe_sink_la_LDFLAGS = -module -avoid-version
|
||||
module_pipe_sink_la_LIBADD = libiochannel.la
|
||||
|
||||
sink_oss_la_SOURCES = sink-pipe.c
|
||||
sink_oss_la_LDFLAGS = -module -avoid-version
|
||||
sink_oss_la_LIBADD = libiochannel.la
|
||||
module_oss_la_SOURCES = module-oss.c
|
||||
module_oss_la_LDFLAGS = -module -avoid-version
|
||||
module_oss_la_LIBADD = libiochannel.la
|
||||
|
|
|
|||
|
|
@ -14,10 +14,13 @@ struct input_stream* input_stream_new(struct sink *s, struct sample_spec *spec,
|
|||
i->name = name ? strdup(name) : NULL;
|
||||
i->sink = s;
|
||||
i->spec = *spec;
|
||||
|
||||
i->kill = NULL;
|
||||
i->kill_userdata = NULL;
|
||||
i->notify = NULL;
|
||||
i->notify_userdata = NULL;
|
||||
|
||||
i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec));
|
||||
i->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1);
|
||||
assert(i->memblockq);
|
||||
|
||||
assert(s->core);
|
||||
|
|
@ -45,7 +48,7 @@ void input_stream_free(struct input_stream* i) {
|
|||
void input_stream_notify_sink(struct input_stream *i) {
|
||||
assert(i);
|
||||
|
||||
if (memblockq_is_empty(i->memblockq))
|
||||
if (!memblockq_is_readable(i->memblockq))
|
||||
return;
|
||||
|
||||
sink_notify(i->sink);
|
||||
|
|
@ -64,3 +67,16 @@ void input_stream_kill(struct input_stream*i) {
|
|||
if (i->kill)
|
||||
i->kill(i, i->kill_userdata);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ struct input_stream {
|
|||
|
||||
void (*kill)(struct input_stream* i, 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);
|
||||
|
|
@ -31,10 +34,17 @@ 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 *c, void (*kill)(struct input_stream*i, void *userdata), void *userdata);
|
||||
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
|
||||
* request destruction of it */
|
||||
void input_stream_kill(struct input_stream *c);
|
||||
void input_stream_kill(struct input_stream *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
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ int main(int argc, char *argv[]) {
|
|||
mainloop_source_new_signal(m, SIGINT, signal_callback, NULL);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
module_load(c, "sink-pipe", NULL);
|
||||
module_load(c, "protocol-simple-tcp", NULL);
|
||||
module_load(c, "module-oss", NULL);
|
||||
module_load(c, "module-pipe-sink", NULL);
|
||||
module_load(c, "module-simple-protocol-tcp", NULL);
|
||||
|
||||
mainloop_run(m);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
|
@ -14,9 +15,10 @@ struct memblockq {
|
|||
size_t total_length;
|
||||
size_t maxlength;
|
||||
size_t base;
|
||||
size_t prebuf;
|
||||
};
|
||||
|
||||
struct memblockq* memblockq_new(size_t maxlength, size_t base) {
|
||||
struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf) {
|
||||
struct memblockq* bq;
|
||||
assert(maxlength && base);
|
||||
|
||||
|
|
@ -27,6 +29,11 @@ struct memblockq* memblockq_new(size_t maxlength, size_t base) {
|
|||
bq->total_length = 0;
|
||||
bq->base = base;
|
||||
bq->maxlength = ((maxlength+base-1)/base)*base;
|
||||
bq->prebuf = prebuf == (size_t) -1 ? bq->maxlength/2 : prebuf;
|
||||
|
||||
if (bq->prebuf > bq->maxlength)
|
||||
bq->prebuf = bq->maxlength;
|
||||
|
||||
assert(bq->maxlength >= base);
|
||||
return bq;
|
||||
}
|
||||
|
|
@ -72,9 +79,11 @@ void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta)
|
|||
int memblockq_peek(struct memblockq* bq, struct memchunk *chunk) {
|
||||
assert(bq && chunk);
|
||||
|
||||
if (!bq->blocks)
|
||||
if (!bq->blocks || bq->total_length < bq->prebuf)
|
||||
return -1;
|
||||
|
||||
bq->prebuf = 0;
|
||||
|
||||
*chunk = bq->blocks->chunk;
|
||||
memblock_ref(chunk->memblock);
|
||||
return 0;
|
||||
|
|
@ -85,9 +94,11 @@ int memblockq_pop(struct memblockq* bq, struct memchunk *chunk) {
|
|||
|
||||
assert(bq && chunk);
|
||||
|
||||
if (!bq->blocks)
|
||||
if (!bq->blocks || bq->total_length < bq->prebuf)
|
||||
return -1;
|
||||
|
||||
bq->prebuf = 0;
|
||||
|
||||
q = bq->blocks;
|
||||
bq->blocks = bq->blocks->next;
|
||||
|
||||
|
|
@ -138,6 +149,8 @@ void memblockq_shorten(struct memblockq *bq, size_t length) {
|
|||
if (bq->total_length <= length)
|
||||
return;
|
||||
|
||||
fprintf(stderr, "Warning! memblockq_shorten()\n");
|
||||
|
||||
l = bq->total_length - length;
|
||||
l /= bq->base;
|
||||
l *= bq->base;
|
||||
|
|
@ -151,8 +164,15 @@ void memblockq_empty(struct memblockq *bq) {
|
|||
memblockq_shorten(bq, 0);
|
||||
}
|
||||
|
||||
int memblockq_is_empty(struct memblockq *bq) {
|
||||
int memblockq_is_readable(struct memblockq *bq) {
|
||||
assert(bq);
|
||||
|
||||
return bq->total_length < bq->base;
|
||||
return bq->total_length >= bq->prebuf;
|
||||
}
|
||||
|
||||
int memblockq_is_writable(struct memblockq *bq, size_t length) {
|
||||
assert(bq);
|
||||
|
||||
assert(length <= bq->maxlength);
|
||||
return bq->total_length + length <= bq->maxlength;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
struct memblockq;
|
||||
|
||||
struct memblockq* memblockq_new(size_t maxlength, size_t base);
|
||||
struct memblockq* memblockq_new(size_t maxlength, size_t base, size_t prebuf);
|
||||
void memblockq_free(struct memblockq* bq);
|
||||
|
||||
void memblockq_push(struct memblockq* bq, struct memchunk *chunk, size_t delta);
|
||||
|
|
@ -19,6 +19,7 @@ void memblockq_drop(struct memblockq *bq, size_t length);
|
|||
void memblockq_shorten(struct memblockq *bq, size_t length);
|
||||
void memblockq_empty(struct memblockq *bq);
|
||||
|
||||
int memblockq_is_empty(struct memblockq *bq);
|
||||
int memblockq_is_readable(struct memblockq *bq);
|
||||
int memblockq_is_writable(struct memblockq *bq, size_t length);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include <soundcard.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -22,7 +23,7 @@ struct userdata {
|
|||
|
||||
struct memchunk memchunk, silence;
|
||||
|
||||
uint32_t fragment_size;
|
||||
uint32_t in_fragment_size, out_fragment_size, sample_size;
|
||||
};
|
||||
|
||||
static void do_write(struct userdata *u) {
|
||||
|
|
@ -34,7 +35,7 @@ static void do_write(struct userdata *u) {
|
|||
return;
|
||||
|
||||
if (!u->memchunk.length) {
|
||||
if (sink_render(u->sink, fragment_size, &u->memchunk) < 0)
|
||||
if (sink_render(u->sink, u->out_fragment_size, &u->memchunk) < 0)
|
||||
memchunk = &u->silence;
|
||||
else
|
||||
memchunk = &u->memchunk;
|
||||
|
|
@ -68,15 +69,15 @@ static void do_read(struct userdata *u) {
|
|||
if (!iochannel_is_readable(u->io))
|
||||
return;
|
||||
|
||||
memchunk.memblock = memblock_new(u->fragment_size);
|
||||
memchunk.memblock = memblock_new(u->in_fragment_size);
|
||||
assert(memchunk.memblock);
|
||||
if ((r = iochannel_read(u->io, memchunk.memblock->data, memchunk->memblock->length)) < 0) {
|
||||
if ((r = iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
|
||||
memblock_unref(memchunk.memblock);
|
||||
fprintf(stderr, "read() failed: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
assert(r < memchunk->memblock->length);
|
||||
assert(r <= memchunk.memblock->length);
|
||||
memchunk.length = memchunk.memblock->length = r;
|
||||
memchunk.index = 0;
|
||||
|
||||
|
|
@ -92,17 +93,17 @@ static void io_callback(struct iochannel *io, void*userdata) {
|
|||
}
|
||||
|
||||
int module_init(struct core *c, struct module*m) {
|
||||
struct audio_buf_info info;
|
||||
struct userdata *u = NULL;
|
||||
struct stat st;
|
||||
char *p;
|
||||
int fd = -1;
|
||||
int format, channels, speed, frag_size;
|
||||
int m;
|
||||
const static struct sample_spec ss;
|
||||
int format, channels, speed, frag_size, in_frag_size, out_frag_size;
|
||||
int mode;
|
||||
struct sample_spec ss;
|
||||
assert(c && m);
|
||||
|
||||
p = m->argument ? m->argument : "/dev/dsp";
|
||||
if ((fd = open(p, m = O_RDWR)) >= 0) {
|
||||
if ((fd = open(p, mode = O_RDWR)) >= 0) {
|
||||
int caps;
|
||||
|
||||
ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
|
||||
|
|
@ -119,16 +120,16 @@ int module_init(struct core *c, struct module*m) {
|
|||
}
|
||||
|
||||
if (fd < 0) {
|
||||
if ((fd = open(p, m = O_WRONLY)) < 0) {
|
||||
if ((fd = open(p, m = O_RDONLY)) < 0) {
|
||||
if ((fd = open(p, mode = O_WRONLY)) < 0) {
|
||||
if ((fd = open(p, mode = O_RDONLY)) < 0) {
|
||||
fprintf(stderr, "open('%s'): %s\n", p, strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frags = 0x7fff0000 | (10 << 16); /* 1024 bytes fragment size */
|
||||
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frags) < 0) {
|
||||
|
||||
frag_size = ((int) 0x7ffff << 4) | 10; /* nfrags = 4; frag_size = 2^10 */
|
||||
if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag_size) < 0) {
|
||||
fprintf(stderr, "SNDCTL_DSP_SETFRAGMENT: %s\n", strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -165,25 +166,35 @@ int module_init(struct core *c, struct module*m) {
|
|||
assert(speed);
|
||||
ss.rate = speed;
|
||||
|
||||
if (ioctl(fd, SNCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
|
||||
if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) {
|
||||
fprintf(stderr, "SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
assert(frag_size);
|
||||
|
||||
in_frag_size = out_frag_size = frag_size;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
|
||||
fprintf(stderr, "INPUT: %u fragments of size %u.\n", info.fragstotal, info.fragsize);
|
||||
in_frag_size = info.fragsize;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
|
||||
fprintf(stderr, "OUTUT: %u fragments of size %u.\n", info.fragstotal, info.fragsize);
|
||||
out_frag_size = info.fragsize;
|
||||
}
|
||||
|
||||
u = malloc(sizeof(struct userdata));
|
||||
assert(u);
|
||||
|
||||
u->core = c;
|
||||
|
||||
if (m != O_RDONLY) {
|
||||
if (mode != O_RDONLY) {
|
||||
u->sink = sink_new(c, "dsp", &ss);
|
||||
assert(u->sink);
|
||||
} else
|
||||
u->sink = NULL;
|
||||
|
||||
if (m != O_WRONLY) {
|
||||
if (mode != O_WRONLY) {
|
||||
u->source = source_new(c, "dsp", &ss);
|
||||
assert(u->source);
|
||||
} else
|
||||
|
|
@ -197,11 +208,13 @@ int module_init(struct core *c, struct module*m) {
|
|||
|
||||
u->memchunk.memblock = NULL;
|
||||
u->memchunk.length = 0;
|
||||
u->sample_size = sample_size(&ss);
|
||||
|
||||
u->fragment_size = frag_size;
|
||||
u->silence.memblock = memblock_new(u->fragment_size);
|
||||
assert(u->silence);
|
||||
u->silence.length = u->fragment_size;
|
||||
u->out_fragment_size = out_frag_size;
|
||||
u->in_fragment_size = in_frag_size;
|
||||
u->silence.memblock = memblock_new(u->silence.length = u->out_fragment_size);
|
||||
assert(u->silence.memblock);
|
||||
silence(u->silence.memblock, &ss);
|
||||
u->silence.index = 0;
|
||||
|
||||
m->userdata = u;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ struct output_stream* output_stream_new(struct source *s, struct sample_spec *sp
|
|||
o->kill = NULL;
|
||||
o->kill_userdata = NULL;
|
||||
|
||||
o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec));
|
||||
o->memblockq = memblockq_new(bytes_per_second(spec)*5, sample_size(spec), (size_t) -1);
|
||||
assert(o->memblockq);
|
||||
|
||||
assert(s->core);
|
||||
|
|
|
|||
|
|
@ -66,53 +66,73 @@ static void client_kill_cb(struct client *client, void*userdata) {
|
|||
destroy_connection(c);
|
||||
}
|
||||
|
||||
static int do_read(struct connection *c) {
|
||||
struct memchunk chunk;
|
||||
ssize_t r;
|
||||
|
||||
if (!iochannel_is_readable(c->io))
|
||||
return 0;
|
||||
|
||||
if (!c->istream || !memblockq_is_writable(c->istream->memblockq, BUFSIZE))
|
||||
return 0;
|
||||
|
||||
chunk.memblock = memblock_new(BUFSIZE);
|
||||
assert(chunk.memblock);
|
||||
|
||||
if ((r = iochannel_read(c->io, chunk.memblock->data, BUFSIZE)) <= 0) {
|
||||
fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno));
|
||||
memblock_unref(chunk.memblock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
chunk.memblock->length = r;
|
||||
chunk.length = r;
|
||||
chunk.index = 0;
|
||||
|
||||
memblockq_push(c->istream->memblockq, &chunk, 0);
|
||||
input_stream_notify_sink(c->istream);
|
||||
memblock_unref(chunk.memblock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_write(struct connection *c) {
|
||||
struct memchunk chunk;
|
||||
ssize_t r;
|
||||
|
||||
if (!iochannel_is_writable(c->io))
|
||||
return 0;
|
||||
|
||||
if (!c->ostream)
|
||||
return 0;
|
||||
|
||||
memblockq_peek(c->ostream->memblockq, &chunk);
|
||||
assert(chunk.memblock && chunk.length);
|
||||
|
||||
if ((r = iochannel_write(c->io, chunk.memblock->data+chunk.index, chunk.length)) < 0) {
|
||||
fprintf(stderr, "write(): %s\n", strerror(errno));
|
||||
memblock_unref(chunk.memblock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memblockq_drop(c->ostream->memblockq, r);
|
||||
memblock_unref(chunk.memblock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void io_callback(struct iochannel*io, void *userdata) {
|
||||
struct connection *c = userdata;
|
||||
assert(io && c);
|
||||
assert(io && c && c->io == io);
|
||||
|
||||
if (c->istream && iochannel_is_readable(io)) {
|
||||
struct memchunk chunk;
|
||||
ssize_t r;
|
||||
if (do_read(c) < 0 || do_write(c) < 0)
|
||||
destroy_connection(c);
|
||||
}
|
||||
|
||||
chunk.memblock = memblock_new(BUFSIZE);
|
||||
assert(chunk.memblock);
|
||||
|
||||
if ((r = iochannel_read(io, chunk.memblock->data, BUFSIZE)) <= 0) {
|
||||
fprintf(stderr, "read(): %s\n", r == 0 ? "EOF" : strerror(errno));
|
||||
memblock_unref(chunk.memblock);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
chunk.memblock->length = r;
|
||||
chunk.length = r;
|
||||
chunk.index = 0;
|
||||
|
||||
memblockq_push(c->istream->memblockq, &chunk, 0);
|
||||
input_stream_notify_sink(c->istream);
|
||||
memblock_unref(chunk.memblock);
|
||||
}
|
||||
|
||||
if (c->ostream && iochannel_is_writable(io)) {
|
||||
struct memchunk chunk;
|
||||
ssize_t r;
|
||||
|
||||
memblockq_peek(c->ostream->memblockq, &chunk);
|
||||
assert(chunk.memblock && chunk.length);
|
||||
|
||||
if ((r = iochannel_write(io, chunk.memblock->data+chunk.index, chunk.length)) < 0) {
|
||||
fprintf(stderr, "write(): %s\n", strerror(errno));
|
||||
memblock_unref(chunk.memblock);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memblockq_drop(c->ostream->memblockq, r);
|
||||
memblock_unref(chunk.memblock);
|
||||
}
|
||||
|
||||
return;
|
||||
static void istream_notify_cb(struct input_stream *i, void *userdata) {
|
||||
struct connection*c = userdata;
|
||||
assert(i && c && c->istream == i);
|
||||
|
||||
fail:
|
||||
destroy_connection(c);
|
||||
if (do_read(c) < 0)
|
||||
destroy_connection(c);
|
||||
}
|
||||
|
||||
static void on_connection(struct socket_server*s, struct iochannel *io, void *userdata) {
|
||||
|
|
@ -155,6 +175,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us
|
|||
c->istream = input_stream_new(sink, &DEFAULT_SAMPLE_SPEC, c->client->name);
|
||||
assert(c->istream);
|
||||
input_stream_set_kill_callback(c->istream, istream_kill_cb, c);
|
||||
input_stream_set_notify_callback(c->istream, istream_notify_cb, c);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
20
src/sink.c
20
src/sink.c
|
|
@ -33,8 +33,8 @@ struct sink* sink_new(struct core *core, const char *name, const struct sample_s
|
|||
|
||||
s->volume = 0xFF;
|
||||
|
||||
s->notify_callback = NULL;
|
||||
s->userdata = NULL;
|
||||
s->notify = NULL;
|
||||
s->notify_userdata = NULL;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
|
@ -103,6 +103,10 @@ static int do_mix(void *p, uint32_t index, int *del, void*userdata) {
|
|||
assert(chunk.length && chunk.length <= info->chunk->memblock->length - info->chunk->index);
|
||||
|
||||
add_clip(info->chunk, &chunk, info->spec);
|
||||
memblock_unref(chunk.memblock);
|
||||
memblockq_drop(i->memblockq, info->chunk->length);
|
||||
|
||||
input_stream_notify(i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +143,8 @@ int sink_render_into(struct sink*s, struct memblock *target, struct memchunk *re
|
|||
target->length = l;
|
||||
memblock_unref(chunk.memblock);
|
||||
memblockq_drop(i->memblockq, l);
|
||||
|
||||
input_stream_notify(i);
|
||||
|
||||
result->memblock = target;
|
||||
result->length = l;
|
||||
|
|
@ -191,6 +197,8 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) {
|
|||
l = length < result->length ? length : result->length;
|
||||
result->length = l;
|
||||
memblockq_drop(i->memblockq, l);
|
||||
input_stream_notify(i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -211,15 +219,15 @@ int sink_render(struct sink*s, size_t length, struct memchunk *result) {
|
|||
void sink_notify(struct sink*s) {
|
||||
assert(s);
|
||||
|
||||
if (s->notify_callback)
|
||||
s->notify_callback(s, s->userdata);
|
||||
if (s->notify)
|
||||
s->notify(s, s->notify_userdata);
|
||||
}
|
||||
|
||||
void sink_set_notify_callback(struct sink *s, void (*notify_callback)(struct sink*sink, void *userdata), void *userdata) {
|
||||
assert(s && notify_callback);
|
||||
|
||||
s->notify_callback = notify_callback;
|
||||
s->userdata = userdata;
|
||||
s->notify = notify_callback;
|
||||
s->notify_userdata = userdata;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ struct sink {
|
|||
|
||||
uint8_t volume;
|
||||
|
||||
void (*notify_callback)(struct sink*sink, void *userdata);
|
||||
void *userdata;
|
||||
void (*notify)(struct sink*sink, void *userdata);
|
||||
void *notify_userdata;
|
||||
};
|
||||
|
||||
struct sink* sink_new(struct core *core, const char *name, const struct sample_spec *spec);
|
||||
|
|
|
|||
16
src/todo
Normal file
16
src/todo
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
- mixing
|
||||
- resampling
|
||||
- native protocol/library
|
||||
- oss/mmap
|
||||
- esound prodocol
|
||||
- config-parser
|
||||
-- 0.1
|
||||
- future cancellation
|
||||
- client-ui
|
||||
|
||||
drivers:
|
||||
- libao
|
||||
- xmms
|
||||
- portaudio
|
||||
- mplayer
|
||||
- python
|
||||
Loading…
Add table
Add a link
Reference in a new issue