/*
* Copyright (c) 2010 Antti Kantee. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Make input buffer (and it is also expected data). */
inplen = sizeof(musa) * 4;
inpbuf = (uint32_t *)malloc(inplen);
if (inpbuf == NULL)
err(1, "malloc: inpbuf");
/* mulaw:mono to slinear_le16:stereo */
for (i = 0; i < (int)sizeof(musa); i++) {
int16_t s = mulaw_to_slinear16[musa[i]];
uint32_t v = htole16((uint16_t)s);
inpbuf[i] = (v << 16) | v;
}
DPRINTF(1, "ioctl\n");
/* pad is SLINEAR_LE, 16bit, 2ch, 44100Hz. */
AUDIO_INITINFO(&ai);
ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE;
ai.play.precision = 16;
ai.play.channels = 2;
ai.play.sample_rate = 44100;
n = rump_sys_ioctl(audiofd, AUDIO_SETINFO, &ai);
if (n == -1)
err(1, "ioctl");
DPRINTF(1, "write %d\n", inplen);
n = rump_sys_write(audiofd, inpbuf, inplen);
if (n == -1)
err(1, "write");
if (n != inplen)
errx(1, "write: n=%zd < %d", n, inplen);
phase = PRE;
i = 0;
nframe = 0;
outp = NULL;
for (;;) {
/* Read to outbuf when it is empty. */
if (nframe == 0) {
n = rump_sys_read(padfd, outbuf, outlen);
if (n == -1)
err(1, "read");
if (n == 0)
errx(1, "read: EOF");
/* XXX Should I recover from this? */
if (n % 4 != 0)
errx(1, "read: n=%zd", n);
nframe = n / 4;
outp = outbuf;
}
if (phase == PRE) {
/* Skip preceding silence part. */
if (*outp == 0) {
outp++;
nframe--;
} else {
/* This is the first frame. */
phase = BODY;
}
} else if (phase == BODY) {
/* Compare wavedata. */
expected = le32dec(outp);
actual = le32dec(inpbuf + i);
DPRINTF(2, "[%d] %08x %08x\n", i, actual, expected);
if (actual != expected) {
errx(1, "bad output [%d] %08x %08x",
i, actual, expected);
}
outp++;
nframe--;
i++;
if (i >= (int)sizeof(musa)) {
phase = POST;
i = 0;
}
} else if (phase == POST) {
/*
* There is no way to determine the end of playback.
* Therefore it detects and terminates with some
* continuous silence.
*/
actual = le32dec(outp);
if (actual != 0)
errx(1, "bad post output: %08x", actual);
outp++;
nframe--;
i++;
if (i >= (int)ai.play.sample_rate / 100)
break;
}
}
DPRINTF(1, "success\n");
return 0;
}