On Wed, Jul 21, 2010 at 10:27:29AM +0400, Dmitrij D. Czarkoff wrote:
I've been told this by a few people now. unfortunately, I don't have
any idea where the problem is.
can you try running the following? save it to a file, let's call
it audrops.c then build it with 'make LDFLAGS=-lm audrops'.
let that run for a while, at least as long as it takes for you to
normally hear drops and echos. start it with simply ./audrops. it
should play a steady tone. does it print much? do you hear drops
and/or echos?
--
jakemsr@sdf.lonestar.org
SDF Public Access UNIX System -
http://sdf.lonestar.org
/*
* Copyright (c) 2010 Jacob Meuser <jakemsr@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/audioio.h>
#include <sys/param.h>
#include <sys/time.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <err.h>
#include <stdlib.h>
#include <math.h>
#define DEFAULT_DEVICE "/dev/audio"
#define AUDIO_BPS(bits) ((bits) <= 8 ? 1 : (((bits) <= 16) ? 2 : 4))
volatile sig_atomic_t quit;
extern char *__progname;
void
usage(void)
{
fprintf(stderr,
"Usage: %s [-b blocksize] [-c channels] [-f device]\n"
" [-p precision] [-r rate] [-w hiwat]\n",
__progname);
}
void
sigint(int s)
{
quit = 1;
}
void
setsig(void)
{
struct sigaction sa;
quit = 0;
sigfillset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = sigint;
if (sigaction(SIGINT, &sa, NULL) < 0)
err(1, "sigaction(int) failed");
if (sigaction(SIGTERM, &sa, NULL) < 0)
err(1, "sigaction(term) failed");
if (sigaction(SIGHUP, &sa, NULL) < 0)
err(1, "sigaction(hup) failed");
}
int
set_params(int fd, u_int precision, u_int rate, u_int channels, u_int hiwat,
u_int *bpf, size_t *block_size)
{
audio_info_t info;
AUDIO_INITINFO(&info);
info.mode = AUMODE_PLAY;
info.play.precision = precision;
info.play.channels = channels;
info.play.sample_rate = rate;
info.play.encoding = AUDIO_ENCODING_SLINEAR;
info.play.block_size = *block_size;
info.hiwat = hiwat;
info.lowat = hiwat - 1;
if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
warn("AUDIO_SETINFO");
return 0;
}
if (ioctl(fd, AUDIO_GETINFO, &info) < 0) {
warn("AUDIO_GETINFO");
return 0;
}
if (info.play.precision != precision) {
warnx("unable to set play precision: tried %u, got %u",
precision, info.play.precision);
return 0;
}
if (info.play.channels != channels) {
warnx("unable to set play channels: tried %u, got %u",
channels, info.play.channels);
return 0;
}
if (info.play.sample_rate != rate) {
warnx("unable to set play sample_rate: tried %u, got %u",
rate, info.play.sample_rate);
return 0;
}
*bpf = AUDIO_BPS(info.play.precision) * info.play.channels;
*block_size = info.play.block_size;
return 1;
}
int
paint_samples(uint8_t *samples, u_int precision, u_int rate, u_int channels)
{
float d, m;
double playfreq = 440.0;
int16_t v;
uint8_t *p;
int i, j;
m = (1 << (precision - 1)) - 1;
for (i = 0, p = samples; i < rate; i++) {
d = m * sinf(((float)i / (float)rate) *
(2 * M_PI * playfreq));
d = rintf(d);
v = d;
for (j = 0; j < channels; j++) {
switch (precision) {
case 8:
*p = v;
p++;
break;
case 16:
*p = (v & 0x00ff) >> 0;
p++;
*p = (v & 0xff00) >> 8;
p++;
break;
default:
printf("invalid precision\n");
return 0;
}
}
}
return 1;
}
size_t
run_test(int fd, uint8_t *samples, size_t samples_size, size_t block_size,
long block_usec)
{
struct timeval now, last_time, diff;
uint8_t *play_buf;
size_t total_written = 0;
int samples_pos = 0, ret, l, l2;
play_buf = malloc(block_size);
if (play_buf == NULL)
err(1, "play_buf=malloc(%lu)", block_size);
bcopy(samples, play_buf, block_size);
samples_pos += block_size;
gettimeofday(&last_time, NULL);
while (!quit) {
ret = write(fd, play_buf, block_size);
gettimeofday(&now, NULL);
if (ret != block_size)
printf("broken write: %d of %lu\n", ret, block_size);
total_written += (ret > 0) ? ret : 0;
timersub(&now, &last_time, &diff);
last_time = now;
if (diff.tv_usec > block_usec * 2) {
printf("late return at %ld.%06ld: %ld > %ld\n",
now.tv_sec, now.tv_usec, diff.tv_usec, block_usec);
} else if (diff.tv_usec * 2 < block_usec) {
printf("early return at %ld.%06ld: %ld < %ld\n",
now.tv_sec, now.tv_usec, diff.tv_usec, block_usec);
}
if (samples_pos + block_size > samples_size) {
l = samples_size - samples_pos;
bcopy(samples + samples_pos, play_buf, l);
l2 = block_size - l;
bcopy(samples, play_buf + l, l2);
samples_pos = l2;
} else {
bcopy(samples + samples_pos, play_buf, block_size);
samples_pos += block_size;
}
}
free(play_buf);
return(total_written);
}
int
main(int argc, char *argv[])
{
audio_info_t info;
struct timeval now, start_time, diff;
char dev[MAXPATHLEN];
unsigned long block_usec, run_usec;
size_t block_size = 4096, samples_size, total_written;
u_int rate = 48000, channels = 2, precision = 16, hiwat = 2;
int fd, bpf, ch, pe, error = 0;
uint8_t *samples;
const char *errstr;
snprintf(dev, sizeof(dev), DEFAULT_DEVICE);
while ((ch = getopt(argc, argv, "b:c:f:p:r:w:")) != -1) {
switch (ch) {
case 'b':
block_size = (size_t)strtonum(optarg, 32, 32768, &errstr);
if (errstr != NULL) {
error++;
warnx("block_size %s", errstr);
}
break;
case 'c':
channels = (u_int)strtonum(optarg, 1, 12, &errstr);
if (errstr != NULL) {
error++;
warnx("channels %s", errstr);
}
break;
case 'f':
snprintf(dev, sizeof(dev), "%s", optarg);
break;
case 'p':
precision = (u_int)strtonum(optarg, 8, 32, &errstr);
if (errstr != NULL) {
error++;
warnx("precision %s", errstr);
}
break;
case 'r':
rate = (u_int)strtonum(optarg, 4000, 192000, &errstr);
if (errstr != NULL) {
error++;
warnx("sample_rate %s", errstr);
}
break;
case 'w':
hiwat = (u_int)strtonum(optarg, 2, 4096, &errstr);
if (errstr != NULL) {
error++;
warnx("hiwat %s", errstr);
}
break;
default:
error++;
break;
}
if (error) {
usage();
exit(1);
}
}
argc -= optind;
argv += optind;
if ((fd = open(dev, O_WRONLY, 0)) == -1)
err(1, "open(%s)", dev);
if (!set_params(fd, precision, rate, channels, hiwat,
&bpf, &block_size))
exit(1);
samples_size = rate * bpf;
samples = malloc(samples_size);
if (samples == NULL)
err(1, "samples=malloc(%lu)", samples_size);
if (!paint_samples(samples, precision, rate, channels))
errx(1, "paint_samples() failed");
block_usec = 1000000 * (block_size / bpf) / rate;
printf("pre=%u ch=%u bpf=%d block_size=%lu rate=%u block_usec=%ld\n",
precision, channels, bpf, block_size, rate, block_usec);
setsig();
gettimeofday(&start_time, NULL);
total_written = run_test(fd, samples, samples_size, block_size,
block_usec);
gettimeofday(&now, NULL);
if (ioctl(fd, AUDIO_GETINFO, &info) < 0) {
warn("AUDIO_GETINFO");
exit(0);
}
if (ioctl(fd, AUDIO_PERROR, &pe) < 0) {
warn("AUDIO_PERROR");
exit(0);
}
close(fd);
free(samples);
timersub(&now, &start_time, &diff);
printf("pre=%u ch=%u bpf=%d block_size=%lu rate=%u block_usec=%ld\n",
precision, channels, bpf, block_size, rate, block_usec);
printf("bytes written = %lu\n", total_written);
printf("bytes processed = %u\n", info.play.samples);
printf("bytes errors = %u\n", pe * bpf);
printf("bytes buffered = %u\n", info.play.seek);
printf("%lu == %u ?\n", total_written,
info.play.samples + info.play.seek + pe * bpf);
printf("run time = %ld.%06ld s\n", diff.tv_sec, diff.tv_usec);
run_usec = diff.tv_sec * 1000000 + diff.tv_usec;
printf("avg rate = %llu\n", ((unsigned long long)(info.play.samples / bpf) * 1000000) / run_usec);
exit(0);
}