Ugly hack to get around Solaris particularly brain dead sound system.

The system has a buffer size of 0.5 MB which cannot be changed. We emulate
a smaller buffer through some SIGPOLL trickery.


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@457 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Pierre Ossman 2006-01-19 10:24:49 +00:00
parent 719c3773d4
commit 0ca9a0ea09

View file

@ -35,6 +35,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <signal.h>
#include <stropts.h> #include <stropts.h>
#include <sys/conf.h> #include <sys/conf.h>
#include <sys/audio.h> #include <sys/audio.h>
@ -48,6 +49,7 @@
#include "modargs.h" #include "modargs.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "log.h" #include "log.h"
#include "mainloop-signal.h"
#include "module-solaris-symdef.h" #include "module-solaris-symdef.h"
PA_MODULE_AUTHOR("Pierre Ossman") PA_MODULE_AUTHOR("Pierre Ossman")
@ -62,10 +64,12 @@ struct userdata {
pa_source *source; pa_source *source;
pa_iochannel *io; pa_iochannel *io;
pa_core *core; pa_core *core;
pa_signal_event *sig;
pa_memchunk memchunk, silence; pa_memchunk memchunk, silence;
uint32_t sample_size; uint32_t sample_size;
uint32_t buffer_size;
unsigned int written_bytes, read_bytes; unsigned int written_bytes, read_bytes;
int fd; int fd;
@ -99,7 +103,10 @@ static void update_usage(struct userdata *u) {
} }
static void do_write(struct userdata *u) { static void do_write(struct userdata *u) {
audio_info_t info;
int err;
pa_memchunk *memchunk; pa_memchunk *memchunk;
size_t len;
ssize_t r; ssize_t r;
assert(u); assert(u);
@ -109,17 +116,40 @@ static void do_write(struct userdata *u) {
update_usage(u); update_usage(u);
err = ioctl(u->fd, AUDIO_GETINFO, &info);
assert(err >= 0);
/*
* Since we cannot modify the size of the output buffer we fake it
* by not filling it more than u->buffer_size.
*/
len = u->buffer_size;
len -= u->written_bytes - (info.play.samples * u->sample_size);
/*
* Do not fill more than half the buffer in one chunk since we only
* get notifications upon completion of entire chunks.
*/
if (len > (u->buffer_size / 2))
len = u->buffer_size / 2;
if (len < u->sample_size)
return;
memchunk = &u->memchunk; memchunk = &u->memchunk;
if (!memchunk->length) if (!memchunk->length)
if (pa_sink_render(u->sink, CHUNK_SIZE, memchunk) < 0) if (pa_sink_render(u->sink, len, memchunk) < 0)
memchunk = &u->silence; memchunk = &u->silence;
assert(memchunk->memblock); assert(memchunk->memblock);
assert(memchunk->memblock->data); assert(memchunk->memblock->data);
assert(memchunk->length); assert(memchunk->length);
if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { if (memchunk->length < len)
len = memchunk->length;
if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, len)) < 0) {
pa_log(__FILE__": write() failed: %s\n", strerror(errno)); pa_log(__FILE__": write() failed: %s\n", strerror(errno));
return; return;
} }
@ -137,6 +167,14 @@ static void do_write(struct userdata *u) {
} }
u->written_bytes += r; u->written_bytes += r;
/*
* Write 0 bytes which will generate a SIGPOLL when "played".
*/
if (write(u->fd, NULL, 0) < 0) {
pa_log(__FILE__": write() failed: %s\n", strerror(errno));
return;
}
} }
static void do_read(struct userdata *u) { static void do_read(struct userdata *u) {
@ -179,6 +217,12 @@ static void io_callback(pa_iochannel *io, void*userdata) {
do_read(u); do_read(u);
} }
void sig_callback(pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata) {
struct userdata *u = userdata;
assert(u);
do_write(u);
}
static pa_usec_t sink_get_latency_cb(pa_sink *s) { static pa_usec_t sink_get_latency_cb(pa_sink *s) {
pa_usec_t r = 0; pa_usec_t r = 0;
audio_info_t info; audio_info_t info;
@ -326,7 +370,7 @@ int pa__init(pa_core *c, pa_module*m) {
mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
buffer_size = -1; buffer_size = 16384;
if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) { if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
pa_log(__FILE__": failed to parse buffer size argument\n"); pa_log(__FILE__": failed to parse buffer size argument\n");
goto fail; goto fail;
@ -383,6 +427,7 @@ int pa__init(pa_core *c, pa_module*m) {
u->memchunk.memblock = NULL; u->memchunk.memblock = NULL;
u->memchunk.length = 0; u->memchunk.length = 0;
u->sample_size = pa_frame_size(&ss); u->sample_size = pa_frame_size(&ss);
u->buffer_size = buffer_size;
u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat); u->silence.memblock = pa_memblock_new(u->silence.length = CHUNK_SIZE, u->core->memblock_stat);
assert(u->silence.memblock); assert(u->silence.memblock);
@ -395,6 +440,10 @@ int pa__init(pa_core *c, pa_module*m) {
u->module = m; u->module = m;
m->userdata = u; m->userdata = u;
u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
assert(u->sig);
ioctl(u->fd, I_SETSIG, S_MSG);
pa_modargs_free(ma); pa_modargs_free(ma);
return 0; return 0;
@ -416,6 +465,9 @@ void pa__done(pa_core *c, pa_module*m) {
if (!(u = m->userdata)) if (!(u = m->userdata))
return; return;
ioctl(u->fd, I_SETSIG, 0);
pa_signal_free(u->sig);
if (u->memchunk.memblock) if (u->memchunk.memblock)
pa_memblock_unref(u->memchunk.memblock); pa_memblock_unref(u->memchunk.memblock);
if (u->silence.memblock) if (u->silence.memblock)