From e205b25d65ccb380fa158711e24d55b6de5d9bc1 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 16 Feb 2006 19:19:58 +0000 Subject: Reorganised the source tree. We now have src/ with a couple of subdirs: * daemon/ - Contains the files specific to the polypaudio daemon. * modules/ - All loadable modules. * polyp/ - Files that are part of the public, application interface or are only used in libpolyp. * polypcore/ - All other shared files. * tests/ - Test programs. * utils/ - Utility programs. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@487 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 468 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) create mode 100644 src/modules/module-oss.c (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c new file mode 100644 index 00000000..04458419 --- /dev/null +++ b/src/modules/module-oss.c @@ -0,0 +1,468 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "module-oss-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("OSS Sink/Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") + +struct userdata { + pa_sink *sink; + pa_source *source; + pa_iochannel *io; + pa_core *core; + + pa_memchunk memchunk, silence; + + uint32_t in_fragment_size, out_fragment_size, sample_size; + int use_getospace, use_getispace; + + int fd; + pa_module *module; +}; + +static const char* const valid_modargs[] = { + "sink_name", + "source_name", + "device", + "record", + "playback", + "fragments", + "fragment_size", + "format", + "rate", + "channels", + NULL +}; + +#define DEFAULT_SINK_NAME "oss_output" +#define DEFAULT_SOURCE_NAME "oss_input" +#define DEFAULT_DEVICE "/dev/dsp" + +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + + (u->source ? pa_idxset_size(u->source->outputs) : 0)); +} + +static void do_write(struct userdata *u) { + pa_memchunk *memchunk; + ssize_t r; + size_t l; + int loop = 0; + + assert(u); + + if (!u->sink || !pa_iochannel_is_writable(u->io)) + return; + + update_usage(u); + + l = u->out_fragment_size; + + if (u->use_getospace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) + u->use_getospace = 0; + else { + if (info.bytes/l > 0) { + l = (info.bytes/l)*l; + loop = 1; + } + } + } + + do { + memchunk = &u->memchunk; + + if (!memchunk->length) + if (pa_sink_render(u->sink, l, memchunk) < 0) + memchunk = &u->silence; + + assert(memchunk->memblock); + assert(memchunk->memblock->data); + assert(memchunk->length); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + break; + } + + if (memchunk == &u->silence) + assert(r % u->sample_size == 0); + else { + u->memchunk.index += r; + u->memchunk.length -= r; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + u->memchunk.memblock = NULL; + } + } + + l = l > (size_t) r ? l - r : 0; + } while (loop && l > 0); +} + +static void do_read(struct userdata *u) { + pa_memchunk memchunk; + ssize_t r; + size_t l; + int loop = 0; + assert(u); + + if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) + return; + + update_usage(u); + + l = u->in_fragment_size; + + if (u->use_getispace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) + u->use_getispace = 0; + else { + if (info.bytes/l > 0) { + l = (info.bytes/l)*l; + loop = 1; + } + } + } + + do { + memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) + pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + break; + } + + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; + memchunk.index = 0; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + l = l > (size_t) r ? l - r : 0; + } while (loop && l > 0); +} + +static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { + struct userdata *u = userdata; + assert(u); + do_write(u); + do_read(u); +} + +static void source_notify_cb(pa_source *s) { + struct userdata *u = s->userdata; + assert(u); + do_read(u); +} + +static pa_usec_t sink_get_latency_cb(pa_sink *s) { + pa_usec_t r = 0; + int arg; + struct userdata *u = s->userdata; + assert(s && u && u->sink); + + if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); + s->get_latency = NULL; + return 0; + } + + r += pa_bytes_to_usec(arg, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; +} + +static pa_usec_t source_get_latency_cb(pa_source *s) { + struct userdata *u = s->userdata; + audio_buf_info info; + assert(s && u && u->source); + + if (!u->use_getispace) + return 0; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + u->use_getispace = 0; + return 0; + } + + if (info.bytes <= 0) + return 0; + + return pa_bytes_to_usec(info.bytes, &s->sample_spec); +} + +static int sink_get_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; + + if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) + s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; + + pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + +static int sink_set_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; + + if (s->sample_spec.channels >= 2) + vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; + + if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + +int pa__init(pa_core *c, pa_module*m) { + struct audio_buf_info info; + struct userdata *u = NULL; + const char *p; + int fd = -1; + int nfrags, frag_size, in_frag_size, out_frag_size; + int mode; + int record = 1, playback = 1; + pa_sample_spec ss; + pa_modargs *ma = NULL; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": failed to parse module arguments.\n"); + goto fail; + } + + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { + pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + goto fail; + } + + if (!playback && !record) { + pa_log(__FILE__": neither playback nor record enabled for device.\n"); + goto fail; + } + + mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + + nfrags = 12; + frag_size = 1024; + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments\n"); + goto fail; + } + + ss = c->default_sample_spec; + if (pa_modargs_get_sample_spec(ma, &ss) < 0) { + pa_log(__FILE__": failed to parse sample specification\n"); + goto fail; + } + + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) + goto fail; + + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + + if (nfrags >= 2 && frag_size >= 1) + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; + + if (pa_oss_auto_format(fd, &ss) < 0) + goto fail; + + if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + goto fail; + } + assert(frag_size); + in_frag_size = out_frag_size = frag_size; + + u = pa_xmalloc(sizeof(struct userdata)); + u->core = c; + u->use_getospace = u->use_getispace = 0; + + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { + pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + in_frag_size = info.fragsize; + u->use_getispace = 1; + } + + if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { + pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + out_frag_size = info.fragsize; + u->use_getospace = 1; + } + + if (mode != O_WRONLY) { + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); + assert(u->source); + u->source->userdata = u; + u->source->notify = source_notify_cb; + u->source->get_latency = source_get_latency_cb; + pa_source_set_owner(u->source, m); + u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + } else + u->source = NULL; + + if (mode != O_RDONLY) { + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); + assert(u->sink); + u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; + u->sink->userdata = u; + pa_sink_set_owner(u->sink, m); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + } else + u->sink = NULL; + + assert(u->source || u->sink); + + u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); + assert(u->io); + pa_iochannel_set_callback(u->io, io_callback, u); + u->fd = fd; + + u->memchunk.memblock = NULL; + u->memchunk.length = 0; + u->sample_size = pa_frame_size(&ss); + + u->out_fragment_size = out_frag_size; + u->in_fragment_size = in_frag_size; + u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size, u->core->memblock_stat); + assert(u->silence.memblock); + pa_silence_memblock(u->silence.memblock, &ss); + u->silence.index = 0; + + u->module = m; + m->userdata = u; + + pa_modargs_free(ma); + + /* + * Some crappy drivers do not start the recording until we read something. + * Without this snippet, poll will never register the fd as ready. + */ + if (u->source) { + char buf[u->sample_size]; + read(u->fd, buf, u->sample_size); + } + + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume(u->sink); + + return 0; + +fail: + if (fd >= 0) + close(fd); + + if (ma) + pa_modargs_free(ma); + + return -1; +} + +void pa__done(pa_core *c, pa_module*m) { + struct userdata *u; + assert(c && m); + + if (!(u = m->userdata)) + return; + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } + + pa_iochannel_free(u->io); + pa_xfree(u); +} -- cgit From c75972f54a136eda05ab7cd87966526e026edc5a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 16 Feb 2006 22:08:06 +0000 Subject: move alsa-util.[ch], oss-util.[ch] and howl-wrap.[ch] to the modules directory since they are just helper source used exclusively by the modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@489 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 04458419..264e8792 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include "module-oss-symdef.h" +#include "oss-util.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") -- cgit From 5eda18bf608a325c136a450e58fa154eb0b270f4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 17 Feb 2006 12:10:58 +0000 Subject: Cleaned up the includes after the restructuring. Indicate which headers are public and which are internal through <> vs "". git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@500 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 264e8792..fe43c45e 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -45,8 +45,8 @@ #include #include -#include "module-oss-symdef.h" #include "oss-util.h" +#include "module-oss-symdef.h" PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") -- cgit From 893204fd5789acff9ca03fe4d46beec5d55a6aa4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 00:14:25 +0000 Subject: add hw volume control for module-oss-mmap git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@544 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index fe43c45e..34743a1d 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -255,41 +255,25 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - char cv[PA_CVOLUME_SNPRINT_MAX]; - unsigned vol; - if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { + if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); s->get_hw_volume = NULL; return -1; } - s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; - - if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) - s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; - - pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); return 0; } static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - char cv[PA_CVOLUME_SNPRINT_MAX]; - unsigned vol; - vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; - - if (s->sample_spec.channels >= 2) - vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; - - if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { + if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); s->set_hw_volume = NULL; return -1; } - pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); return 0; } -- cgit From 5014db91d55ce1b4f6b3691f6fd75078da588a40 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 21 Feb 2006 23:40:07 +0000 Subject: include hw description gathered from /dev/sndstat in sink/source description string git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@556 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 34743a1d..0a3c6143 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -287,7 +287,10 @@ int pa__init(pa_core *c, pa_module*m) { int record = 1, playback = 1; pa_sample_spec ss; pa_modargs *ma = NULL; - assert(c && m); + char hwdesc[64]; + + assert(c); + assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": failed to parse module arguments.\n"); @@ -322,6 +325,11 @@ int pa__init(pa_core *c, pa_module*m) { if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; + if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) + pa_log_info(__FILE__": hardware name is '%s'.\n", hwdesc); + else + hwdesc[0] = 0; + pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) @@ -361,7 +369,11 @@ int pa__init(pa_core *c, pa_module*m) { u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : ""); } else u->source = NULL; @@ -373,7 +385,11 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : ""); } else u->sink = NULL; -- cgit From 4a64b0d1167e980d81b798d813f35209895f0674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 23 Feb 2006 02:27:19 +0000 Subject: change pa_log() and friends to not require a trailing \n on all logged strings git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@574 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 0a3c6143..67ece5a7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -133,7 +133,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s\n", strerror(errno)); + pa_log(__FILE__": write() failed: %s", strerror(errno)); break; } @@ -186,7 +186,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s\n", strerror(errno)); + pa_log(__FILE__": read() failed: %s", strerror(errno)); break; } @@ -221,7 +221,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", strerror(errno)); s->get_latency = NULL; return 0; } @@ -257,7 +257,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -269,7 +269,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -293,17 +293,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments.\n"); + pa_log(__FILE__": failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument.\n"); + pa_log(__FILE__": record= and playback= expect numeric argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device.\n"); + pa_log(__FILE__": neither playback nor record enabled for device."); goto fail; } @@ -312,13 +312,13 @@ int pa__init(pa_core *c, pa_module*m) { nfrags = 12; frag_size = 1024; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments\n"); + pa_log(__FILE__": failed to parse fragments arguments"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification"); goto fail; } @@ -326,11 +326,11 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.\n", hwdesc); + pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) @@ -340,7 +340,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s\n", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", strerror(errno)); goto fail; } assert(frag_size); @@ -351,13 +351,13 @@ int pa__init(pa_core *c, pa_module*m) { u->use_getospace = u->use_getispace = 0; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": input -- %u fragments of size %u.", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize); + pa_log_info(__FILE__": output -- %u fragments of size %u.", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; u->use_getospace = 1; } -- cgit From ce9b035b7bf2af53bbfcabbc474e62f422224f87 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 23 Feb 2006 08:59:31 +0000 Subject: Hardware source volume support in OSS. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@578 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 67ece5a7..3a3f6b88 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -256,7 +256,7 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - if (pa_oss_get_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; @@ -268,7 +268,31 @@ static int sink_get_hw_volume(pa_sink *s) { static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; - if (pa_oss_set_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int source_get_hw_volume(pa_source *s) { + struct userdata *u = s->userdata; + + if (pa_oss_get_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + return 0; +} + +static int source_set_hw_volume(pa_source *s) { + struct userdata *u = s->userdata; + + if (pa_oss_set_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; @@ -368,6 +392,8 @@ int pa__init(pa_core *c, pa_module*m) { u->source->userdata = u; u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; + u->source->get_hw_volume = source_get_hw_volume; + u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", p, @@ -426,6 +452,8 @@ int pa__init(pa_core *c, pa_module*m) { } /* Read mixer settings */ + if (u->source) + source_get_hw_volume(u->source); if (u->sink) sink_get_hw_volume(u->sink); -- cgit From 3374df571d281caffcfa304fb27b2e49c8e509c8 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 24 Feb 2006 09:12:15 +0000 Subject: IGAIN is a better choice than IMIX for source volume. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@592 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 3a3f6b88..52427592 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -280,7 +280,7 @@ static int sink_set_hw_volume(pa_sink *s) { static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; - if (pa_oss_get_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); s->get_hw_volume = NULL; return -1; @@ -292,7 +292,7 @@ static int source_get_hw_volume(pa_source *s) { static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; - if (pa_oss_set_imix_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { + if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); s->set_hw_volume = NULL; return -1; -- cgit From 8f2d9aeb9544b128249c2126e561d10ff5d498ad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 10 Apr 2006 19:42:44 +0000 Subject: minor cleanups for OSS module git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@676 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 52427592..d9980d82 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -51,7 +51,17 @@ PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_DESCRIPTION("OSS Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) -PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") +PA_MODULE_USAGE( + "sink_name= " + "source_name= " + "device= " + "record= " + "playback= " + "format= " + "channels= " + "rate= " + "fragments= " + "fragment_size=") struct userdata { pa_sink *sink; @@ -85,6 +95,8 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "oss_output" #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" +#define DEFAULT_NFRAGS 12 +#define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { pa_module_set_used(u->module, @@ -332,9 +344,9 @@ int pa__init(pa_core *c, pa_module*m) { } mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - - nfrags = 12; - frag_size = 1024; + + nfrags = DEFAULT_NFRAGS; + frag_size = DEFAULT_FRAGSIZE; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log(__FILE__": failed to parse fragments arguments"); goto fail; @@ -387,8 +399,9 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); - assert(u->source); + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) + goto fail; + u->source->userdata = u; u->source->notify = source_notify_cb; u->source->get_latency = source_get_latency_cb; @@ -404,8 +417,9 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); - assert(u->sink); + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) + goto fail; + u->sink->get_latency = sink_get_latency_cb; u->sink->get_hw_volume = sink_get_hw_volume; u->sink->set_hw_volume = sink_set_hw_volume; @@ -471,7 +485,9 @@ fail: void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - assert(c && m); + + assert(c); + assert(m); if (!(u = m->userdata)) return; -- cgit From 746adcfed5dc396bc4820724b2e951369fc63aeb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Apr 2006 19:31:50 +0000 Subject: fix a couple of issues I found when compiling polypaudio with gcc 2.95 git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@754 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index d9980d82..ccc3c7d9 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -461,8 +461,9 @@ int pa__init(pa_core *c, pa_module*m) { * Without this snippet, poll will never register the fd as ready. */ if (u->source) { - char buf[u->sample_size]; + char *buf = pa_xnew(char, u->sample_size); read(u->fd, buf, u->sample_size); + pa_xfree(buf); } /* Read mixer settings */ -- cgit From 185a57cadd7b4e8e85c7fbecc866d7c279704e12 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 26 Apr 2006 15:40:14 +0000 Subject: support new channel_map argument in sink/source modules git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@803 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index ccc3c7d9..0795ae39 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -61,7 +61,8 @@ PA_MODULE_USAGE( "channels= " "rate= " "fragments= " - "fragment_size=") + "fragment_size= " + "channel_map=") struct userdata { pa_sink *sink; @@ -89,6 +90,7 @@ static const char* const valid_modargs[] = { "format", "rate", "channels", + "channel_map", NULL }; @@ -322,6 +324,7 @@ int pa__init(pa_core *c, pa_module*m) { int mode; int record = 1, playback = 1; pa_sample_spec ss; + pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64]; @@ -353,8 +356,8 @@ int pa__init(pa_core *c, pa_module*m) { } ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - pa_log(__FILE__": failed to parse sample specification"); + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } @@ -399,7 +402,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) goto fail; u->source->userdata = u; @@ -417,7 +420,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) goto fail; u->sink->get_latency = sink_get_latency_cb; -- cgit From 0f22d63289779931cfc3ddd3d2cdfb579e4be3c7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 13 May 2006 21:20:34 +0000 Subject: * set default fragment metrics depending on the sample specs of the device in OSS and ALSA * fix fragment size calculation in module-alsa-sink git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@855 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 0795ae39..4d811a76 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -97,8 +97,6 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "oss_output" #define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" -#define DEFAULT_NFRAGS 12 -#define DEFAULT_FRAGSIZE 1024 static void update_usage(struct userdata *u) { pa_module_set_used(u->module, @@ -348,19 +346,21 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - nfrags = DEFAULT_NFRAGS; - frag_size = DEFAULT_FRAGSIZE; - if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments"); - goto fail; - } - ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } + /* Fix latency to 100ms */ + nfrags = 12; + frag_size = pa_bytes_per_second(&ss)/128; + + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { + pa_log(__FILE__": failed to parse fragments arguments"); + goto fail; + } + if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) goto fail; -- cgit From 4b6ab291a787ff597c938842b569a35434ab11d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 May 2006 23:47:38 +0000 Subject: * modify pa_channel_map_init_auto() to take an extra argument specifying the standard to use (ALSA, AIFF, ...) * add some more validity checks to pa_source_new(),pa_sink_new(),pa_sink_input_new(),pa_source_output_new() git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@888 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 4d811a76..eab9a60a 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -347,7 +347,7 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } -- cgit From 270a409bf543f0ec7152f66e76d22445434aca4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 13:09:46 +0000 Subject: use PA_CHANNEL_MAP_OSS in module-oss, module-oss-mmap git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@896 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index eab9a60a..f6d19544 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -347,7 +347,7 @@ int pa__init(pa_core *c, pa_module*m) { mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); ss = c->default_sample_spec; - if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_ALSA) < 0) { + if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) { pa_log(__FILE__": failed to parse sample specification or channel map"); goto fail; } -- cgit From d9cc2cfcb97c1b0449bcbfb6ab0301a58d77bd55 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 17 May 2006 16:34:18 +0000 Subject: Move xmalloc to the public side (libpolyp). git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@908 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index f6d19544..46d100f1 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -35,6 +35,8 @@ #include #include +#include + #include #include #include @@ -42,7 +44,6 @@ #include #include #include -#include #include #include "oss-util.h" -- cgit From c47e937011f00eebab7230cedb58fd59f16487b4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 May 2006 20:09:57 +0000 Subject: split polypcore/util.[ch] into polypcore/core-util.[ch] and polyp/util.[ch] git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@917 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 46d100f1..9233420d 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include -- cgit From 4e3dc7ce68561c16254712d713b2ccd472b8afe7 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 22 May 2006 15:20:46 +0000 Subject: Wrap strerror() in a function that makes it thread safe and converts the output to UTF-8. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@945 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 9233420d..8e217855 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -146,7 +147,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s", strerror(errno)); + pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); break; } @@ -199,7 +200,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) - pa_log(__FILE__": read() failed: %s", strerror(errno)); + pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); break; } @@ -234,7 +235,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); s->get_latency = NULL; return 0; } @@ -270,7 +271,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -282,7 +283,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -294,7 +295,7 @@ static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -306,7 +307,7 @@ static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", strerror(errno)); + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -380,7 +381,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", strerror(errno)); + pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } assert(frag_size); -- cgit From 4413b89d7a45587b545a31463ad2196767f45563 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 25 May 2006 17:16:55 +0000 Subject: * split pa_cstrerror() into its own file polypcore/core-error.[ch] * fix building of padsp * remove a warning when compiling padsp.c git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@972 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 8e217855..88724673 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -35,9 +35,9 @@ #include #include -#include #include +#include #include #include #include -- cgit From f44ba092651aa75055e109e04b4164ea92ae7fdc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jun 2006 21:53:48 +0000 Subject: big s/polyp/pulse/g git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1033 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 88724673..5a80661e 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -1,20 +1,20 @@ /* $Id$ */ /*** - This file is part of polypaudio. + This file is part of PulseAudio. - polypaudio is free software; you can redistribute it and/or modify + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - polypaudio is distributed in the hope that it will be useful, but + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License - along with polypaudio; if not, write to the Free Software + along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ @@ -35,17 +35,17 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "oss-util.h" #include "module-oss-symdef.h" -- cgit From 860be2e70b33ff5eeb9130f80c4b1c096a2a8f27 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 14 Jul 2006 22:42:01 +0000 Subject: try to use send(,,MSG_NOSIGNAL) instead of write() wherever possible (which will allow us to drop the SIGPIPE check). Cache the results of the last write()/send() to make sure that we do not issue more than necessary system calls. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1083 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 5a80661e..a3ea2c1f 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -467,7 +467,7 @@ int pa__init(pa_core *c, pa_module*m) { */ if (u->source) { char *buf = pa_xnew(char, u->sample_size); - read(u->fd, buf, u->sample_size); + pa_read(u->fd, buf, u->sample_size, NULL); pa_xfree(buf); } -- cgit From b91dd2381bffeb0a4b5450ef4ce1f0031909f79a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 16 Jul 2006 17:28:41 +0000 Subject: set is_hardware flag for a few hw plugins git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1092 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index a3ea2c1f..cde7f311 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -418,6 +418,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); + u->source->is_hardware = 1; } else u->source = NULL; @@ -435,6 +436,7 @@ int pa__init(pa_core *c, pa_module*m) { hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", hwdesc[0] ? ")" : ""); + u->sink->is_hardware = 1; } else u->sink = NULL; -- cgit From bfff23db10db9fe6370f8bfbc8498d2057030a0d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 17:14:35 +0000 Subject: shorten sink/source device descriptions a little git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1201 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index cde7f311..c9fce7a7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -413,7 +413,7 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + u->source->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", @@ -431,7 +431,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'%s%s%s", + u->sink->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", -- cgit From bfa6604b1ddc5e2c0f1aaa15330363724856359b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 11 Aug 2006 23:58:55 +0000 Subject: don't set the sink/source descriptions manually, use the new functions pa_{sink,source}_set_description() instead git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1205 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index c9fce7a7..085ae5da 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -326,7 +326,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; - char hwdesc[64]; + char hwdesc[64], *t; assert(c); assert(m); @@ -413,11 +413,12 @@ int pa__init(pa_core *c, pa_module*m) { u->source->get_hw_volume = source_get_hw_volume; u->source->set_hw_volume = source_set_hw_volume; pa_source_set_owner(u->source, m); - u->source->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : ""); + pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "")); + pa_xfree(t); u->source->is_hardware = 1; } else u->source = NULL; @@ -431,11 +432,12 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - u->sink->description = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : ""); + pa_sink_set_description(u->sink, pa_sprintf_malloc("OSS PCM on %s%s%s%s", + p, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "")); + pa_xfree(t); u->sink->is_hardware = 1; } else u->sink = NULL; -- cgit From 7fa074480687dff06723b7078c8146aae5eec61a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 13:17:33 +0000 Subject: fix a segfault in module-oss git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1216 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 085ae5da..5ce74151 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -432,7 +432,7 @@ int pa__init(pa_core *c, pa_module*m) { u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, pa_sprintf_malloc("OSS PCM on %s%s%s%s", + pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", p, hwdesc[0] ? " (" : "", hwdesc[0] ? hwdesc : "", -- cgit From 4c9c4269bb70aad6c7a62ed7f73867087f4af217 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:02:26 +0000 Subject: handle hot-remeving of OSS devices properly git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1221 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 5ce74151..c3972680 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -107,6 +107,27 @@ static void update_usage(struct userdata *u) { (u->source ? pa_idxset_size(u->source->outputs) : 0)); } +static void clear_up(struct userdata *u) { + assert(u); + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); + u->sink = NULL; + } + + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + u->source = NULL; + } + + if (u->io) { + pa_iochannel_free(u->io); + u->io = NULL; + } +} + static void do_write(struct userdata *u) { pa_memchunk *memchunk; ssize_t r; @@ -148,6 +169,9 @@ static void do_write(struct userdata *u) { if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); break; } @@ -199,8 +223,11 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); - if (errno != EAGAIN) + if (errno != EAGAIN) { pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + clear_up(u); + pa_module_unload_request(u->module); + } break; } @@ -501,22 +528,13 @@ void pa__done(pa_core *c, pa_module*m) { if (!(u = m->userdata)) return; + + clear_up(u); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) pa_memblock_unref(u->silence.memblock); - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - } - - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - } - - pa_iochannel_free(u->io); pa_xfree(u); } -- cgit From bf79e9759112abfa7be5d01de807b24a68038d26 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 16:26:59 +0000 Subject: generate default sink/source names from the device files they belong to git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1223 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index c3972680..89a8152b 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -96,8 +97,6 @@ static const char* const valid_modargs[] = { NULL }; -#define DEFAULT_SINK_NAME "oss_output" -#define DEFAULT_SOURCE_NAME "oss_input" #define DEFAULT_DEVICE "/dev/dsp" static void update_usage(struct userdata *u) { @@ -354,6 +353,9 @@ int pa__init(pa_core *c, pa_module*m) { pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64], *t; + const char *name; + char *name_buf = NULL; + int namereg_fail; assert(c); assert(m); @@ -431,7 +433,14 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map))) + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); + namereg_fail = 0; + } + + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; u->source->userdata = u; @@ -450,8 +459,18 @@ int pa__init(pa_core *c, pa_module*m) { } else u->source = NULL; + pa_xfree(name_buf); + name_buf = NULL; + if (mode != O_RDONLY) { - if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) + if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) + namereg_fail = 1; + else { + name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); + namereg_fail = 0; + } + + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; u->sink->get_latency = sink_get_latency_cb; @@ -469,6 +488,9 @@ int pa__init(pa_core *c, pa_module*m) { } else u->sink = NULL; + pa_xfree(name_buf); + name_buf = NULL; + assert(u->source || u->sink); u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); @@ -516,6 +538,8 @@ fail: if (ma) pa_modargs_free(ma); + + pa_xfree(name_buf); return -1; } -- cgit From dbe6bdd2bcd035b0b07d70811593be719c5cc7c0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 12 Aug 2006 17:06:05 +0000 Subject: make use of pa_sink_used_by()/pa_source_used_by() wherever applicable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1227 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 89a8152b..ce11ee02 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -100,10 +100,9 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "/dev/dsp" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_idxset_size(u->sink->inputs) : 0) + - (u->sink ? pa_idxset_size(u->sink->monitor_source->outputs) : 0) + - (u->source ? pa_idxset_size(u->source->outputs) : 0)); + pa_module_set_used(u->module, + (u->sink ? pa_sink_used_by(u->sink) : 0) + + (u->source ? pa_source_used_by(u->source) : 0)); } static void clear_up(struct userdata *u) { -- cgit From 0e436a6926af56f37a74a03bb5e143e078ca0d55 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 19:55:18 +0000 Subject: Rework memory management to allow shared memory data transfer. The central idea is to allocate all audio memory blocks from a per-process memory pool which is available as read-only SHM segment to other local processes. Then, instead of writing the actual audio data to the socket just write references to this shared memory pool. To work optimally all memory blocks should now be of type PA_MEMBLOCK_POOL or PA_MEMBLOCK_POOL_EXTERNAL. The function pa_memblock_new() now generates memory blocks of this type by default. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1266 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index ce11ee02..b9b80e72 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -217,7 +217,7 @@ static void do_read(struct userdata *u) { } do { - memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat); + memchunk.memblock = pa_memblock_new(u->core->mempool, l); assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); @@ -503,7 +503,7 @@ int pa__init(pa_core *c, pa_module*m) { u->out_fragment_size = out_frag_size; u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->silence.length = u->out_fragment_size, u->core->memblock_stat); + u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = u->out_fragment_size); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; -- cgit From e385d93e5aad6a6fce754c00c804ff1d6a6746d4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 18 Aug 2006 21:38:40 +0000 Subject: remove all occurences of pa_logXXX(__FILE__": and replace them by pa_logXXX(" git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1272 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b9b80e72..b71581d9 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -166,7 +166,7 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log(__FILE__": write() failed: %s", pa_cstrerror(errno)); + pa_log("write() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); @@ -222,7 +222,7 @@ static void do_read(struct userdata *u) { if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) { - pa_log(__FILE__": read() failed: %s", pa_cstrerror(errno)); + pa_log("read() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); } @@ -260,7 +260,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); s->get_latency = NULL; return 0; } @@ -296,7 +296,7 @@ static int sink_get_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -308,7 +308,7 @@ static int sink_set_hw_volume(pa_sink *s) { struct userdata *u = s->userdata; if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -320,7 +320,7 @@ static int source_get_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); s->get_hw_volume = NULL; return -1; } @@ -332,7 +332,7 @@ static int source_set_hw_volume(pa_source *s) { struct userdata *u = s->userdata; if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info(__FILE__": device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); s->set_hw_volume = NULL; return -1; } @@ -360,17 +360,17 @@ int pa__init(pa_core *c, pa_module*m) { assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log(__FILE__": failed to parse module arguments."); + pa_log("failed to parse module arguments."); goto fail; } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log(__FILE__": record= and playback= expect numeric argument."); + pa_log("record= and playback= expect numeric argument."); goto fail; } if (!playback && !record) { - pa_log(__FILE__": neither playback nor record enabled for device."); + pa_log("neither playback nor record enabled for device."); goto fail; } @@ -378,7 +378,7 @@ int pa__init(pa_core *c, pa_module*m) { ss = c->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) { - pa_log(__FILE__": failed to parse sample specification or channel map"); + pa_log("failed to parse sample specification or channel map"); goto fail; } @@ -387,7 +387,7 @@ int pa__init(pa_core *c, pa_module*m) { frag_size = pa_bytes_per_second(&ss)/128; if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log(__FILE__": failed to parse fragments arguments"); + pa_log("failed to parse fragments arguments"); goto fail; } @@ -395,11 +395,11 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info(__FILE__": hardware name is '%s'.", hwdesc); + pa_log_info("hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - pa_log_info(__FILE__": device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) @@ -409,7 +409,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { - pa_log(__FILE__": SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); + pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } assert(frag_size); @@ -420,13 +420,13 @@ int pa__init(pa_core *c, pa_module*m) { u->use_getospace = u->use_getispace = 0; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info(__FILE__": input -- %u fragments of size %u.", info.fragstotal, info.fragsize); + pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info(__FILE__": output -- %u fragments of size %u.", info.fragstotal, info.fragsize); + pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); out_frag_size = info.fragsize; u->use_getospace = 1; } -- cgit From d210ebbb09daddb2c8c8e8e77243e088b0b19c4d Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 26 Sep 2006 23:50:56 +0000 Subject: rework memory block management to be thread-safe and mostly lock-free. pa_memblock is now an opaque structure. Access to its fields is now done through various accessor functions in a thread-safe manner. pa_memblock_acquire() and pa_memblock_release() are now used to access the attached audio data. Why? To allow safe manipulation of the memory pointer maintained by the memory block. Internally _acquire() and _release() maintain a reference counter. Please do not confuse this reference counter whith the one maintained by pa_memblock_ref()/_unref()! As a side effect this patch removes all direct usages of AO_t and replaces it with pa_atomic_xxx based code. This stuff needs some serious testing love. Especially if threads are actively used. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1404 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b71581d9..73f0d57e 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -155,6 +155,7 @@ static void do_write(struct userdata *u) { } do { + void *p; memchunk = &u->memchunk; if (!memchunk->length) @@ -162,16 +163,18 @@ static void do_write(struct userdata *u) { memchunk = &u->silence; assert(memchunk->memblock); - assert(memchunk->memblock->data); assert(memchunk->length); - - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + + p = pa_memblock_acquire(memchunk->memblock); + if ((r = pa_iochannel_write(u->io, (uint8_t*) p + memchunk->index, memchunk->length)) < 0) { + pa_memblock_release(memchunk->memblock); pa_log("write() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); break; } + pa_memblock_release(memchunk->memblock); if (memchunk == &u->silence) assert(r % u->sample_size == 0); @@ -217,9 +220,13 @@ static void do_read(struct userdata *u) { } do { + void *p; memchunk.memblock = pa_memblock_new(u->core->mempool, l); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { + + p = pa_memblock_acquire(memchunk.memblock); + + if ((r = pa_iochannel_read(u->io, p, pa_memblock_get_length(memchunk.memblock))) < 0) { + pa_memblock_release(memchunk.memblock); pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); @@ -228,9 +235,10 @@ static void do_read(struct userdata *u) { } break; } + pa_memblock_release(memchunk.memblock); - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; + assert(r <= (ssize_t) pa_memblock_get_length(memchunk.memblock)); + memchunk.length = r; memchunk.index = 0; pa_source_post(u->source, &memchunk); -- cgit From 8dc62142765249addf131b058c27f931ede1776b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 6 Nov 2006 13:06:01 +0000 Subject: Revert r1404 and keep it on a development branch until it is fully tested. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1409 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 73f0d57e..b71581d9 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -155,7 +155,6 @@ static void do_write(struct userdata *u) { } do { - void *p; memchunk = &u->memchunk; if (!memchunk->length) @@ -163,18 +162,16 @@ static void do_write(struct userdata *u) { memchunk = &u->silence; assert(memchunk->memblock); + assert(memchunk->memblock->data); assert(memchunk->length); - - p = pa_memblock_acquire(memchunk->memblock); - if ((r = pa_iochannel_write(u->io, (uint8_t*) p + memchunk->index, memchunk->length)) < 0) { - pa_memblock_release(memchunk->memblock); + + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); clear_up(u); pa_module_unload_request(u->module); break; } - pa_memblock_release(memchunk->memblock); if (memchunk == &u->silence) assert(r % u->sample_size == 0); @@ -220,13 +217,9 @@ static void do_read(struct userdata *u) { } do { - void *p; memchunk.memblock = pa_memblock_new(u->core->mempool, l); - - p = pa_memblock_acquire(memchunk.memblock); - - if ((r = pa_iochannel_read(u->io, p, pa_memblock_get_length(memchunk.memblock))) < 0) { - pa_memblock_release(memchunk.memblock); + assert(memchunk.memblock); + if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); @@ -235,10 +228,9 @@ static void do_read(struct userdata *u) { } break; } - pa_memblock_release(memchunk.memblock); - assert(r <= (ssize_t) pa_memblock_get_length(memchunk.memblock)); - memchunk.length = r; + assert(r <= (ssize_t) memchunk.memblock->length); + memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; pa_source_post(u->source, &memchunk); -- cgit From 521daf6f0ac4fa6a2fbfb5d523c0c743342dca2b Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jan 2007 13:43:45 +0000 Subject: Huge trailing whitespace cleanup. Let's keep the tree pure from here on, mmmkay? git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1418 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 70 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 35 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b71581d9..b8ced86f 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -2,17 +2,17 @@ /*** This file is part of PulseAudio. - + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 @@ -100,20 +100,20 @@ static const char* const valid_modargs[] = { #define DEFAULT_DEVICE "/dev/dsp" static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, + pa_module_set_used(u->module, (u->sink ? pa_sink_used_by(u->sink) : 0) + (u->source ? pa_source_used_by(u->source) : 0)); } static void clear_up(struct userdata *u) { assert(u); - + if (u->sink) { pa_sink_disconnect(u->sink); pa_sink_unref(u->sink); u->sink = NULL; } - + if (u->source) { pa_source_disconnect(u->source); pa_source_unref(u->source); @@ -131,7 +131,7 @@ static void do_write(struct userdata *u) { ssize_t r; size_t l; int loop = 0; - + assert(u); if (!u->sink || !pa_iochannel_is_writable(u->io)) @@ -140,10 +140,10 @@ static void do_write(struct userdata *u) { update_usage(u); l = u->out_fragment_size; - + if (u->use_getospace) { audio_buf_info info; - + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) u->use_getospace = 0; else { @@ -156,15 +156,15 @@ static void do_write(struct userdata *u) { do { memchunk = &u->memchunk; - + if (!memchunk->length) if (pa_sink_render(u->sink, l, memchunk) < 0) memchunk = &u->silence; - + assert(memchunk->memblock); assert(memchunk->memblock->data); assert(memchunk->length); - + if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { pa_log("write() failed: %s", pa_cstrerror(errno)); @@ -172,13 +172,13 @@ static void do_write(struct userdata *u) { pa_module_unload_request(u->module); break; } - + if (memchunk == &u->silence) assert(r % u->sample_size == 0); else { u->memchunk.index += r; u->memchunk.length -= r; - + if (u->memchunk.length <= 0) { pa_memblock_unref(u->memchunk.memblock); u->memchunk.memblock = NULL; @@ -195,7 +195,7 @@ static void do_read(struct userdata *u) { size_t l; int loop = 0; assert(u); - + if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) return; @@ -205,7 +205,7 @@ static void do_read(struct userdata *u) { if (u->use_getispace) { audio_buf_info info; - + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) u->use_getispace = 0; else { @@ -215,7 +215,7 @@ static void do_read(struct userdata *u) { } } } - + do { memchunk.memblock = pa_memblock_new(u->core->mempool, l); assert(memchunk.memblock); @@ -228,11 +228,11 @@ static void do_read(struct userdata *u) { } break; } - + assert(r <= (ssize_t) memchunk.memblock->length); memchunk.length = memchunk.memblock->length = r; memchunk.index = 0; - + pa_source_post(u->source, &memchunk); pa_memblock_unref(memchunk.memblock); @@ -280,12 +280,12 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { if (!u->use_getispace) return 0; - + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { u->use_getispace = 0; return 0; } - + if (info.bytes <= 0) return 0; @@ -355,7 +355,7 @@ int pa__init(pa_core *c, pa_module*m) { const char *name; char *name_buf = NULL; int namereg_fail; - + assert(c); assert(m); @@ -363,7 +363,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse module arguments."); goto fail; } - + if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { pa_log("record= and playback= expect numeric argument."); goto fail; @@ -381,11 +381,11 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("failed to parse sample specification or channel map"); goto fail; } - + /* Fix latency to 100ms */ nfrags = 12; frag_size = pa_bytes_per_second(&ss)/128; - + if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { pa_log("failed to parse fragments arguments"); goto fail; @@ -398,12 +398,12 @@ int pa__init(pa_core *c, pa_module*m) { pa_log_info("hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - + pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) - if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) - goto fail; + if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) + goto fail; if (pa_oss_auto_format(fd, &ss) < 0) goto fail; @@ -418,7 +418,7 @@ int pa__init(pa_core *c, pa_module*m) { u = pa_xmalloc(sizeof(struct userdata)); u->core = c; u->use_getospace = u->use_getispace = 0; - + if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); in_frag_size = info.fragsize; @@ -438,7 +438,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); namereg_fail = 0; } - + if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; @@ -468,7 +468,7 @@ int pa__init(pa_core *c, pa_module*m) { name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); namereg_fail = 0; } - + if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) goto fail; @@ -489,7 +489,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_xfree(name_buf); name_buf = NULL; - + assert(u->source || u->sink); u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); @@ -539,13 +539,13 @@ fail: pa_modargs_free(ma); pa_xfree(name_buf); - + return -1; } void pa__done(pa_core *c, pa_module*m) { struct userdata *u; - + assert(c); assert(m); @@ -553,7 +553,7 @@ void pa__done(pa_core *c, pa_module*m) { return; clear_up(u); - + if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); if (u->silence.memblock) -- cgit From 06211b7c8fd329137ae9003818543912a87d9898 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Tue, 13 Feb 2007 15:35:19 +0000 Subject: Add copyright notices to all relevant files. (based on svn log) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1426 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index b8ced86f..965944a7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -3,6 +3,9 @@ /*** This file is part of PulseAudio. + Copyright 2004-2006 Lennart Poettering + Copyright 2006 Pierre Ossman for Cendio AB + PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, -- cgit From 312c326def9b4cc20642ea8f2692d4f2da1406ad Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 23 May 2007 01:02:06 +0000 Subject: Fix module-oss for devices that return EAGAIN when we don't expect it. (Closes #66) git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1442 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 965944a7..22b12ef7 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -169,10 +169,14 @@ static void do_write(struct userdata *u) { assert(memchunk->length); if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { - pa_log("write() failed: %s", pa_cstrerror(errno)); - clear_up(u); - pa_module_unload_request(u->module); + if (errno != EAGAIN) { + pa_log("write() failed: %s", pa_cstrerror(errno)); + + clear_up(u); + pa_module_unload_request(u->module); + } + break; } @@ -224,11 +228,14 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); + if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); + clear_up(u); pa_module_unload_request(u->module); } + break; } -- cgit From 1e12e0ee8dfdda1632b9c082aba6fc1956813a5b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 May 2007 17:24:48 +0000 Subject: Kill spaces on EOL git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1465 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 22b12ef7..9d4d0eac 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -172,11 +172,11 @@ static void do_write(struct userdata *u) { if (errno != EAGAIN) { pa_log("write() failed: %s", pa_cstrerror(errno)); - + clear_up(u); pa_module_unload_request(u->module); } - + break; } @@ -228,14 +228,14 @@ static void do_read(struct userdata *u) { assert(memchunk.memblock); if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { pa_memblock_unref(memchunk.memblock); - + if (errno != EAGAIN) { pa_log("read() failed: %s", pa_cstrerror(errno)); - + clear_up(u); pa_module_unload_request(u->module); } - + break; } -- cgit From a67c21f093202f142438689d3f7cfbdf4ea82eea Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 28 Oct 2007 19:13:50 +0000 Subject: merge 'lennart' branch back into trunk. git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1971 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 1469 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 1197 insertions(+), 272 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 9d4d0eac..19dceef2 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -22,27 +22,46 @@ USA. ***/ +/* General power management rules: + * + * When SUSPENDED we close the audio device. + * + * We make no difference between IDLE and RUNNING in our handling. + * + * As long as we are in RUNNING/IDLE state we will *always* write data to + * the device. If none is avilable from the inputs, we write silence + * instead. + * + * If power should be saved on IDLE module-suspend-on-idle should be used. + * + */ + #ifdef HAVE_CONFIG_H #include #endif +#ifdef HAVE_SYS_MMAN_H +#include +#endif + #include #include #include #include #include -#include #include #include #include #include #include +#include +#include #include #include #include -#include +#include #include #include #include @@ -50,6 +69,9 @@ #include #include #include +#include +#include +#include #include "oss-util.h" #include "module-oss-symdef.h" @@ -68,21 +90,48 @@ PA_MODULE_USAGE( "rate= " "fragments= " "fragment_size= " - "channel_map=") + "channel_map= " + "mmap=") + +#define DEFAULT_DEVICE "/dev/dsp" struct userdata { + pa_core *core; + pa_module *module; pa_sink *sink; pa_source *source; - pa_iochannel *io; - pa_core *core; - pa_memchunk memchunk, silence; + pa_thread *thread; + pa_thread_mq thread_mq; + pa_rtpoll *rtpoll; + + char *device_name; + + pa_memchunk memchunk; - uint32_t in_fragment_size, out_fragment_size, sample_size; - int use_getospace, use_getispace; + size_t frame_size; + uint32_t in_fragment_size, out_fragment_size, in_nfrags, out_nfrags, in_hwbuf_size, out_hwbuf_size; + pa_bool_t use_getospace, use_getispace; + pa_bool_t use_getodelay; + + pa_bool_t sink_suspended, source_suspended; int fd; - pa_module *module; + int mode; + + int mixer_fd; + int mixer_devmask; + + int nfrags, frag_size; + + pa_bool_t use_mmap; + unsigned out_mmap_current, in_mmap_current; + void *in_mmap, *out_mmap; + pa_memblock **in_mmap_memblocks, **out_mmap_memblocks; + + int in_mmap_saved_nfrags, out_mmap_saved_nfrags; + + pa_rtpoll_item *rtpoll_item; }; static const char* const valid_modargs[] = { @@ -97,280 +146,1010 @@ static const char* const valid_modargs[] = { "rate", "channels", "channel_map", + "mmap", NULL }; -#define DEFAULT_DEVICE "/dev/dsp" +static void trigger(struct userdata *u, pa_bool_t quick) { + int enable_bits = 0, zero = 0; -static void update_usage(struct userdata *u) { - pa_module_set_used(u->module, - (u->sink ? pa_sink_used_by(u->sink) : 0) + - (u->source ? pa_source_used_by(u->source) : 0)); -} + pa_assert(u); -static void clear_up(struct userdata *u) { - assert(u); + if (u->fd < 0) + return; - if (u->sink) { - pa_sink_disconnect(u->sink); - pa_sink_unref(u->sink); - u->sink = NULL; - } + pa_log_debug("trigger"); - if (u->source) { - pa_source_disconnect(u->source); - pa_source_unref(u->source); - u->source = NULL; - } + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) + enable_bits |= PCM_ENABLE_INPUT; - if (u->io) { - pa_iochannel_free(u->io); - u->io = NULL; - } -} + if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) + enable_bits |= PCM_ENABLE_OUTPUT; -static void do_write(struct userdata *u) { - pa_memchunk *memchunk; - ssize_t r; - size_t l; - int loop = 0; + pa_log_debug("trigger: %i", enable_bits); - assert(u); - if (!u->sink || !pa_iochannel_is_writable(u->io)) - return; + if (u->use_mmap) { - update_usage(u); + if (!quick) + ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero); - l = u->out_fragment_size; +#ifdef SNDCTL_DSP_HALT + if (enable_bits == 0) + if (ioctl(u->fd, SNDCTL_DSP_HALT, NULL) < 0) + pa_log_warn("SNDCTL_DSP_HALT: %s", pa_cstrerror(errno)); +#endif - if (u->use_getospace) { - audio_buf_info info; + if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) + pa_log_warn("SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno)); - if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) - u->use_getospace = 0; - else { - if (info.bytes/l > 0) { - l = (info.bytes/l)*l; - loop = 1; + if (u->sink && !(enable_bits & PCM_ENABLE_OUTPUT)) { + pa_log_debug("clearing playback buffer"); + pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &u->sink->sample_spec); + } + + } else { + + if (enable_bits) + if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0) + pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno)); + + if (!quick) { + /* + * Some crappy drivers do not start the recording until we + * read something. Without this snippet, poll will never + * register the fd as ready. + */ + + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) { + uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size); + pa_read(u->fd, buf, u->in_fragment_size, NULL); + pa_xfree(buf); } } } +} - do { - memchunk = &u->memchunk; +static void mmap_fill_memblocks(struct userdata *u, unsigned n) { + pa_assert(u); + pa_assert(u->out_mmap_memblocks); - if (!memchunk->length) - if (pa_sink_render(u->sink, l, memchunk) < 0) - memchunk = &u->silence; +/* pa_log("Mmmap writing %u blocks", n); */ - assert(memchunk->memblock); - assert(memchunk->memblock->data); - assert(memchunk->length); + while (n > 0) { + pa_memchunk chunk; - if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) { + if (u->out_mmap_memblocks[u->out_mmap_current]) + pa_memblock_unref_fixed(u->out_mmap_memblocks[u->out_mmap_current]); - if (errno != EAGAIN) { - pa_log("write() failed: %s", pa_cstrerror(errno)); + chunk.memblock = u->out_mmap_memblocks[u->out_mmap_current] = + pa_memblock_new_fixed( + u->core->mempool, + (uint8_t*) u->out_mmap + u->out_fragment_size * u->out_mmap_current, + u->out_fragment_size, + 1); - clear_up(u); - pa_module_unload_request(u->module); - } + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; - break; - } + pa_sink_render_into_full(u->sink, &chunk); - if (memchunk == &u->silence) - assert(r % u->sample_size == 0); - else { - u->memchunk.index += r; - u->memchunk.length -= r; + u->out_mmap_current++; + while (u->out_mmap_current >= u->out_nfrags) + u->out_mmap_current -= u->out_nfrags; - if (u->memchunk.length <= 0) { - pa_memblock_unref(u->memchunk.memblock); - u->memchunk.memblock = NULL; - } - } + n--; + } +} + +static int mmap_write(struct userdata *u) { + struct count_info info; + + pa_assert(u); + pa_assert(u->sink); + +/* pa_log("Mmmap writing..."); */ + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + return -1; + } + + info.blocks += u->out_mmap_saved_nfrags; + u->out_mmap_saved_nfrags = 0; + + if (info.blocks > 0) + mmap_fill_memblocks(u, info.blocks); - l = l > (size_t) r ? l - r : 0; - } while (loop && l > 0); + return info.blocks; } -static void do_read(struct userdata *u) { - pa_memchunk memchunk; - ssize_t r; - size_t l; - int loop = 0; - assert(u); +static void mmap_post_memblocks(struct userdata *u, unsigned n) { + pa_assert(u); + pa_assert(u->in_mmap_memblocks); - if (!u->source || !pa_iochannel_is_readable(u->io) || !pa_idxset_size(u->source->outputs)) - return; +/* pa_log("Mmmap reading %u blocks", n); */ - update_usage(u); + while (n > 0) { + pa_memchunk chunk; - l = u->in_fragment_size; + if (!u->in_mmap_memblocks[u->in_mmap_current]) { - if (u->use_getispace) { - audio_buf_info info; + chunk.memblock = u->in_mmap_memblocks[u->in_mmap_current] = + pa_memblock_new_fixed( + u->core->mempool, + (uint8_t*) u->in_mmap + u->in_fragment_size*u->in_mmap_current, + u->in_fragment_size, + 1); - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) - u->use_getispace = 0; - else { - if (info.bytes/l > 0) { - l = (info.bytes/l)*l; - loop = 1; - } + chunk.length = pa_memblock_get_length(chunk.memblock); + chunk.index = 0; + + pa_source_post(u->source, &chunk); } + + u->in_mmap_current++; + while (u->in_mmap_current >= u->in_nfrags) + u->in_mmap_current -= u->in_nfrags; + + n--; } +} - do { - memchunk.memblock = pa_memblock_new(u->core->mempool, l); - assert(memchunk.memblock); - if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) { - pa_memblock_unref(memchunk.memblock); +static void mmap_clear_memblocks(struct userdata*u, unsigned n) { + unsigned i = u->in_mmap_current; - if (errno != EAGAIN) { - pa_log("read() failed: %s", pa_cstrerror(errno)); + pa_assert(u); + pa_assert(u->in_mmap_memblocks); - clear_up(u); - pa_module_unload_request(u->module); - } + if (n > u->in_nfrags) + n = u->in_nfrags; - break; + while (n > 0) { + if (u->in_mmap_memblocks[i]) { + pa_memblock_unref_fixed(u->in_mmap_memblocks[i]); + u->in_mmap_memblocks[i] = NULL; } - assert(r <= (ssize_t) memchunk.memblock->length); - memchunk.length = memchunk.memblock->length = r; - memchunk.index = 0; + i++; + while (i >= u->in_nfrags) + i -= u->in_nfrags; - pa_source_post(u->source, &memchunk); - pa_memblock_unref(memchunk.memblock); + n--; + } +} - l = l > (size_t) r ? l - r : 0; - } while (loop && l > 0); +static int mmap_read(struct userdata *u) { + struct count_info info; + pa_assert(u); + pa_assert(u->source); + +/* pa_log("Mmmap reading..."); */ + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + return -1; + } + +/* pa_log("... %i", info.blocks); */ + + info.blocks += u->in_mmap_saved_nfrags; + u->in_mmap_saved_nfrags = 0; + + if (info.blocks > 0) { + mmap_post_memblocks(u, info.blocks); + mmap_clear_memblocks(u, u->in_nfrags/2); + } + + return info.blocks; } -static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void*userdata) { - struct userdata *u = userdata; - assert(u); - do_write(u); - do_read(u); +static pa_usec_t mmap_sink_get_latency(struct userdata *u) { + struct count_info info; + size_t bpos, n; + + pa_assert(u); + + if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno)); + return 0; + } + + u->out_mmap_saved_nfrags += info.blocks; + + bpos = ((u->out_mmap_current + u->out_mmap_saved_nfrags) * u->out_fragment_size) % u->out_hwbuf_size; + + if (bpos <= (size_t) info.ptr) + n = u->out_hwbuf_size - (info.ptr - bpos); + else + n = bpos - info.ptr; + +/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->out_fragment_size, u->out_fragments); */ + + return pa_bytes_to_usec(n, &u->sink->sample_spec); } -static void source_notify_cb(pa_source *s) { - struct userdata *u = s->userdata; - assert(u); - do_read(u); +static pa_usec_t mmap_source_get_latency(struct userdata *u) { + struct count_info info; + size_t bpos, n; + + pa_assert(u); + + if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) { + pa_log("SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno)); + return 0; + } + + u->in_mmap_saved_nfrags += info.blocks; + bpos = ((u->in_mmap_current + u->in_mmap_saved_nfrags) * u->in_fragment_size) % u->in_hwbuf_size; + + if (bpos <= (size_t) info.ptr) + n = info.ptr - bpos; + else + n = u->in_hwbuf_size - bpos + info.ptr; + +/* pa_log("n = %u, bpos = %u, ptr = %u, total=%u, fragsize = %u, n_frags = %u\n", n, bpos, (unsigned) info.ptr, total, u->in_fragment_size, u->in_fragments); */ + + return pa_bytes_to_usec(n, &u->source->sample_spec); } -static pa_usec_t sink_get_latency_cb(pa_sink *s) { +static pa_usec_t io_sink_get_latency(struct userdata *u) { pa_usec_t r = 0; - int arg; - struct userdata *u = s->userdata; - assert(s && u && u->sink); - if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info("device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); - s->get_latency = NULL; - return 0; + pa_assert(u); + + if (u->use_getodelay) { + int arg; + + if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETODELAY: %s", pa_cstrerror(errno)); + u->use_getodelay = 0; + } else + r = pa_bytes_to_usec(arg, &u->sink->sample_spec); + } - r += pa_bytes_to_usec(arg, &s->sample_spec); + if (!u->use_getodelay && u->use_getospace) { + struct audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); + u->use_getospace = 0; + } else + r = pa_bytes_to_usec(info.bytes, &u->sink->sample_spec); + } if (u->memchunk.memblock) - r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + r += pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec); return r; } -static pa_usec_t source_get_latency_cb(pa_source *s) { - struct userdata *u = s->userdata; - audio_buf_info info; - assert(s && u && u->source); - if (!u->use_getispace) - return 0; +static pa_usec_t io_source_get_latency(struct userdata *u) { + pa_usec_t r = 0; - if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { - u->use_getispace = 0; - return 0; + pa_assert(u); + + if (u->use_getispace) { + struct audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); + u->use_getispace = 0; + } else + r = pa_bytes_to_usec(info.bytes, &u->source->sample_spec); } - if (info.bytes <= 0) - return 0; + return r; +} + +static void build_pollfd(struct userdata *u) { + struct pollfd *pollfd; - return pa_bytes_to_usec(info.bytes, &s->sample_spec); + pa_assert(u); + pa_assert(u->fd >= 0); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->fd = u->fd; + pollfd->events = 0; + pollfd->revents = 0; } -static int sink_get_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; +static int suspend(struct userdata *u) { + pa_assert(u); + pa_assert(u->fd >= 0); - if (pa_oss_get_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); - s->get_hw_volume = NULL; - return -1; + pa_log_info("Suspending..."); + + if (u->out_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->out_nfrags; i++) + if (u->out_mmap_memblocks[i]) { + pa_memblock_unref_fixed(u->out_mmap_memblocks[i]); + u->out_mmap_memblocks[i] = NULL; + } } + if (u->in_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->in_nfrags; i++) + if (u->in_mmap_memblocks[i]) { + pa_memblock_unref_fixed(u->in_mmap_memblocks[i]); + u->in_mmap_memblocks[i] = NULL; + } + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) { + munmap(u->in_mmap, u->in_hwbuf_size); + u->in_mmap = NULL; + } + + if (u->out_mmap && u->out_mmap != MAP_FAILED) { + munmap(u->out_mmap, u->out_hwbuf_size); + u->out_mmap = NULL; + } + + /* Let's suspend */ + ioctl(u->fd, SNDCTL_DSP_SYNC, NULL); + pa_close(u->fd); + u->fd = -1; + + if (u->rtpoll_item) { + pa_rtpoll_item_free(u->rtpoll_item); + u->rtpoll_item = NULL; + } + + pa_log_info("Device suspended..."); + return 0; } -static int sink_set_hw_volume(pa_sink *s) { - struct userdata *u = s->userdata; +static int unsuspend(struct userdata *u) { + int m; + pa_sample_spec ss, *ss_original; + int frag_size, in_frag_size, out_frag_size; + int in_nfrags, out_nfrags; + struct audio_buf_info info; + + pa_assert(u); + pa_assert(u->fd < 0); + + m = u->mode; + + pa_log_info("Trying resume..."); - if (pa_oss_set_pcm_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); - s->set_hw_volume = NULL; + if ((u->fd = pa_oss_open(u->device_name, &m, NULL)) < 0) { + pa_log_warn("Resume failed, device busy (%s)", pa_cstrerror(errno)); return -1; + + if (m != u->mode) + pa_log_warn("Resume failed, couldn't open device with original access mode."); + goto fail; + } + + if (u->nfrags >= 2 && u->frag_size >= 1) + if (pa_oss_set_fragments(u->fd, u->nfrags, u->frag_size) < 0) { + pa_log_warn("Resume failed, couldn't set original fragment settings."); + goto fail; + } + + ss = *(ss_original = u->sink ? &u->sink->sample_spec : &u->source->sample_spec); + if (pa_oss_auto_format(u->fd, &ss) < 0 || !pa_sample_spec_equal(&ss, ss_original)) { + pa_log_warn("Resume failed, couldn't set original sample format settings."); + goto fail; + } + + if (ioctl(u->fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) < 0) { + pa_log_warn("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); + goto fail; + } + + in_frag_size = out_frag_size = frag_size; + in_nfrags = out_nfrags = u->nfrags; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { + in_frag_size = info.fragsize; + in_nfrags = info.fragstotal; + } + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { + out_frag_size = info.fragsize; + out_nfrags = info.fragstotal; + } + + if ((u->source && (in_frag_size != (int) u->in_fragment_size || in_nfrags != (int) u->in_nfrags)) || + (u->sink && (out_frag_size != (int) u->out_fragment_size || out_nfrags != (int) u->out_nfrags))) { + pa_log_warn("Resume failed, input fragment settings don't match."); + goto fail; + } + + if (u->use_mmap) { + if (u->source) { + if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno)); + goto fail; + } + } + + if (u->sink) { + if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, u->fd, 0)) == MAP_FAILED) { + pa_log("Resume failed, mmap(): %s", pa_cstrerror(errno)); + if (u->in_mmap && u->in_mmap != MAP_FAILED) { + munmap(u->in_mmap, u->in_hwbuf_size); + u->in_mmap = NULL; + } + + goto fail; + } + + pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss); + } } + u->out_mmap_current = u->in_mmap_current = 0; + u->out_mmap_saved_nfrags = u->in_mmap_saved_nfrags = 0; + + pa_assert(!u->rtpoll_item); + + build_pollfd(u); + + if (u->sink) + pa_sink_get_volume(u->sink); + if (u->source) + pa_source_get_volume(u->source); + + pa_log_info("Resumed successfully..."); + return 0; + +fail: + pa_close(u->fd); + u->fd = -1; + return -1; } -static int source_get_hw_volume(pa_source *s) { - struct userdata *u = s->userdata; +static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SINK(o)->userdata; + int ret; + pa_bool_t do_trigger = FALSE, quick = TRUE; + + switch (code) { + + case PA_SINK_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->fd >= 0) { + if (u->use_mmap) + r = mmap_sink_get_latency(u); + else + r = io_sink_get_latency(u); + } + + *((pa_usec_t*) data) = r; + + return 0; + } + + case PA_SINK_MESSAGE_SET_STATE: + + switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) { + + case PA_SINK_SUSPENDED: + pa_assert(PA_SINK_OPENED(u->sink->thread_info.state)); + + if (!u->source || u->source_suspended) { + if (suspend(u) < 0) + return -1; + } + + do_trigger = TRUE; + + u->sink_suspended = TRUE; + break; + + case PA_SINK_IDLE: + case PA_SINK_RUNNING: + + if (u->sink->thread_info.state == PA_SINK_INIT) { + do_trigger = TRUE; + quick = u->source && PA_SOURCE_OPENED(u->source->thread_info.state); + } + + if (u->sink->thread_info.state == PA_SINK_SUSPENDED) { + + if (!u->source || u->source_suspended) { + if (unsuspend(u) < 0) + return -1; + quick = FALSE; + } + + do_trigger = TRUE; + + u->out_mmap_current = 0; + u->out_mmap_saved_nfrags = 0; + + u->sink_suspended = FALSE; + } + + break; + + case PA_SINK_UNLINKED: + case PA_SINK_INIT: + ; + } + + break; - if (pa_oss_get_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); - s->get_hw_volume = NULL; - return -1; } - return 0; + ret = pa_sink_process_msg(o, code, data, offset, chunk); + + if (do_trigger) + trigger(u, quick); + + return ret; } -static int source_set_hw_volume(pa_source *s) { - struct userdata *u = s->userdata; +static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { + struct userdata *u = PA_SOURCE(o)->userdata; + int ret; + int do_trigger = FALSE, quick = TRUE; + + switch (code) { + + case PA_SOURCE_MESSAGE_GET_LATENCY: { + pa_usec_t r = 0; + + if (u->fd >= 0) { + if (u->use_mmap) + r = mmap_source_get_latency(u); + else + r = io_source_get_latency(u); + } + + *((pa_usec_t*) data) = r; + return 0; + } + + case PA_SOURCE_MESSAGE_SET_STATE: + + switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) { + case PA_SOURCE_SUSPENDED: + pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state)); + + if (!u->sink || u->sink_suspended) { + if (suspend(u) < 0) + return -1; + } + + do_trigger = TRUE; + + u->source_suspended = TRUE; + break; + + case PA_SOURCE_IDLE: + case PA_SOURCE_RUNNING: + + if (u->source->thread_info.state == PA_SOURCE_INIT) { + do_trigger = TRUE; + quick = u->sink && PA_SINK_OPENED(u->sink->thread_info.state); + } + + if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) { + + if (!u->sink || u->sink_suspended) { + if (unsuspend(u) < 0) + return -1; + quick = FALSE; + } + + do_trigger = TRUE; + + u->in_mmap_current = 0; + u->in_mmap_saved_nfrags = 0; + + u->source_suspended = FALSE; + } + break; + + case PA_SOURCE_UNLINKED: + case PA_SOURCE_INIT: + ; + + } + break; - if (pa_oss_set_input_volume(u->fd, &s->sample_spec, &s->hw_volume) < 0) { - pa_log_info("device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); - s->set_hw_volume = NULL; - return -1; } - return 0; + ret = pa_source_process_msg(o, code, data, offset, chunk); + + if (do_trigger) + trigger(u, quick); + + return ret; +} + +static int sink_get_volume(pa_sink *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); + + if (u->mixer_devmask & SOUND_MASK_VOLUME) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_PCM) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + return -1; +} + +static int sink_set_volume(pa_sink *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); + + if (u->mixer_devmask & SOUND_MASK_VOLUME) + if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_PCM) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + return -1; } -int pa__init(pa_core *c, pa_module*m) { +static int source_get_volume(pa_source *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); + + if (u->mixer_devmask & SOUND_MASK_IGAIN) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_RECLEV) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); + return -1; +} + +static int source_set_volume(pa_source *s) { + struct userdata *u; + int r; + + pa_assert_se(u = s->userdata); + + pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); + + if (u->mixer_devmask & SOUND_MASK_IGAIN) + if ((r = pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->volume)) >= 0) + return r; + + if (u->mixer_devmask & SOUND_MASK_RECLEV) + if ((r = pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->volume)) >= 0) + return r; + + pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + return -1; +} + +static void thread_func(void *userdata) { + struct userdata *u = userdata; + int write_type = 0, read_type = 0; + unsigned short revents = 0; + + pa_assert(u); + + pa_log_debug("Thread starting up"); + + if (u->core->high_priority) + pa_make_realtime(); + + pa_thread_mq_install(&u->thread_mq); + pa_rtpoll_install(u->rtpoll); + + for (;;) { + int ret; + +/* pa_log("loop"); */ + + /* Render some data and write it to the dsp */ + + if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) { + + if (u->use_mmap) { + + if ((ret = mmap_write(u)) < 0) + goto fail; + + revents &= ~POLLOUT; + + if (ret > 0) + continue; + + } else { + ssize_t l; + pa_bool_t loop = FALSE, work_done = FALSE; + + l = u->out_fragment_size; + + if (u->use_getospace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno)); + u->use_getospace = FALSE; + } else { + l = info.bytes; + + /* We loop only if GETOSPACE worked and we + * actually *know* that we can write more than + * one fragment at a time */ + loop = TRUE; + } + } + + /* Round down to multiples of the fragment size, + * because OSS needs that (at least some versions + * do) */ + l = (l/u->out_fragment_size) * u->out_fragment_size; + + /* Hmm, so poll() signalled us that we can read + * something, but GETOSPACE told us there was nothing? + * Hmm, make the best of it, try to read some data, to + * avoid spinning forever. */ + if (l <= 0 && (revents & POLLOUT)) { + l = u->out_fragment_size; + loop = FALSE; + } + + while (l > 0) { + void *p; + ssize_t t; + + if (u->memchunk.length <= 0) + pa_sink_render(u->sink, l, &u->memchunk); + + pa_assert(u->memchunk.length > 0); + + p = pa_memblock_acquire(u->memchunk.memblock); + t = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type); + pa_memblock_release(u->memchunk.memblock); + +/* pa_log("wrote %i bytes of %u", t, l); */ + + pa_assert(t != 0); + + if (t < 0) { + + if (errno == EINTR) + continue; + + else if (errno == EAGAIN) { + pa_log_debug("EAGAIN"); + + revents &= ~POLLOUT; + break; + + } else { + pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + + u->memchunk.index += t; + u->memchunk.length -= t; + + if (u->memchunk.length <= 0) { + pa_memblock_unref(u->memchunk.memblock); + pa_memchunk_reset(&u->memchunk); + } + + l -= t; + + revents &= ~POLLOUT; + work_done = TRUE; + } + + if (!loop) + break; + } + + if (work_done) + continue; + } + } + + /* Try to read some data and pass it on to the source driver. */ + + if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) { + + if (u->use_mmap) { + + if ((ret = mmap_read(u)) < 0) + goto fail; + + revents &= ~POLLIN; + + if (ret > 0) + continue; + + } else { + + void *p; + ssize_t l; + pa_memchunk memchunk; + pa_bool_t loop = FALSE, work_done = FALSE; + + l = u->in_fragment_size; + + if (u->use_getispace) { + audio_buf_info info; + + if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) { + pa_log_info("Device doesn't support SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno)); + u->use_getispace = FALSE; + } else { + l = info.bytes; + loop = TRUE; + } + } + + l = (l/u->in_fragment_size) * u->in_fragment_size; + + if (l <= 0 && (revents & POLLIN)) { + l = u->in_fragment_size; + loop = FALSE; + } + + while (l > 0) { + ssize_t t, k; + + pa_assert(l > 0); + + memchunk.memblock = pa_memblock_new(u->core->mempool, (size_t) -1); + + k = pa_memblock_get_length(memchunk.memblock); + + if (k > l) + k = l; + + k = (k/u->frame_size)*u->frame_size; + + p = pa_memblock_acquire(memchunk.memblock); + t = pa_read(u->fd, p, k, &read_type); + pa_memblock_release(memchunk.memblock); + + pa_assert(t != 0); /* EOF cannot happen */ + +/* pa_log("read %i bytes of %u", t, l); */ + + if (t < 0) { + pa_memblock_unref(memchunk.memblock); + + if (errno == EINTR) + continue; + + else if (errno == EAGAIN) { + pa_log_debug("EAGAIN"); + + revents &= ~POLLIN; + break; + + } else { + pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno)); + goto fail; + } + + } else { + memchunk.index = 0; + memchunk.length = t; + + pa_source_post(u->source, &memchunk); + pa_memblock_unref(memchunk.memblock); + + l -= t; + + revents &= ~POLLIN; + work_done = TRUE; + } + + if (!loop) + break; + } + + if (work_done) + continue; + } + } + +/* pa_log("loop2 revents=%i", revents); */ + + if (u->rtpoll_item) { + struct pollfd *pollfd; + + pa_assert(u->fd >= 0); + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + pollfd->events = + ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0) | + ((u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0); + } + + /* Hmm, nothing to do. Let's sleep */ + if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) + goto fail; + + if (ret == 0) + goto finish; + + if (u->rtpoll_item) { + struct pollfd *pollfd; + + pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); + + if (pollfd->revents & ~(POLLOUT|POLLIN)) { + pa_log("DSP shutdown."); + goto fail; + } + + revents = pollfd->revents; + } else + revents = 0; + } + +fail: + /* If this was no regular exit from the loop we have to continue + * processing messages until we received PA_MESSAGE_SHUTDOWN */ + pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); + pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); + +finish: + pa_log_debug("Thread shutting down"); +} + +int pa__init(pa_module*m) { + struct audio_buf_info info; struct userdata *u = NULL; - const char *p; + const char *dev; int fd = -1; - int nfrags, frag_size, in_frag_size, out_frag_size; - int mode; - int record = 1, playback = 1; + int nfrags, frag_size; + int mode, caps; + int record = 1, playback = 1, use_mmap = 1; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; char hwdesc[64], *t; const char *name; - char *name_buf = NULL; int namereg_fail; - assert(c); - assert(m); + pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - pa_log("failed to parse module arguments."); + pa_log("Failed to parse module arguments."); goto fail; } @@ -380,36 +1159,52 @@ int pa__init(pa_core *c, pa_module*m) { } if (!playback && !record) { - pa_log("neither playback nor record enabled for device."); + pa_log("Neither playback nor record enabled for device."); goto fail; } - mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); + mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0)); - ss = c->default_sample_spec; + ss = m->core->default_sample_spec; if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_OSS) < 0) { - pa_log("failed to parse sample specification or channel map"); + pa_log("Failed to parse sample specification or channel map"); goto fail; } - /* Fix latency to 100ms */ - nfrags = 12; - frag_size = pa_bytes_per_second(&ss)/128; + nfrags = m->core->default_n_fragments; + frag_size = pa_usec_to_bytes(m->core->default_fragment_size_msec*1000, &ss); + if (frag_size <= 0) + frag_size = pa_frame_size(&ss); if (pa_modargs_get_value_s32(ma, "fragments", &nfrags) < 0 || pa_modargs_get_value_s32(ma, "fragment_size", &frag_size) < 0) { - pa_log("failed to parse fragments arguments"); + pa_log("Failed to parse fragments arguments"); goto fail; } - if ((fd = pa_oss_open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, NULL)) < 0) + if (pa_modargs_get_value_boolean(ma, "mmap", &use_mmap) < 0) { + pa_log("Failed to parse mmap argument."); goto fail; + } - if (pa_oss_get_hw_description(p, hwdesc, sizeof(hwdesc)) >= 0) - pa_log_info("hardware name is '%s'.", hwdesc); + if ((fd = pa_oss_open(dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), &mode, &caps)) < 0) + goto fail; + + if (use_mmap && (!(caps & DSP_CAP_MMAP) || !(caps & DSP_CAP_TRIGGER))) { + pa_log_info("OSS device not mmap capable, falling back to UNIX read/write mode."); + use_mmap = 0; + } + + if (use_mmap && mode == O_WRONLY) { + pa_log_info("Device opened for playback only, cannot do memory mapping, falling back to UNIX write() mode."); + use_mmap = 0; + } + + if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0) + pa_log_info("Hardware name is '%s'.", hwdesc); else hwdesc[0] = 0; - pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); + pa_log_info("Device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) @@ -422,152 +1217,282 @@ int pa__init(pa_core *c, pa_module*m) { pa_log("SNDCTL_DSP_GETBLKSIZE: %s", pa_cstrerror(errno)); goto fail; } - assert(frag_size); - in_frag_size = out_frag_size = frag_size; + pa_assert(frag_size > 0); - u = pa_xmalloc(sizeof(struct userdata)); - u->core = c; - u->use_getospace = u->use_getispace = 0; + u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + m->userdata = u; + u->fd = fd; + u->mixer_fd = -1; + u->use_getospace = u->use_getispace = 1; + u->use_getodelay = 1; + u->mode = mode; + u->frame_size = pa_frame_size(&ss); + u->device_name = pa_xstrdup(dev); + u->in_nfrags = u->out_nfrags = u->nfrags = nfrags; + u->out_fragment_size = u->in_fragment_size = u->frag_size = frag_size; + u->use_mmap = use_mmap; + pa_thread_mq_init(&u->thread_mq, m->core->mainloop); + u->rtpoll = pa_rtpoll_new(); + pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq); + u->rtpoll_item = NULL; + build_pollfd(u); if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) { - pa_log_info("input -- %u fragments of size %u.", info.fragstotal, info.fragsize); - in_frag_size = info.fragsize; + pa_log_info("Input -- %u fragments of size %u.", info.fragstotal, info.fragsize); + u->in_fragment_size = info.fragsize; + u->in_nfrags = info.fragstotal; u->use_getispace = 1; } if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) { - pa_log_info("output -- %u fragments of size %u.", info.fragstotal, info.fragsize); - out_frag_size = info.fragsize; + pa_log_info("Output -- %u fragments of size %u.", info.fragstotal, info.fragsize); + u->out_fragment_size = info.fragsize; + u->out_nfrags = info.fragstotal; u->use_getospace = 1; } + u->in_hwbuf_size = u->in_nfrags * u->in_fragment_size; + u->out_hwbuf_size = u->out_nfrags * u->out_fragment_size; + if (mode != O_WRONLY) { + char *name_buf = NULL; + + if (use_mmap) { + if ((u->in_mmap = mmap(NULL, u->in_hwbuf_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { + pa_log_warn("mmap(PROT_READ) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno)); + use_mmap = u->use_mmap = 0; + u->in_mmap = NULL; + } else + pa_log_debug("Successfully mmap()ed input buffer."); + } + if ((name = pa_modargs_get_value(ma, "source_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(p)); + name = name_buf = pa_sprintf_malloc("oss_input.%s", pa_path_get_filename(dev)); namereg_fail = 0; } - if (!(u->source = pa_source_new(c, __FILE__, name, namereg_fail, &ss, &map))) + u->source = pa_source_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + if (!u->source) { + pa_log("Failed to create source object"); goto fail; + } + u->source->parent.process_msg = source_process_msg; u->source->userdata = u; - u->source->notify = source_notify_cb; - u->source->get_latency = source_get_latency_cb; - u->source->get_hw_volume = source_get_hw_volume; - u->source->set_hw_volume = source_set_hw_volume; - pa_source_set_owner(u->source, m); - pa_source_set_description(u->source, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : "")); + + pa_source_set_module(u->source, m); + pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); + pa_source_set_rtpoll(u->source, u->rtpoll); + pa_source_set_description(u->source, t = pa_sprintf_malloc( + "OSS PCM on %s%s%s%s%s", + dev, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "", + use_mmap ? " via DMA" : "")); pa_xfree(t); - u->source->is_hardware = 1; - } else - u->source = NULL; + u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY; + u->source->refresh_volume = TRUE; - pa_xfree(name_buf); - name_buf = NULL; + if (use_mmap) + u->in_mmap_memblocks = pa_xnew0(pa_memblock*, u->in_nfrags); + } if (mode != O_RDONLY) { + char *name_buf = NULL; + + if (use_mmap) { + if ((u->out_mmap = mmap(NULL, u->out_hwbuf_size, PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) { + if (mode == O_RDWR) { + pa_log_debug("mmap() failed for input. Changing to O_WRONLY mode."); + mode = O_WRONLY; + goto go_on; + } else { + pa_log_warn("mmap(PROT_WRITE) failed, reverting to non-mmap mode: %s", pa_cstrerror(errno)); + u->use_mmap = (use_mmap = FALSE); + u->out_mmap = NULL; + } + } else { + pa_log_debug("Successfully mmap()ed output buffer."); + pa_silence_memory(u->out_mmap, u->out_hwbuf_size, &ss); + } + } + if ((name = pa_modargs_get_value(ma, "sink_name", NULL))) namereg_fail = 1; else { - name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(p)); + name = name_buf = pa_sprintf_malloc("oss_output.%s", pa_path_get_filename(dev)); namereg_fail = 0; } - if (!(u->sink = pa_sink_new(c, __FILE__, name, namereg_fail, &ss, &map))) + u->sink = pa_sink_new(m->core, __FILE__, name, namereg_fail, &ss, &map); + pa_xfree(name_buf); + if (!u->sink) { + pa_log("Failed to create sink object"); goto fail; + } - u->sink->get_latency = sink_get_latency_cb; - u->sink->get_hw_volume = sink_get_hw_volume; - u->sink->set_hw_volume = sink_set_hw_volume; + u->sink->parent.process_msg = sink_process_msg; u->sink->userdata = u; - pa_sink_set_owner(u->sink, m); - pa_sink_set_description(u->sink, t = pa_sprintf_malloc("OSS PCM on %s%s%s%s", - p, - hwdesc[0] ? " (" : "", - hwdesc[0] ? hwdesc : "", - hwdesc[0] ? ")" : "")); + + pa_sink_set_module(u->sink, m); + pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); + pa_sink_set_rtpoll(u->sink, u->rtpoll); + pa_sink_set_description(u->sink, t = pa_sprintf_malloc( + "OSS PCM on %s%s%s%s%s", + dev, + hwdesc[0] ? " (" : "", + hwdesc[0] ? hwdesc : "", + hwdesc[0] ? ")" : "", + use_mmap ? " via DMA" : "")); pa_xfree(t); - u->sink->is_hardware = 1; - } else - u->sink = NULL; + u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY; + u->sink->refresh_volume = TRUE; - pa_xfree(name_buf); - name_buf = NULL; + if (use_mmap) + u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags); + } - assert(u->source || u->sink); + if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) { + int do_close = 1; + u->mixer_devmask = 0; - u->io = pa_iochannel_new(c->mainloop, u->source ? fd : -1, u->sink ? fd : -1); - assert(u->io); - pa_iochannel_set_callback(u->io, io_callback, u); - u->fd = fd; + if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0) + pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno)); - u->memchunk.memblock = NULL; - u->memchunk.length = 0; - u->sample_size = pa_frame_size(&ss); + else { + if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) { + pa_log_debug("Found hardware mixer track for playback."); + u->sink->flags |= PA_SINK_HW_VOLUME_CTRL; + u->sink->get_volume = sink_get_volume; + u->sink->set_volume = sink_set_volume; + do_close = 0; + } - u->out_fragment_size = out_frag_size; - u->in_fragment_size = in_frag_size; - u->silence.memblock = pa_memblock_new(u->core->mempool, u->silence.length = u->out_fragment_size); - assert(u->silence.memblock); - pa_silence_memblock(u->silence.memblock, &ss); - u->silence.index = 0; + if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) { + pa_log_debug("Found hardware mixer track for recording."); + u->source->flags |= PA_SOURCE_HW_VOLUME_CTRL; + u->source->get_volume = source_get_volume; + u->source->set_volume = source_set_volume; + do_close = 0; + } + } - u->module = m; - m->userdata = u; + if (do_close) { + pa_close(u->mixer_fd); + u->mixer_fd = -1; + } + } - pa_modargs_free(ma); +go_on: + + pa_assert(u->source || u->sink); - /* - * Some crappy drivers do not start the recording until we read something. - * Without this snippet, poll will never register the fd as ready. - */ - if (u->source) { - char *buf = pa_xnew(char, u->sample_size); - pa_read(u->fd, buf, u->sample_size, NULL); - pa_xfree(buf); + pa_memchunk_reset(&u->memchunk); + + if (!(u->thread = pa_thread_new(thread_func, u))) { + pa_log("Failed to create thread."); + goto fail; } /* Read mixer settings */ - if (u->source) - source_get_hw_volume(u->source); + if (u->sink && u->sink->get_volume) + sink_get_volume(u->sink); + if (u->source && u->source->get_volume) + source_get_volume(u->source); + if (u->sink) - sink_get_hw_volume(u->sink); + pa_sink_put(u->sink); + if (u->source) + pa_source_put(u->source); + + pa_modargs_free(ma); return 0; fail: - if (fd >= 0) - close(fd); + + if (u) + pa__done(m); + else if (fd >= 0) + pa_close(fd); if (ma) pa_modargs_free(ma); - pa_xfree(name_buf); - return -1; } -void pa__done(pa_core *c, pa_module*m) { +void pa__done(pa_module*m) { struct userdata *u; - assert(c); - assert(m); + pa_assert(m); if (!(u = m->userdata)) return; - clear_up(u); + if (u->sink) + pa_sink_unlink(u->sink); + + if (u->source) + pa_source_unlink(u->source); + + if (u->thread) { + pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); + pa_thread_free(u->thread); + } + + pa_thread_mq_done(&u->thread_mq); + + if (u->sink) + pa_sink_unref(u->sink); + + if (u->source) + pa_source_unref(u->source); if (u->memchunk.memblock) pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); + + if (u->rtpoll_item) + pa_rtpoll_item_free(u->rtpoll_item); + + if (u->rtpoll) + pa_rtpoll_free(u->rtpoll); + + if (u->out_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->out_nfrags; i++) + if (u->out_mmap_memblocks[i]) + pa_memblock_unref_fixed(u->out_mmap_memblocks[i]); + pa_xfree(u->out_mmap_memblocks); + } + + if (u->in_mmap_memblocks) { + unsigned i; + for (i = 0; i < u->in_nfrags; i++) + if (u->in_mmap_memblocks[i]) + pa_memblock_unref_fixed(u->in_mmap_memblocks[i]); + pa_xfree(u->in_mmap_memblocks); + } + + if (u->in_mmap && u->in_mmap != MAP_FAILED) + munmap(u->in_mmap, u->in_hwbuf_size); + + if (u->out_mmap && u->out_mmap != MAP_FAILED) + munmap(u->out_mmap, u->out_hwbuf_size); + + if (u->fd >= 0) + pa_close(u->fd); + + if (u->mixer_fd >= 0) + pa_close(u->mixer_fd); + + pa_xfree(u->device_name); pa_xfree(u); } -- cgit From 7bfd1b2f01613dd14b9ca478ae530c1641aa46a1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 1 Nov 2007 02:58:26 +0000 Subject: make rtprio and nice level actually configurable git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2014 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 19dceef2..51ab8a85 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -863,8 +863,8 @@ static void thread_func(void *userdata) { pa_log_debug("Thread starting up"); - if (u->core->high_priority) - pa_make_realtime(); + if (u->core->realtime_scheduling) + pa_make_realtime(u->core->realtime_priority); pa_thread_mq_install(&u->thread_mq); pa_rtpoll_install(u->rtpoll); -- cgit From e313fe1b3d0d9f9945c41c151d72edbe9cf1ec54 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 9 Nov 2007 18:25:40 +0000 Subject: tag modules that may only be loaded once at most especially, and enforce that in the module loader git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2043 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 51ab8a85..a44ad083 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -76,9 +76,10 @@ #include "oss-util.h" #include "module-oss-symdef.h" -PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("OSS Sink/Source") -PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_AUTHOR("Lennart Poettering"); +PA_MODULE_DESCRIPTION("OSS Sink/Source"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(FALSE); PA_MODULE_USAGE( "sink_name= " "source_name= " @@ -91,7 +92,7 @@ PA_MODULE_USAGE( "fragments= " "fragment_size= " "channel_map= " - "mmap=") + "mmap="); #define DEFAULT_DEVICE "/dev/dsp" -- cgit From d17bb53d3ebfbd7046719400264bd87830c140d8 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 13 Nov 2007 17:37:44 +0000 Subject: Completely rework ALSA device selection code: choose the device to open depending on the requested number of channels and channel map. In most cases it will now suffice to set default-channels=6 to enable 5.1 sound for all devices that support it git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2050 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index a44ad083..8352a790 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -1139,7 +1139,7 @@ int pa__init(pa_module*m) { int fd = -1; int nfrags, frag_size; int mode, caps; - int record = 1, playback = 1, use_mmap = 1; + pa_bool_t record = TRUE, playback = TRUE, use_mmap = TRUE; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma = NULL; -- cgit From 4ac6b53478be63ae5d0163a330e67e4134f17f89 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 21 Nov 2007 01:21:53 +0000 Subject: minor typo fix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2066 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/modules/module-oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/modules/module-oss.c') diff --git a/src/modules/module-oss.c b/src/modules/module-oss.c index 8352a790..a7df8a0c 100644 --- a/src/modules/module-oss.c +++ b/src/modules/module-oss.c @@ -1155,7 +1155,7 @@ int pa__init(pa_module*m) { } if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) { - pa_log("record= and playback= expect numeric argument."); + pa_log("record= and playback= expect boolean argument."); goto fail; } -- cgit