#include <limits.h>
#include <sys/mman.h>
+#include <polyp/xmalloc.h>
+
+#include <polypcore/core-error.h>
#include <polypcore/iochannel.h>
#include <polypcore/sink.h>
#include <polypcore/source.h>
#include <polypcore/module.h>
#include <polypcore/sample-util.h>
-#include <polypcore/util.h>
+#include <polypcore/core-util.h>
#include <polypcore/modargs.h>
-#include <polypcore/xmalloc.h>
#include <polypcore/log.h>
#include "oss-util.h"
"channels=<number of channels> "
"rate=<sample rate> "
"fragments=<number of fragments> "
- "fragment_size=<fragment size>")
+ "fragment_size=<fragment size> "
+ "channel_map=<channel map>")
struct userdata {
pa_sink *sink;
pa_core *core;
pa_sample_spec sample_spec;
- size_t in_fragment_size, out_fragment_size, in_fragments, out_fragments;
- int out_blocks_saved, in_blocks_saved;
+ size_t in_fragment_size, out_fragment_size;
+ unsigned in_fragments, out_fragments;
+ unsigned out_blocks_saved, in_blocks_saved;
int fd;
"format",
"rate",
"channels",
+ "channel_map",
NULL
};
if (u->out_memblocks[u->out_current])
pa_memblock_unref_fixed(u->out_memblocks[u->out_current]);
- chunk.memblock = u->out_memblocks[u->out_current] = pa_memblock_new_fixed((uint8_t*)u->out_mmap+u->out_fragment_size*u->out_current, u->out_fragment_size, 1, u->core->memblock_stat);
+ chunk.memblock = u->out_memblocks[u->out_current] =
+ pa_memblock_new_fixed(
+ (uint8_t*) u->out_mmap+u->out_fragment_size*u->out_current,
+ u->out_fragment_size,
+ 1,
+ u->core->memblock_stat);
assert(chunk.memblock);
chunk.length = chunk.memblock->length;
chunk.index = 0;
update_usage(u);
if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
return;
}
update_usage(u);
if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
return;
}
static pa_usec_t sink_get_latency_cb(pa_sink *s) {
struct userdata *u = s->userdata;
struct count_info info;
- size_t bpos, n;
+ size_t bpos, n, total;
assert(s && u);
if (ioctl(u->fd, SNDCTL_DSP_GETOPTR, &info) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_GETOPTR: %s", pa_cstrerror(errno));
return 0;
}
u->out_blocks_saved += info.blocks;
- bpos = ((u->out_current + u->out_blocks_saved) % u->out_fragments) * u->out_fragment_size;
+ total = u->out_fragments * u->out_fragment_size;
+ bpos = ((u->out_current + u->out_blocks_saved) * u->out_fragment_size) % total;
- if (bpos < (size_t) info.ptr)
- n = (u->out_fragments * u->out_fragment_size) - (info.ptr - bpos);
+ if (bpos <= (size_t) info.ptr)
+ n = total - (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, &s->sample_spec);
}
static pa_usec_t source_get_latency_cb(pa_source *s) {
struct userdata *u = s->userdata;
struct count_info info;
- size_t bpos, n;
+ size_t bpos, n, total;
assert(s && u);
if (ioctl(u->fd, SNDCTL_DSP_GETIPTR, &info) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_GETIPTR: %s", pa_cstrerror(errno));
return 0;
}
u->in_blocks_saved += info.blocks;
- bpos = ((u->in_current + u->in_blocks_saved) % u->in_fragments) * u->in_fragment_size;
+ total = u->in_fragments * u->in_fragment_size;
+ bpos = ((u->in_current + u->in_blocks_saved) * u->in_fragment_size) % total;
- if (bpos < (size_t) info.ptr)
+ if (bpos <= (size_t) info.ptr)
n = info.ptr - bpos;
else
n = (u->in_fragments * u->in_fragment_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, &s->sample_spec);
}
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;
}
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;
}
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;
}
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;
}
int playback = 1, record = 1;
pa_modargs *ma = NULL;
char hwdesc[64];
-
+ pa_channel_map map;
+
assert(c);
assert(m);
}
u->sample_spec = c->default_sample_spec;
- if (pa_modargs_get_sample_spec(ma, &u->sample_spec) < 0) {
- pa_log(__FILE__": failed to parse sample specification");
+ if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &map, PA_CHANNEL_MAP_OSS) < 0) {
+ pa_log(__FILE__": failed to parse sample specification or channel map");
goto fail;
}
if (mode != O_WRONLY) {
if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_GETISPACE: %s", pa_cstrerror(errno));
goto fail;
}
pa_log(__FILE__": mmap failed for input. Changing to O_WRONLY mode.");
mode = O_WRONLY;
} else {
- pa_log(__FILE__": mmap(): %s", strerror(errno));
+ pa_log(__FILE__": mmap(): %s", pa_cstrerror(errno));
goto fail;
}
} else {
- if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL)))
+ if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, &map)))
goto fail;
u->source->userdata = u;
if (mode != O_RDONLY) {
if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_GETOSPACE: %s", pa_cstrerror(errno));
goto fail;
}
pa_log(__FILE__": mmap filed for output. Changing to O_RDONLY mode.");
mode = O_RDONLY;
} else {
- pa_log(__FILE__": mmap(): %s", strerror(errno));
+ pa_log(__FILE__": mmap(): %s", pa_cstrerror(errno));
goto fail;
}
} else {
pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec);
- if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL)))
+ if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, &map)))
goto fail;
u->sink->get_latency = sink_get_latency_cb;
zero = 0;
if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &zero) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
goto fail;
}
if (ioctl(u->fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) < 0) {
- pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", strerror(errno));
+ pa_log(__FILE__": SNDCTL_DSP_SETTRIGGER: %s", pa_cstrerror(errno));
goto fail;
}