Date: Mon, 01 Sep 1997 00:25:16 -0700 From: Amancio Hasty <hasty@rah.star-gate.com> To: Denis DeLaRoca <CSP1DWD@MVS.OAC.UCLA.EDU> Cc: multimedia@FREEBSD.ORG Subject: fix for multiple vats, was( Re: guspnp18 and vat ) Message-ID: <199709010725.AAA00272@rah.star-gate.com> In-Reply-To: Your message of "Sun, 31 Aug 1997 20:16:00 PDT." <199709010356.UAA00289@rah.star-gate.com>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
>From The Desk Of Denis DeLaRoca :
> The other outstanding problem is with passing the audio device among
> multiple active vats. That is completely broken and I think we have
> to wrestle with vat's code to find out how that is supposed to work.
The problem was in audio-voxare.cc. A separate problem
is group-ipc.cc which needs to enable local ipc multicast.
So here are both modules for vat-4.0b2
Amancio
[-- Attachment #2 --]
/*
* Copyright (c) 1991-1993 Regents of the University of California.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the Computer Systems
* Engineering Group at Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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.
*/
/* Full Duplex audio module for voxware 3.5 sound drivers or higher
This module has been tested on FreeBSD 2.1-Stable, sound driver
3.5 and a GUS PnP. If the sound card is not full duplex this
module will not work.
Amancio Hasty
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: linux_audio.cc,v 1.4 95/10/14 17:44:21 mccanne Exp $ (LBL)";
#endif
#include <osfcn.h>
#include <machine/soundcard.h>
#include "audio.h"
#include "Tcl.h"
#define ULAW_ZERO 0x7f
#define ABUFLOG2 8
#define ABUFLEN (1 << ABUFLOG2)
/*#define ABUFLEN 160*20*/
#define NFRAG 4
int foo_count = 0;
class VoxWare : public Audio {
public:
VoxWare();
virtual int FrameReady();
virtual u_char* Read();
virtual void Write(u_char *);
virtual void SetRGain(int);
virtual void SetPGain(int);
virtual void OutputPort(int);
virtual void InputPort(int);
virtual void Obtain();
virtual void Release();
virtual void RMute();
virtual void RUnmute();
protected:
u_char* readptr;
u_char* readbufend;
u_char* readbuf;
int read_len;
u_char* ubufptr;
u_char* ubufend;
u_char* ubuf;
u_char* writeptr;
u_char* writebufend;
u_char* writebuf;
int mixerfd;
int testfd;
struct timeval cur, now, write_last;
int frame_ready;
char obuff[2048];
int obuff_ptr;
u_char* zbuf;
int rgain;
int pgain;
int inputport;
};
static class VoxWareMatcher : public Matcher {
public:
VoxWareMatcher() : Matcher("audio") {}
TclObject* match(const char* fmt) {
if (strcmp(fmt, "voxware") == 0)
return (new VoxWare);
return (0);
}
} linux_audio_matcher;
extern const short mulawtolin[];
extern const unsigned char lintomulaw[];
extern const unsigned char lintomulawX[];
VoxWare::VoxWare()
{
readbuf = new u_char[ABUFLEN];
readptr = readbufend = readbuf + ABUFLEN;
writeptr = writebuf = new u_char[ABUFLEN];
writebufend = writebuf + ABUFLEN;
ubufptr = ubuf = new u_char[blksize];
ubufend = ubuf + blksize;
memset(ubuf, ULAW_ZERO, blksize);
zbuf = new u_char[blksize];
memset(zbuf, ULAW_ZERO, blksize);
iports = 2;
rgain = -1;
pgain = -1;
inputport = -1;
}
void VoxWare::Obtain()
{
int speed = 8000;
if (HaveAudio())
abort();
frame_ready = 0;
obuff_ptr = 0;
fd = open("/dev/audio", O_RDWR|O_NDELAY);
if (fd >= 0) {
int on = 1;
int frag ;
read_len = 0;
ioctl(fd,SNDCTL_DSP_NONBLOCK , &on);
frag = 160;
ioctl(fd, SNDCTL_DSP_SETBLKSIZE, &frag);
Audio::Obtain();
mixerfd = open("/dev/mixer", O_RDWR);
if (inputport >= 0 ) {
VoxWare::InputPort(inputport);
VoxWare:SetRGain(rgain);
VoxWare::SetPGain(pgain);
}
}
}
void VoxWare::Release()
{
if (HaveAudio()) {
close(mixerfd);
mixerfd = -1;
Audio::Release();
}
}
void VoxWare::Write(u_char *cp)
{
int foo, block_sound;
int msec, delta;
struct timeval write_delta;
count_info info;
gettimeofday(&write_delta, NULL);
ioctl(fd, SNDCTL_DSP_GETOPTR, &info);
block_sound = info.blocks;
while (info.blocks > 2 ) {
ioctl(fd, SNDCTL_DSP_GETOPTR, &info);
usleep(1);
}
foo = write(fd, cp, blksize);
gettimeofday(&now, NULL);
delta = ((1000 * now.tv_sec) + now.tv_usec / 1000) -
((1000 * write_delta.tv_sec) + write_delta.tv_usec / 1000);
msec = ((1000 * now.tv_sec) + now.tv_usec / 1000) -
((1000 * write_last.tv_sec) + write_last.tv_usec / 1000);
/* printf("write msec %d delta %d byte %d \n", msec, delta, info.bytes); */
write_last = now;
}
u_char* VoxWare::Read()
{
u_char* cp;
int i = read_len;
int msec;
cp = readbuf;
i = 0;
while (i == 0 ) {
i = read(fd, cp, blksize);
}
if (i < 150 ) printf("read xxx %d \n", i);
cur = now;
return cp;
}
void VoxWare::SetRGain(int level)
{
float x = level;
rgain = level;
level = (int) (x/2.56);
int foo = level<<8 | level;
int zero;
if (!HaveAudio() ) {
return;
}
if (iport) {
/* for the gus pnp line3 is line input :( */
if (ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_LINE1), &foo) == -1) {
printf("failed set input line volume \n");
}
} else {
if (ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_MIC), &foo) == -1) {
printf("failed to set mic volume \n");
}
}
}
void VoxWare::SetPGain(int level)
{
float x = level;
pgain = level;
level = (int) (x/2.56);
int foo = level<<8 | level;
if (!HaveAudio() ) {
return;
}
if (ioctl(mixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &foo) == -1) {
printf("failed to output level %x \n", level);
}
}
void VoxWare::OutputPort(int p)
{
oport = p;
}
void VoxWare::InputPort(int p)
{
int zero = 0;
int foo = rgain<<8 | rgain;
inputport = p;
if (!HaveAudio() ) {
return;
}
if (p) {
/* for the gus pnp line input is line3 :( */
zero = 1 << SOUND_MIXER_LINE3;
if (ioctl(mixerfd, SOUND_MIXER_WRITE_RECSRC, &zero) == -1) {
printf("failed to select line input \n");
}
} else {
zero = 1 << SOUND_MIXER_MIC;
if ( ioctl(mixerfd, SOUND_MIXER_WRITE_RECSRC, &zero) == -1 ) {
printf("failed to select mic input \n");
}
}
iport = p;
}
void VoxWare::RMute()
{
rmute |= 1;
}
void VoxWare::RUnmute()
{
rmute &=~ 1;
}
int VoxWare::FrameReady()
{
int i, io;
count_info info;
io = ioctl(fd, SNDCTL_DSP_GETIPTR, &info);
if (info.blocks > 0 )
frame_ready = 1;
else frame_ready = 0;
return frame_ready;
}
[-- Attachment #3 --]
/*
* Copyright (c) 1991-1994 Regents of the University of California.
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and the Network Research Group at
* Lawrence Berkeley Laboratory.
* 4. Neither the name of the University nor of the Laboratory may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS 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.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Header: group-ipc.cc,v 1.21 96/02/06 14:43:30 mccanne Exp $ (LBL)";
#endif
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <winsock.h>
#define close closesocket
#else
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#endif
#include <fcntl.h>
#include "group-ipc.h"
#define GROUP_IPC_ADDR 0xe0ffdeef
#define GROUP_IPC_PORT 0xdeaf
static void nonblock(int fd)
{
#ifdef WIN32
u_long flag = 1;
if (ioctlsocket(fd, FIONBIO, &flag) == -1) {
fprintf(stderr, "ioctlsocket: FIONBIO: %lu\n", GetLastError());
exit(1);
}
#else
int flags = fcntl(fd, F_GETFL, 0);
#if defined(hpux) || defined(__hpux)
flags |= O_NONBLOCK;
#else
flags |= O_NONBLOCK|O_NDELAY;
#endif
if (fcntl(fd, F_SETFL, flags) == -1) {
perror("fcntl: F_SETFL");
exit(1);
}
#endif
}
IPCHandler::IPCHandler(int mask) : mask_(mask) { }
#ifdef IP_ADD_MEMBERSHIP
GroupIPC::GroupIPC(int channel) : handlers_(0)
{
rsock_ = socket(AF_INET, SOCK_DGRAM, 0);
if (rsock_ < 0) {
perror("socket");
exit(1);
}
int on = 1;
if (setsockopt(rsock_, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
sizeof(on)) < 0) {
perror("SO_REUSEADDR");
exit(1);
}
#ifdef SO_REUSEPORT
on = 1;
if (setsockopt(rsock_, SOL_SOCKET, SO_REUSEPORT, (char *)&on,
sizeof(on)) < 0) {
perror("SO_REUSEPORT");
exit(1);
}
#endif
sockaddr_in sin;
memset((char *)&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
int port = htons(GROUP_IPC_PORT + channel);
sin.sin_port = port;
sin.sin_addr.s_addr = htonl(GROUP_IPC_ADDR);
if (bind(rsock_, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(rsock_, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("GroupIPC bind");
close(rsock_);
rsock_ = -1;
ssock_ = -1;
}
}
if (rsock_ >= 0) {
nonblock(rsock_);
struct ip_mreq mr;
mr.imr_multiaddr.s_addr = htonl(GROUP_IPC_ADDR);
mr.imr_interface.s_addr = htonl(INADDR_LOOPBACK);
if (setsockopt(rsock_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(char *)&mr, sizeof(mr)) < 0) {
/*
* host probably doesn't have multicast
*/
close(rsock_);
rsock_ = -1;
ssock_ = -1;
}
}
if (rsock_ >= 0) {
link(rsock_, TK_READABLE);
ssock_ = socket(AF_INET, SOCK_DGRAM, 0);
if (ssock_ < 0) {
perror("GroupIPC socket");
exit(1);
}
sin.sin_port = 0;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (bind(ssock_, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("GroupIPC bind");
exit(1);
}
sin.sin_port = port;
sin.sin_addr.s_addr = htonl(GROUP_IPC_ADDR);
if (connect(ssock_, (struct sockaddr*)&sin, sizeof(sin)) < 0) {
perror("GroupIPC connect");
exit(1);
}
char ttl = 0;
if (setsockopt(ssock_, IPPROTO_IP, IP_MULTICAST_TTL,
&ttl, 1) < 0) {
perror("GroupIPC: IP_MULTICAST_TTL");
exit(1);
}
u_int32_t addr = htonl(INADDR_LOOPBACK);
if (setsockopt(ssock_, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&addr, 4) < 0) {
perror("GroupIPC: IP_MULTICAST_IF");
exit(1);
}
#if defined(ultrix) || defined(__FreeBSD__)
ttl = 1;
if (setsockopt(ssock_, IPPROTO_IP, IP_MULTICAST_LOOP,
&ttl, 1) < 0) {
perror("GroupIPC: IP_MULTICAST_LOOP");
exit(1);
}
#endif
}
pid_ = getpid();
}
#else
GroupIPC::GroupIPC(int channel) : handlers_(0), rsock_(-1), ssock_(-1)
{
}
#endif
GroupIPC::~GroupIPC()
{
if (rsock_ >= 0)
(void)close(rsock_);
if (ssock_ >= 0)
(void)close(ssock_);
}
void GroupIPC::send(int type, int len)
{
ipchdr* h = (ipchdr*)buffer_;
h->type = type;
h->pid = pid_;
h->magic = GIPC_MAGIC;
len += sizeof(*h);
if (ssock_ >= 0 && ::send(ssock_, (char*)buffer_, len, 0) < 0)
perror("GroupIPC send");
}
void GroupIPC::send(int type, const char* msg)
{
strcpy((char*)buffer(), msg);
/* include null terminator */
send(type, strlen(msg) + 1);
}
void GroupIPC::attach(IPCHandler *h)
{
h->next_ = handlers_;
handlers_ = h;
}
void GroupIPC::dispatch(int)
{
int cc = recv(rsock_, (char*)buffer_, sizeof(buffer_), 0);
if (cc < 0) {
perror("GroupIPC: recv");
return;
}
cc -= sizeof(ipchdr);
if (cc < 0)
return;
ipchdr* h = (ipchdr*)buffer_;
if (h->pid == pid_)
return;
int bit = 1 << h->type;
for (IPCHandler* p = handlers_; p != 0; p = p->next_) {
if (p->mask() & bit)
p->ipc_input(h->type, h->pid, (u_char*)(h + 1), cc);
}
}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199709010725.AAA00272>
