Skip site navigation (1)Skip section navigation (2)
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>