Example #1
0
static int
aucat_connect_un(struct aucat *hdl, unsigned int unit)
{
	struct sockaddr_un ca;
	socklen_t len = sizeof(struct sockaddr_un);
	uid_t uid;
	int s;

	uid = geteuid();
	snprintf(ca.sun_path, sizeof(ca.sun_path),
	    "/tmp/aucat-%u/%s%u", uid, AUCAT_PATH, unit);
	ca.sun_family = AF_UNIX;
	s = socket(AF_UNIX, SOCK_STREAM, 0);
	if (s < 0)
		return 0;
	while (connect(s, (struct sockaddr *)&ca, len) < 0) {
		if (errno == EINTR)
			continue;
		DPERROR(ca.sun_path);
		/* try shared server */
		snprintf(ca.sun_path, sizeof(ca.sun_path),
		    "/tmp/aucat/%s%u", AUCAT_PATH, unit);
		while (connect(s, (struct sockaddr *)&ca, len) < 0) {
			if (errno == EINTR)
				continue;
			DPERROR(ca.sun_path);
			close(s);
			return 0;
		}
		break;
	}
	hdl->fd = s;
	DPRINTFN(2, "%s: connected\n", ca.sun_path);
	return 1;
}
Example #2
0
static size_t
sio_sun_autostart(struct sio_sun_hdl *hdl)
{
	struct audio_info aui;
	struct pollfd pfd;

	pfd.fd = hdl->fd;
	pfd.events = POLLOUT;
	while (poll(&pfd, 1, 0) < 0) {
		if (errno == EINTR)
			continue;
		DPERROR("sio_sun_autostart: poll");
		hdl->sio.eof = 1;
		return 0;
	}
	if (!(pfd.revents & POLLOUT)) {
		hdl->filling = 0;
		AUDIO_INITINFO(&aui);
		if (hdl->sio.mode & SIO_PLAY)
			aui.play.pause = 0;
		if (hdl->sio.mode & SIO_REC)
			aui.record.pause = 0;
		if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
			DPERROR("sio_sun_autostart: setinfo");
			hdl->sio.eof = 1;
			return 0;
		}
		_sio_onmove_cb(&hdl->sio, 0);
	}
	return 1;
}
Example #3
0
/*
 * try to set the device to the given parameters and check that the
 * device can use them; return 1 on success, 0 on failure or error
 */
static int
sio_sun_tryinfo(struct sio_sun_hdl *hdl, struct sio_enc *enc,
    unsigned int pchan, unsigned int rchan, unsigned int rate)
{
	struct audio_info aui;
	struct audio_prinfo *pr;

	pr = (hdl->sio.mode & SIO_PLAY) ? &aui.play : &aui.record;

	AUDIO_INITINFO(&aui);
	if (enc) {
		if (enc->le && enc->sig) {
			pr->encoding = AUDIO_ENCODING_SLINEAR_LE;
		} else if (!enc->le && enc->sig) {
			pr->encoding = AUDIO_ENCODING_SLINEAR_BE;
		} else if (enc->le && !enc->sig) {
			pr->encoding = AUDIO_ENCODING_ULINEAR_LE;
		} else {
			pr->encoding = AUDIO_ENCODING_ULINEAR_BE;
		}
		pr->precision = enc->bits;
	}
	if (rate)
		pr->sample_rate = rate;
	if ((hdl->sio.mode & (SIO_PLAY | SIO_REC)) == (SIO_PLAY | SIO_REC))
		aui.record = aui.play;
	if (pchan && (hdl->sio.mode & SIO_PLAY))
		aui.play.channels = pchan;
	if (rchan && (hdl->sio.mode & SIO_REC))
		aui.record.channels = rchan;
	if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
		if (errno == EINVAL)
			return 0;
		DPERROR("sio_sun_tryinfo: setinfo");
		hdl->sio.eof = 1;
		return 0;
	}
	if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
		DPERROR("sio_sun_tryinfo: getinfo");
		hdl->sio.eof = 1;
		return 0;
	}
	if (pchan && aui.play.channels != pchan)
		return 0;
	if (rchan && aui.record.channels != rchan)
		return 0;
	if (rate) {
		if ((hdl->sio.mode & SIO_PLAY) &&
		    (aui.play.sample_rate != rate))
			return 0;
		if ((hdl->sio.mode & SIO_REC) &&
		    (aui.record.sample_rate != rate))
			return 0;
	}
	return 1;
}
Example #4
0
static int
sio_psleep(struct sio_hdl *hdl, int event)
{
    struct pollfd pfd[SIO_MAXNFDS];
    int revents;
    int nfds;

    nfds = sio_nfds(hdl);
    if (nfds > SIO_MAXNFDS) {
        DPRINTF("sio_psleep: %d: too many descriptors\n", nfds);
        hdl->eof = 1;
        return 0;
    }
    for (;;) {
        nfds = sio_pollfd(hdl, pfd, event);
        while (poll(pfd, nfds, -1) < 0) {
            if (errno == EINTR)
                continue;
            DPERROR("sio_psleep: poll");
            hdl->eof = 1;
            return 0;
        }
        revents = sio_revents(hdl, pfd);
        if (revents & POLLHUP) {
            DPRINTF("sio_psleep: hang-up\n");
            return 0;
        }
        if (revents & event)
            break;
    }
    return 1;
}
Example #5
0
size_t
_aucat_rdata(struct aucat *hdl, void *buf, size_t len, int *eof)
{
	ssize_t n;

	if (hdl->rstate != RSTATE_DATA) {
		DPRINTF("_aucat_rdata: bad state\n");
		abort();
	}
	if (len > hdl->rtodo)
		len = hdl->rtodo;
	while ((n = read(hdl->fd, buf, len)) < 0) {
		if (errno == EINTR)
			continue;
		if (errno != EAGAIN) {
			*eof = 1;
			DPERROR("_aucat_rdata: read");
		}
		return 0;
	}
	if (n == 0) {
		DPRINTF("_aucat_rdata: eof\n");
		*eof = 1;
		return 0;
	}
	hdl->rtodo -= n;
	if (hdl->rtodo == 0) {
		hdl->rstate = RSTATE_MSG;
		hdl->rtodo = sizeof(struct amsg);
	}
	DPRINTFN(2, "_aucat_rdata: read: n = %zd\n", n);
	return n;
}
Example #6
0
struct fuse_vnode *
alloc_vn(struct fuse *f, const char *path, ino_t ino, ino_t parent)
{
    struct fuse_vnode *vn;

    if ((vn = malloc(sizeof(*vn))) == NULL) {
        DPERROR(__func__);
        return (NULL);
    }

    vn->ino = ino;
    vn->parent = parent;
    if (strlcpy(vn->path, path, sizeof(vn->path)) >= sizeof(vn->path)) {
        DPRINTF("%s: strlcpy name too long\n", __func__);
        free(vn);
        return (NULL);
    }

    if (ino == (ino_t)-1) {
        f->max_ino++;
        vn->ino = f->max_ino;
    }

    return (vn);
}
Example #7
0
static int
sio_sun_getpar(struct sio_hdl *sh, struct sio_par *par)
{
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	struct audio_info aui;

	if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
		DPERROR("sio_sun_getpar: getinfo");
		hdl->sio.eof = 1;
		return 0;
	}
	if (hdl->sio.mode & SIO_PLAY) {
		par->rate = aui.play.sample_rate;
		if (!sio_sun_infotoenc(hdl, &aui.play, par))
			return 0;
	} else if (hdl->sio.mode & SIO_REC) {
		par->rate = aui.record.sample_rate;
		if (!sio_sun_infotoenc(hdl, &aui.record, par))
			return 0;
	} else
		return 0;
	par->pchan = (hdl->sio.mode & SIO_PLAY) ?
	    aui.play.channels : 0;
	par->rchan = (hdl->sio.mode & SIO_REC) ?
	    aui.record.channels : 0;
	par->round = (hdl->sio.mode & SIO_REC) ?
	    aui.record.block_size / (par->bps * par->rchan) :
	    aui.play.block_size / (par->bps * par->pchan);
	par->appbufsz = aui.hiwat * par->round;
	par->bufsz = par->appbufsz;
	return 1;
}
Example #8
0
static int
aucat_connect_tcp(struct aucat *hdl, char *host, unsigned int unit)
{
	int s, error, opt;
	struct addrinfo *ailist, *ai, aihints;
	char serv[NI_MAXSERV];

	snprintf(serv, sizeof(serv), "%u", unit + AUCAT_PORT);
	memset(&aihints, 0, sizeof(struct addrinfo));
	aihints.ai_socktype = SOCK_STREAM;
	aihints.ai_protocol = IPPROTO_TCP;
	error = getaddrinfo(host, serv, &aihints, &ailist);
	if (error) {
		DPRINTF("%s: %s\n", host, gai_strerror(error));
		return 0;
	}
	s = -1;
	for (ai = ailist; ai != NULL; ai = ai->ai_next) {
		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
		if (s < 0) {
			DPERROR("socket");
			continue;
		}
	restart:
		if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
			if (errno == EINTR)
				goto restart;
			DPERROR("connect");
			close(s);
			s = -1;
			continue;
		}
		break;
	}
	freeaddrinfo(ailist);
	if (s < 0)
		return 0;
	opt = 1;
	if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(int)) < 0) {
		DPERROR("setsockopt");
		close(s);
		return 0;
	}
	hdl->fd = s;
	return 1;
}
Example #9
0
void
fuse_unmount(const char *dir, unused struct fuse_chan *ch)
{
	if (ch->dead)
		return;

	if (unmount(dir, MNT_UPDATE) == -1)
		DPERROR(__func__);
}
Example #10
0
int
_aucat_setfl(struct aucat *hdl, int nbio, int *eof)
{
	if (fcntl(hdl->fd, F_SETFL, nbio ? O_NONBLOCK : 0) < 0) {
		DPERROR("_aucat_setfl: fcntl");
		*eof = 1;
		return 0;
	}
	return 1;
}
Example #11
0
static int
sio_sun_stop(struct sio_hdl *sh)
{
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	struct audio_info aui;
	int mode;

	if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
		DPERROR("sio_sun_stop: getinfo");
		hdl->sio.eof = 1;
		return 0;
	}
	mode = aui.mode;

	/*
	 * there's no way to drain the device without blocking, so just
	 * stop it until the kernel driver get fixed
	 */
	AUDIO_INITINFO(&aui);
	aui.mode = 0;
	if (hdl->sio.mode & SIO_PLAY)
		aui.play.pause = 1;
	if (hdl->sio.mode & SIO_REC)
		aui.record.pause = 1;
	if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
		DPERROR("sio_sun_stop: setinfo1");
		hdl->sio.eof = 1;
		return 0;
	}
	AUDIO_INITINFO(&aui);
	aui.mode = mode;
	if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
		DPERROR("sio_sun_stop: setinfo2");
		hdl->sio.eof = 1;
		return 0;
	}
	return 1;
}
Example #12
0
size_t
_aucat_wdata(struct aucat *hdl, const void *buf, size_t len,
   unsigned int wbpf, int *eof)
{
	ssize_t n;
	size_t datasize;

	switch (hdl->wstate) {
	case WSTATE_IDLE:
		datasize = len;
		if (datasize > AMSG_DATAMAX)
			datasize = AMSG_DATAMAX;
		datasize -= datasize % wbpf;
		if (datasize == 0)
			datasize = wbpf;
		hdl->wmsg.cmd = htonl(AMSG_DATA);
		hdl->wmsg.u.data.size = htonl(datasize);
		hdl->wtodo = sizeof(struct amsg);
		hdl->wstate = WSTATE_MSG;
		/* FALLTHROUGH */
	case WSTATE_MSG:
		if (!_aucat_wmsg(hdl, eof))
			return 0;
	}
	if (len > hdl->wtodo)
		len = hdl->wtodo;
	if (len == 0) {
		DPRINTF("_aucat_wdata: len == 0\n");
		abort();
	}
	while ((n = write(hdl->fd, buf, len)) < 0) {
		if (errno == EINTR)
			continue;
		if (errno != EAGAIN) {
			*eof = 1;
			DPERROR("_aucat_wdata: write");
		}
		return 0;
	}
	DPRINTFN(2, "_aucat_wdata: write: n = %zd\n", n);
	hdl->wtodo -= n;
	if (hdl->wtodo == 0) {
		hdl->wstate = WSTATE_IDLE;
		hdl->wtodo = 0xdeadbeef;
	}
	return n;
}
Example #13
0
struct fuse_vnode *
alloc_vn(struct fuse *f, const char *path, ino_t ino, ino_t parent)
{
    struct fuse_vnode *vn;

    if ((vn = malloc(sizeof(*vn))) == NULL) {
        DPERROR("alloc_vn:");
        return (NULL);
    }

    vn->ino = ino;
    vn->parent = parent;
    strncpy(vn->path, path, NAME_MAX);
    vn->path[NAME_MAX - 1] =  '\0';
    if (ino == (ino_t)-1) {
        f->max_ino++;
        vn->ino = f->max_ino;
    }

    return (vn);
}
Example #14
0
static size_t
sio_sun_read(struct sio_hdl *sh, void *buf, size_t len)
{
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	ssize_t n;

	while ((n = read(hdl->fd, buf, len)) < 0) {
		if (errno == EINTR)
			continue;
		if (errno != EAGAIN) {
			DPERROR("sio_sun_read: read");
			hdl->sio.eof = 1;
		}
		return 0;
	}
	if (n == 0) {
		DPRINTF("sio_sun_read: eof\n");
		hdl->sio.eof = 1;
		return 0;
	}
	return n;
}
Example #15
0
/*
 * read a message, return 0 if not completed
 */
int
_aucat_rmsg(struct aucat *hdl, int *eof)
{
	ssize_t n;
	unsigned char *data;

	if (hdl->rstate != RSTATE_MSG) {
		DPRINTF("_aucat_rmsg: bad state\n");
		abort();
	}
	while (hdl->rtodo > 0) {
		data = (unsigned char *)&hdl->rmsg;
		data += sizeof(struct amsg) - hdl->rtodo;
		while ((n = read(hdl->fd, data, hdl->rtodo)) < 0) {
			if (errno == EINTR)
				continue;
			if (errno != EAGAIN) {
				*eof = 1;
				DPERROR("_aucat_rmsg: read");
			}
			return 0;
		}
		if (n == 0) {
			DPRINTF("_aucat_rmsg: eof\n");
			*eof = 1;
			return 0;
		}
		hdl->rtodo -= n;
	}
	if (ntohl(hdl->rmsg.cmd) == AMSG_DATA) {
		hdl->rtodo = ntohl(hdl->rmsg.u.data.size);
		hdl->rstate = RSTATE_DATA;
	} else {
		hdl->rtodo = sizeof(struct amsg);
		hdl->rstate = RSTATE_MSG;
	}
	return 1;
}
Example #16
0
static int
sio_sun_start(struct sio_hdl *sh)
{
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	struct audio_info aui;

	hdl->obpf = hdl->sio.par.pchan * hdl->sio.par.bps;
	hdl->ibpf = hdl->sio.par.rchan * hdl->sio.par.bps;
	hdl->ibytes = 0;
	hdl->obytes = 0;
	hdl->ierr = 0;
	hdl->oerr = 0;
	hdl->idelta = 0;
	hdl->odelta = 0;

	if (hdl->sio.mode & SIO_PLAY) {
		/*
		 * keep the device paused and let sio_sun_write() trigger the
		 * start later, to avoid buffer underruns
		 */
		hdl->filling = 1;
	} else {
		/*
		 * no play buffers to fill, start now!
		 */
		AUDIO_INITINFO(&aui);
		if (hdl->sio.mode & SIO_REC)
			aui.record.pause = 0;
		if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
			DPERROR("sio_sun_start: setinfo");
			hdl->sio.eof = 1;
			return 0;
		}
		hdl->filling = 0;
		_sio_onmove_cb(&hdl->sio, 0);
	}
	return 1;
}
Example #17
0
static size_t
sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len)
{
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	const unsigned char *data = buf;
	ssize_t n, todo;

	todo = len;
	while ((n = write(hdl->fd, data, todo)) < 0) {
		if (errno == EINTR)
			continue;
		if (errno != EAGAIN) {
			DPERROR("sio_sun_write: write");
			hdl->sio.eof = 1;
		}
 		return 0;
	}
	if (hdl->filling) {
		if (!sio_sun_autostart(hdl))
			return 0;
	}
	return n;
}
Example #18
0
/*
 * write a message, return 0 if not completed
 */
int
_aucat_wmsg(struct aucat *hdl, int *eof)
{
	ssize_t n;
	unsigned char *data;

	if (hdl->wstate == WSTATE_IDLE)
		hdl->wstate = WSTATE_MSG;
		hdl->wtodo = sizeof(struct amsg);
	if (hdl->wstate != WSTATE_MSG) {
		DPRINTF("_aucat_wmsg: bad state\n");
		abort();
	}
	while (hdl->wtodo > 0) {
		data = (unsigned char *)&hdl->wmsg;
		data += sizeof(struct amsg) - hdl->wtodo;
		while ((n = write(hdl->fd, data, hdl->wtodo)) < 0) {
			if (errno == EINTR)
				continue;
			if (errno != EAGAIN) {
				*eof = 1;
				DPERROR("_aucat_wmsg: write");
			}
			return 0;
		}
		hdl->wtodo -= n;
	}
	if (ntohl(hdl->wmsg.cmd) == AMSG_DATA) {
		hdl->wtodo = ntohl(hdl->wmsg.u.data.size);
		hdl->wstate = WSTATE_DATA;
	} else {
		hdl->wtodo = 0xdeadbeef;
		hdl->wstate = WSTATE_IDLE;
	}
	return 1;
}
Example #19
0
int
_aucat_open(struct aucat *hdl, const char *str, unsigned int mode,
    unsigned int type)
{
	extern char *__progname;
	int eof;
	char host[NI_MAXHOST], opt[AMSG_OPTMAX];
	const char *p = str;
	unsigned int unit, devnum;

	if (*p == '@') {
		p = parsestr(++p, host, NI_MAXHOST);
		if (p == NULL)
			return 0;
	} else
		*host = '\0';
	if (*p == ',') {
		p = parsedev(++p, &unit);
		if (p == NULL)
			return 0;
	} else
		unit = 0;
	if (*p != '/' && *p != ':') {
		DPRINTF("%s: '/' expected\n", str);
		return 0;
	}
	p = parsedev(++p, &devnum);
	if (p == NULL)
		return 0;
	if (*p == '.') {
		p = parsestr(++p, opt, AMSG_OPTMAX);
		if (p == NULL)
			return 0;
	} else
		strlcpy(opt, "default", AMSG_OPTMAX);
	if (*p != '\0') {
		DPRINTF("%s: junk at end of dev name\n", p);
		return 0;
	}
	devnum += type * 16; /* XXX */
	DPRINTFN(2, "_aucat_open: host=%s unit=%u devnum=%u opt=%s\n",
	    host, unit, devnum, opt);
	if (host[0] != '\0') {
		if (!aucat_connect_tcp(hdl, host, unit))
			return 0;
	} else {
		if (!aucat_connect_un(hdl, unit))
			return 0;
	}
	if (fcntl(hdl->fd, F_SETFD, FD_CLOEXEC) < 0) {
		DPERROR("FD_CLOEXEC");
		goto bad_connect;
	}
	hdl->rstate = RSTATE_MSG;
	hdl->rtodo = sizeof(struct amsg);
	hdl->wstate = WSTATE_IDLE;
	hdl->wtodo = 0xdeadbeef;
	hdl->maxwrite = 0;

	/*
	 * say hello to server
	 */
	AMSG_INIT(&hdl->wmsg);
	hdl->wmsg.cmd = htonl(AMSG_AUTH);
	if (!aucat_mkcookie(hdl->wmsg.u.auth.cookie))
		goto bad_connect;
	hdl->wtodo = sizeof(struct amsg);
	if (!_aucat_wmsg(hdl, &eof))
		goto bad_connect;
	AMSG_INIT(&hdl->wmsg);
	hdl->wmsg.cmd = htonl(AMSG_HELLO);
	hdl->wmsg.u.hello.version = AMSG_VERSION;
	hdl->wmsg.u.hello.mode = htons(mode);
	hdl->wmsg.u.hello.devnum = devnum;
	strlcpy(hdl->wmsg.u.hello.who, __progname,
	    sizeof(hdl->wmsg.u.hello.who));
	strlcpy(hdl->wmsg.u.hello.opt, opt,
	    sizeof(hdl->wmsg.u.hello.opt));
	hdl->wtodo = sizeof(struct amsg);
	if (!_aucat_wmsg(hdl, &eof))
		goto bad_connect;
	hdl->rtodo = sizeof(struct amsg);
	if (!_aucat_rmsg(hdl, &eof)) {
		DPRINTF("aucat_init: mode refused\n");
		goto bad_connect;
	}
	if (ntohl(hdl->rmsg.cmd) != AMSG_ACK) {
		DPRINTF("aucat_init: protocol err\n");
		goto bad_connect;
	}
	return 1;
 bad_connect:
	while (close(hdl->fd) < 0 && errno == EINTR)
		; /* retry */
	return 0;
}
Example #20
0
int
fuse_loop(struct fuse *fuse)
{
	struct fusebuf fbuf;
	struct fuse_context ctx;
	struct fb_ioctl_xch ioexch;
	struct kevent ev;
	ssize_t n;
	int ret;

	fuse->fc->kq = kqueue();
	if (fuse->fc->kq == -1)
		return (-1);

	EV_SET(&fuse->fc->event, fuse->fc->fd, EVFILT_READ, EV_ADD |
	    EV_ENABLE, 0, 0, 0);

	while (!fuse->fc->dead) {
		ret = kevent(fuse->fc->kq, &fuse->fc->event, 1, &ev, 1, NULL);
		if (ret == -1)
			DPERROR(__func__);
		else if (ret > 0) {
			n = read(fuse->fc->fd, &fbuf, sizeof(fbuf));
			if (n != sizeof(fbuf)) {
				fprintf(stderr, "%s: bad fusebuf read\n",
				    __func__);
				return (-1);
			}

			/* check if there is data something present */
			if (fbuf.fb_len) {
				fbuf.fb_dat = malloc(fbuf.fb_len);
				if (fbuf.fb_dat == NULL)
					return (-1);
				ioexch.fbxch_uuid = fbuf.fb_uuid;
				ioexch.fbxch_len = fbuf.fb_len;
				ioexch.fbxch_data = fbuf.fb_dat;

				if (ioctl(fuse->fc->fd, FIOCGETFBDAT,
				    &ioexch)) {
					free(fbuf.fb_dat);
					return (-1);
				}
			}

			ctx.fuse = fuse;
			ctx.uid = fuse->conf.uid;
			ctx.gid = fuse->conf.gid;
			ctx.pid = fuse->conf.pid;
			ctx.umask = fuse->conf.umask;
			ctx.private_data = fuse->private_data;
			ictx = &ctx;

			ret = ifuse_exec_opcode(fuse, &fbuf);
			if (ret) {
				ictx = NULL;
				return (-1);
			}

			n = write(fuse->fc->fd, &fbuf, sizeof(fbuf));
			if (fbuf.fb_len) {
				if (fbuf.fb_dat == NULL) {
					fprintf(stderr, "%s: fb_dat is Null\n",
					    __func__);
					return (-1);
				}
				ioexch.fbxch_uuid = fbuf.fb_uuid;
				ioexch.fbxch_len = fbuf.fb_len;
				ioexch.fbxch_data = fbuf.fb_dat;

				if (ioctl(fuse->fc->fd, FIOCSETFBDAT, &ioexch)) {
					free(fbuf.fb_dat);
					return (-1);
				}
				free(fbuf.fb_dat);
			}
			ictx = NULL;

			if (n != FUSEBUFSIZE) {
				errno = EINVAL;
				return (-1);
			}
		}
	}

	return (0);
}
Example #21
0
/*
 * guess device capabilities
 */
static int
sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
{
#define NCHANS (sizeof(chans) / sizeof(chans[0]))
#define NRATES (sizeof(rates) / sizeof(rates[0]))
	static unsigned int chans[] = {
		1, 2, 4, 6, 8, 10, 12
	};
	static unsigned int rates[] = {
		8000, 11025, 12000, 16000, 22050, 24000,
		32000, 44100, 48000, 64000, 88200, 96000
	};
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	struct sio_par savepar;
	struct audio_encoding ae;
	unsigned int nenc = 0, nconf = 0;
	unsigned int enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map;
	unsigned int i, j, conf;

	if (!sio_sun_getpar(&hdl->sio, &savepar))
		return 0;

	/*
	 * fill encoding list
	 */
	for (ae.index = 0; nenc < SIO_NENC; ae.index++) {
		if (ioctl(hdl->fd, AUDIO_GETENC, &ae) < 0) {
			if (errno == EINVAL)
				break;
			DPERROR("sio_sun_getcap: getenc");
			hdl->sio.eof = 1;
			return 0;
		}
		if (ae.flags & AUDIO_ENCODINGFLAG_EMULATED)
			continue;
		if (ae.encoding == AUDIO_ENCODING_SLINEAR_LE) {
			cap->enc[nenc].le = 1;
			cap->enc[nenc].sig = 1;
		} else if (ae.encoding == AUDIO_ENCODING_SLINEAR_BE) {
			cap->enc[nenc].le = 0;
			cap->enc[nenc].sig = 1;
		} else if (ae.encoding == AUDIO_ENCODING_ULINEAR_LE) {
			cap->enc[nenc].le = 1;
			cap->enc[nenc].sig = 0;
		} else if (ae.encoding == AUDIO_ENCODING_ULINEAR_BE) {
			cap->enc[nenc].le = 0;
			cap->enc[nenc].sig = 0;
		} else if (ae.encoding == AUDIO_ENCODING_SLINEAR) {
			cap->enc[nenc].le = SIO_LE_NATIVE;
			cap->enc[nenc].sig = 1;
		} else if (ae.encoding == AUDIO_ENCODING_ULINEAR) {
			cap->enc[nenc].le = SIO_LE_NATIVE;
			cap->enc[nenc].sig = 0;
		} else {
			/* unsipported encoding */
			continue;
		}
		cap->enc[nenc].bits = ae.precision;
		cap->enc[nenc].bps = ae.bps;
		cap->enc[nenc].msb = ae.msb;
		enc_map |= (1 << nenc);
		nenc++;
	}

	/*
	 * fill channels
	 *
	 * for now we're lucky: all kernel devices assume that the
	 * number of channels and the encoding are independent so we can
	 * use the current encoding and try various channels.
	 */
	if (hdl->sio.mode & SIO_PLAY) {
		memcpy(&cap->pchan, chans, NCHANS * sizeof(unsigned int));
		for (i = 0; i < NCHANS; i++) {
			if (sio_sun_tryinfo(hdl, NULL, chans[i], 0, 0))
				pchan_map |= (1 << i);
		}
	}
	if (hdl->sio.mode & SIO_REC) {
		memcpy(&cap->rchan, chans, NCHANS * sizeof(unsigned int));
		for (i = 0; i < NCHANS; i++) {
			if (sio_sun_tryinfo(hdl, NULL, 0, chans[i], 0))
				rchan_map |= (1 << i);
		}
	}

	/*
	 * fill rates
	 *
	 * rates are not independent from other parameters (eg. on
	 * uaudio devices), so certain rates may not be allowed with
	 * certain encodings. We have to check rates for all encodings
	 */
	memcpy(&cap->rate, rates, NRATES * sizeof(unsigned int));
	for (j = 0; j < nenc; j++) {
		rate_map = 0;
		for (i = 0; i < NRATES; i++) {
			if (sio_sun_tryinfo(hdl, &cap->enc[j], 0, 0, rates[i]))
				rate_map |= (1 << i);
		}
		for (conf = 0; conf < nconf; conf++) {
			if (cap->confs[conf].rate == rate_map) {
				cap->confs[conf].enc |= (1 << j);
				break;
			}
		}
		if (conf == nconf) {
			if (nconf == SIO_NCONF)
				break;
			cap->confs[nconf].enc = (1 << j);
			cap->confs[nconf].pchan = pchan_map;
			cap->confs[nconf].rchan = rchan_map;
			cap->confs[nconf].rate = rate_map;
			nconf++;
		}
	}
	cap->nconf = nconf;
	if (!sio_sun_setpar(&hdl->sio, &savepar))
		return 0;
	return 1;
#undef NCHANS
#undef NRATES
}
Example #22
0
struct sio_hdl *
_sio_sun_open(const char *str, unsigned int mode, int nbio)
{
	int fd, flags, fullduplex;
	struct audio_info aui;
	struct sio_sun_hdl *hdl;
	struct sio_par par;
	char path[PATH_MAX];

	switch (*str) {
	case '/':
	case ':': /* XXX: for backward compat */
		str++;
		break;
	default:
		DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str);
		return NULL;
	}
	hdl = malloc(sizeof(struct sio_sun_hdl));
	if (hdl == NULL)
		return NULL;
	_sio_create(&hdl->sio, &sio_sun_ops, mode, nbio);

	snprintf(path, sizeof(path), "/dev/audio%s", str);
	if (mode == (SIO_PLAY | SIO_REC))
		flags = O_RDWR;
	else
		flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY;

	while ((fd = open(path, flags | O_NONBLOCK)) < 0) {
		if (errno == EINTR)
			continue;
		DPERROR(path);
		goto bad_free;
	}
	if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
		DPERROR("FD_CLOEXEC");
		goto bad_close;
	}

	/*
	 * pause the device
	 */
	AUDIO_INITINFO(&aui);
	if (mode & SIO_PLAY)
		aui.play.pause = 1;
	if (mode & SIO_REC)
		aui.record.pause = 1;
	if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) {
		DPERROR("sio_open_sun: setinfo");
		goto bad_close;
	}
	/*
	 * If both play and record are requested then
	 * set full duplex mode.
	 */
	if (mode == (SIO_PLAY | SIO_REC)) {
		fullduplex = 1;
		if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0) {
			DPRINTF("sio_open_sun: %s: can't set full-duplex\n", path);
			goto bad_close;
		}
	}
	hdl->fd = fd;

	/*
	 * Default parameters may not be compatible with libsndio (eg. mulaw
	 * encodings, different playback and recording parameters, etc...), so
	 * set parameters to a random value. If the requested parameters are
	 * not supported by the device, then sio_setpar() will pick supported
	 * ones.
	 */
	sio_initpar(&par);
	par.rate = 48000;
	par.le = SIO_LE_NATIVE;
	par.sig = 1;
	par.bits = 16;
	par.appbufsz = 1200;
	if (!sio_setpar(&hdl->sio, &par))
		goto bad_close;
	return (struct sio_hdl *)hdl;
 bad_close:
	while (close(fd) < 0 && errno == EINTR)
		; /* retry */
 bad_free:
	free(hdl);
	return NULL;
}
Example #23
0
int
sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd)
{
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	struct audio_offset ao;
	int xrun, dierr = 0, doerr = 0, offset, delta;
	int revents = pfd->revents;

	if (!hdl->sio.started)
		return pfd->revents;
	if (hdl->sio.mode & SIO_PLAY) {
		if (ioctl(hdl->fd, AUDIO_GETOOFFS, &ao) < 0) {
			DPERROR("sio_sun_revents: GETOOFFS");
			hdl->sio.eof = 1;
			return POLLHUP;
		}
		delta = (ao.samples - hdl->obytes) / hdl->obpf;
		hdl->obytes = ao.samples;
		hdl->odelta += delta;
		if (!(hdl->sio.mode & SIO_REC))
			hdl->idelta += delta;
	}
	if (hdl->sio.mode & SIO_REC) {
		if (ioctl(hdl->fd, AUDIO_GETIOFFS, &ao) < 0) {
			DPERROR("sio_sun_revents: GETIOFFS");
			hdl->sio.eof = 1;
			return POLLHUP;
		}
		delta = (ao.samples - hdl->ibytes) / hdl->ibpf;
		hdl->ibytes = ao.samples;
		hdl->idelta += delta;
		if (!(hdl->sio.mode & SIO_PLAY))
			hdl->odelta += delta;
	}
	if (hdl->sio.mode & SIO_PLAY) {
		if (ioctl(hdl->fd, AUDIO_PERROR, &xrun) < 0) {
			DPERROR("sio_sun_revents: PERROR");
			hdl->sio.eof = 1;
			return POLLHUP;
		}
		doerr = xrun - hdl->oerr;
		hdl->oerr = xrun;
		if (!(hdl->sio.mode & SIO_REC))
			dierr = doerr;
		if (doerr > 0)
			DPRINTFN(2, "play xrun %d\n", doerr);
	}
	if (hdl->sio.mode & SIO_REC) {
		if (ioctl(hdl->fd, AUDIO_RERROR, &xrun) < 0) {
			DPERROR("sio_sun_revents: RERROR");
			hdl->sio.eof = 1;
			return POLLHUP;
		}
		dierr = xrun - hdl->ierr;
		hdl->ierr = xrun;
		if (!(hdl->sio.mode & SIO_PLAY))
			doerr = dierr;
		if (dierr > 0)
			DPRINTFN(2, "rec xrun %d\n", dierr);
	}

	/*
	 * GET{I,O}OFFS report positions including xruns,
	 * so we have to substract to get the real position
	 */
	hdl->idelta -= dierr;
	hdl->odelta -= doerr;

	offset = doerr - dierr;
	if (offset > 0) {
		hdl->sio.rdrop += offset * hdl->ibpf;
		hdl->idelta -= offset;
		DPRINTFN(2, "will drop %d and pause %d\n", offset, doerr);
	} else if (offset < 0) {
		hdl->sio.wsil += -offset * hdl->obpf;
		hdl->odelta -= offset;
		DPRINTFN(2, "will insert %d and pause %d\n", -offset, dierr);
	}

	delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta;
	if (delta > 0) {
		_sio_onmove_cb(&hdl->sio, delta);
		hdl->idelta -= delta;
		hdl->odelta -= delta;
	}

	if (hdl->filling)
		revents |= POLLOUT; /* XXX: is this necessary ? */
	return revents;
}
Example #24
0
static int
aucat_mkcookie(unsigned char *cookie)
{
	struct stat sb;
	char buf[PATH_MAX], tmp[PATH_MAX], *path;
	ssize_t len;
	int fd;

	/*
	 * try to load the cookie
	 */
	path = issetugid() ? NULL : getenv("AUCAT_COOKIE");
	if (path == NULL) {
		path = issetugid() ? NULL : getenv("HOME");
		if (path == NULL)
			goto bad_gen;
		snprintf(buf, PATH_MAX, "%s/.aucat_cookie", path);
		path = buf;
	}
	fd = open(path, O_RDONLY);
	if (fd < 0) {
		if (errno != ENOENT)
			DPERROR(path);
		goto bad_gen;
	}
	if (fstat(fd, &sb) < 0) {
		DPERROR(path);
		goto bad_close;
	}
	if (sb.st_mode & 0077) {
		DPRINTF("%s has wrong permissions\n", path);
		goto bad_close;
	}
	len = read(fd, cookie, AMSG_COOKIELEN);
	if (len < 0) {
		DPERROR(path);
		goto bad_close;
	}
	if (len != AMSG_COOKIELEN) {
		DPRINTF("%s: short read\n", path);
		goto bad_close;
	}
	close(fd);
	return 1;
bad_close:
	close(fd);
bad_gen:
	/*
	 * generate a new cookie
	 */
	arc4random_buf(cookie, AMSG_COOKIELEN);

	/*
	 * try to save the cookie
	 */
	if (path == NULL)
		return 1;
	if (strlcpy(tmp, path, PATH_MAX) >= PATH_MAX ||
	    strlcat(tmp, ".XXXXXXXX", PATH_MAX) >= PATH_MAX) {
		DPRINTF("%s: too long\n", path);
		return 1;
	}
	fd = mkstemp(tmp);
	if (fd < 0) {
		DPERROR(tmp);
		return 1;
	}
	if (write(fd, cookie, AMSG_COOKIELEN) < 0) {
		DPERROR(tmp);
		unlink(tmp);
		close(fd);
		return 1;
	}
	close(fd);
	if (rename(tmp, path) < 0) {
		DPERROR(tmp);
		unlink(tmp);
	}
	return 1;
}
Example #25
0
static int
sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
{
#define NRETRIES 8
	struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh;
	struct audio_info aui;
	unsigned int i, infr, ibpf, onfr, obpf;
	unsigned int bufsz, round;
	unsigned int rate, req_rate, prec, enc;

	/*
	 * try to set parameters until the device accepts
	 * a common encoding and rate for play and record
	 */
	rate = par->rate;
	prec = par->bits;
	sio_sun_enctoinfo(hdl, &enc, par);
	for (i = 0;; i++) {
		if (i == NRETRIES) {
			DPRINTF("sio_sun_setpar: couldn't set parameters\n");
			hdl->sio.eof = 1;
			return 0;
		}
		AUDIO_INITINFO(&aui);
		if (hdl->sio.mode & SIO_PLAY) {
			aui.play.sample_rate = rate;
			aui.play.precision = prec;
			aui.play.encoding = enc;
			aui.play.channels = par->pchan;
		}
		if (hdl->sio.mode & SIO_REC) {
			aui.record.sample_rate = rate;
			aui.record.precision = prec;
			aui.record.encoding = enc;
			aui.record.channels = par->rchan;
		}
		DPRINTFN(2, "sio_sun_setpar: %i: trying pars = %u/%u/%u\n",
		    i, rate, prec, enc);
		if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 && errno != EINVAL) {
			DPERROR("sio_sun_setpar: setinfo(pars)");
			hdl->sio.eof = 1;
			return 0;
		}
		if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
			DPERROR("sio_sun_setpar: getinfo(pars)");
			hdl->sio.eof = 1;
			return 0;
		}
		enc = (hdl->sio.mode & SIO_REC) ?
		    aui.record.encoding : aui.play.encoding;
		switch (enc) {
		case AUDIO_ENCODING_SLINEAR_LE:
		case AUDIO_ENCODING_SLINEAR_BE:
		case AUDIO_ENCODING_ULINEAR_LE:
		case AUDIO_ENCODING_ULINEAR_BE:
		case AUDIO_ENCODING_SLINEAR:
		case AUDIO_ENCODING_ULINEAR:
			break;
		default:
			DPRINTF("sio_sun_setpar: couldn't set linear encoding\n");
			hdl->sio.eof = 1;
			return 0;
		}
		if (hdl->sio.mode != (SIO_REC | SIO_PLAY))
			break;
		if (aui.play.sample_rate == aui.record.sample_rate &&
		    aui.play.precision == aui.record.precision &&
		    aui.play.encoding == aui.record.encoding)
			break;
		if (i < NRETRIES / 2) {
			rate = aui.play.sample_rate;
			prec = aui.play.precision;
			enc = aui.play.encoding;
		} else {
			rate = aui.record.sample_rate;
			prec = aui.record.precision;
			enc = aui.record.encoding;
		}
	}

	/*
	 * If the rate that the hardware is using is different than
	 * the requested rate, scale buffer sizes so they will be the
	 * same time duration as what was requested.  This just gets
	 * the rates to use for scaling, that actual scaling is done
	 * later.
	 */
	rate = (hdl->sio.mode & SIO_REC) ? aui.record.sample_rate :
	    aui.play.sample_rate;
	req_rate = rate;
	if (par->rate && par->rate != ~0U)
		req_rate = par->rate;

	/*
	 * if block size and buffer size are not both set then
	 * set the blocksize to half the buffer size
	 */
	bufsz = par->appbufsz;
	round = par->round;
	if (bufsz != ~0U) {
		bufsz = bufsz * rate / req_rate;
		if (round == ~0U)
			round = (bufsz + 1) / 2;
		else
			round = round * rate / req_rate;
	} else if (round != ~0U) {
		round = round * rate / req_rate;
		bufsz = round * 2;
	} else
		return 1;

	/*
	 * get the play/record frame size in bytes
	 */
	if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
		DPERROR("sio_sun_setpar: GETINFO");
		hdl->sio.eof = 1;
		return 0;
	}
	ibpf = (hdl->sio.mode & SIO_REC) ?
	    aui.record.channels * aui.record.bps : 1;
	obpf = (hdl->sio.mode & SIO_PLAY) ?
	    aui.play.channels * aui.play.bps : 1;

	DPRINTFN(2, "sio_sun_setpar: bpf = (%u, %u)\n", ibpf, obpf);

	/*
	 * try to set parameters until the device accepts
	 * a common block size for play and record
	 */
	for (i = 0; i < NRETRIES; i++) {
		AUDIO_INITINFO(&aui);
		aui.hiwat = (bufsz + round - 1) / round;
		aui.lowat = aui.hiwat;
		if (hdl->sio.mode & SIO_REC)
			aui.record.block_size = round * ibpf;
		if (hdl->sio.mode & SIO_PLAY)
			aui.play.block_size = round * obpf;
		if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0) {
			DPERROR("sio_sun_setpar2: SETINFO");
			hdl->sio.eof = 1;
			return 0;
		}
		if (ioctl(hdl->fd, AUDIO_GETINFO, &aui) < 0) {
			DPERROR("sio_sun_setpar2: GETINFO");
			hdl->sio.eof = 1;
			return 0;
		}
		infr = aui.record.block_size / ibpf;
		onfr = aui.play.block_size / obpf;
		DPRINTFN(2, "sio_sun_setpar: %i: trying round = %u -> (%u, %u)\n",
		    i, round, infr, onfr);

		/*
		 * if half-duplex or both block sizes match, we're done
		 */
		if (hdl->sio.mode != (SIO_REC | SIO_PLAY) || infr == onfr) {
			DPRINTFN(2, "sio_sun_setpar: blocksize ok\n");
			return 1;
		}

		/*
		 * half of the retries, retry with the smaller value,
		 * then with the larger returned value
		 */
		if (i < NRETRIES / 2)
			round = infr < onfr ? infr : onfr;
		else
			round = infr < onfr ? onfr : infr;
	}
	DPRINTFN(2, "sio_sun_setpar: couldn't find a working blocksize\n");
	hdl->sio.eof = 1;
	return 0;
#undef NRETRIES
}