Re: Skype and alsa jack-plugin -> xruns (buffer underruns)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Użytkownik Mark napisał:
> I am trying to route the audio connection from Skype to JACK by using the alsa
> jack-plugin after having tried oss2jack and artsdsp without positive results.
> The connection works well for about 10 seconds (both ways capture and playback),
> and then starts running into trouble. This is independent from the device driver
> jackd is using (I tried ALSA and freebob, both crash with xruns). jackd leaves
> hundreds of fifo-files in /dev/shm/jack-1000 after the crash that have to be
> deleted manually in order to use jackd again. When I run jackd with verbose
> output it even reports a "too many open files" error.
>   
In this version of Skype there is an error while opening /dev/dsp device
- previously
opened fd sometimes is not closed so you get "too many open files" after
some time.

Additionally Skype opens dsp device in RW mode works not properly with
typical virtualization of recording and playing with OSS from
www.opensound.com.
The same applay to Macromedia Flash plugin.

You can use a small wrapper called dsp_hijacker and use Skype:

$ dsp_hijacker skype

Of course it is not the best solutions but it works.
Regards

-- 
Adam Tlałka       mailto:atlka@xxxxxxxxx    ^v^ ^v^ ^v^
System  & Network Administration Group       - - - ~~~~~~
Computer Center,  Gdańsk University of Technology, Poland
PGP public key:   finger atlka@xxxxxxxxxxxxxxxxx

#!/bin/bash
#
# setup dsp_hijacker preload to hijack calls made
# to /dev/dsp and /dev/mixer
#
#This script runs program with libskype_dsp_hijacker.so"filter"
# -- CONFIGURATION --

#default configuration when no option is specified

#"catch" when prog is trying to use DSP (microphone/speakers) device
export HIJACKDSP="/dev/dsp"
#"catch" when program is trying to use mixer
export HIJACKMIXER="/dev/mixer"

#real device that will be used for microphone
export MICDEV="/dev/dsp10"
#real device that will be used for speakers 
export SPEAKERDEV="/dev/dsp2"
#real device that will be used for mixer
export MIXERDEV="/dev/mixer"

# -- CONFIGURATION END --

function help {
cat <<EOT

Redirect program microphone/speakers

Options:
 --1st           Use 1st sound card (default)
 --2nd           Use 2nd sound card 
 --speakers2nd   Use 1st sound card microphone & 2nd sound card speakers
 --speakers3rd   Use 1st sound card microphone & 3rd sound card speakers
 --mic2nd        Use 2nd sound card microphone & 1st sound card speakers

Edit the script for full flexibility

EOT
}
  

case "$1" in 
  -h|--help) help; exit;;
  --1st) 
    export MICDEV="/dev/dsp"
    export SPEAKERDEV="/dev/dsp"
    export MIXERDEV="/dev/mixer"
    shift
    ;;
  --2nd) 
    export MICDEV="/dev/dsp1"
    export SPEAKERDEV="/dev/dsp1"
    export MIXERDEV="/dev/mixer1"
    shift
    ;;
  --speakers2nd) 
    export MICDEV="/dev/dsp"
    export SPEAKERDEV="/dev/dsp1"
    export MIXERDEV="/dev/mixer1"
    shift
    ;;
  --speakers3rd) 
    export MICDEV="/dev/dsp"
    export SPEAKERDEV="/dev/dsp2"
    export MIXERDEV="/dev/mixer2"
    shift
    ;;
  --mic2nd) 
    export MICDEV="/dev/dsp1"
    export SPEAKERDEV="/dev/dsp"
    export MIXERDEV="/dev/mixer"
    shift
    ;;
esac




  



prefix=/usr/local
exec_prefix=${prefix}

#prefer use of libdsp_hijacker from current directory
if test -f ./libdsp_hijacker.so; then 
  libdir=.
else
  libdir=${exec_prefix}/lib
fi

LD_PRELOAD=${libdir}/libdsp_hijacker.so
if test -f /lib/libdl.so.2; then
	LD_PRELOAD=$LD_PRELOAD:/lib/libdl.so.2
fi
export LD_PRELOAD

# invoke the program with the args given
exec "$@"
CC=gcc
CFLAGS=-O2 -Wall -m32
LIBADD_DL=-ldl
OPTIONS=-shared -fpic

PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
LIBDIR=$(PREFIX)/lib

all:
	$(CC) $(CFLAGS) $(LIBADD_DL) $(OPTIONS) dsp_hijacker.c -o libdsp_hijacker.so

install:
	cp libdsp_hijacker.so $(LIBDIR)
	chmod 0755 $(LIBDIR)/libdsp_hijacker.so
	cp dsp_hijacker $(BINDIR)
	chmod 0755 $(BINDIR)/dsp_hijacker
	
clean:
#	rm -f *~
	rm -f libdsp_hijacker.so
/* dsp_hijacker 0.8 - redirect the open system call to a second dsp device.
 *                        - patch for separate devices
 *                        - workaround a bug introduced in Skype 1.2.0.11
 *
 * Copyright (C) 2004 <snow-x@xxxxxx>
 * Copyright (C) 2005 <jan@xxxxxxxxxxx>
 * Copyright (C) 2005-2006 Jan Slupski <jslupski@xxxxxxxxxx>
 * Copyright (C) 2005 _26oo_ user of Skype Forum
 * Copyright (C) 2006 Romano Giannetti <romano@xxxxxxxxxxxxxxxxxxxxxx>
 * Copyright (C) 2006 Adam Tlalka <atlka@xxxxxxxxx> 
 *
 * Special thanks to the KDE Project for arts. This program is based on artsdsp.
 * Copyright (C) 1998 Manish Singh <yosh@xxxxxxxx>
 * Copyright (C) 2000 Stefan Westerfeld <stefan@xxxxxxxxxxxx> (aRts port)
 * 
 * Resources:
 *  [http://suedpol.dyndns.org/skype/]
 *  http://195.38.3.142:6502/skype/
 *  http://juljas.net/linux/skype/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#define HIJACKER_VERSION "0.8"

#define _GNU_SOURCE

#include <dlfcn.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/soundcard.h>
//#include <ansidecl.h>

//the redirected dsp device (override with environment variable HIJACKDSP)
#define HIJACKDSP "/dev/dsp"
//the redirected mixer  (override with environment variable HIJACKMIXER)
#define HIJACKMIXER "/dev/mixer"
//the real device that will be used for
//microphone (override with environment variable MICDEV)
#define MICDEV "/dev/dsp"
//speakers (override with environment variable SPEAKERDEV)
#define SPEAKERDEV "/dev/dsp"
//mixer (override with environment variable MIXERDEV)
#define MIXERDEV "/dev/mixer"

//debug
//0 - no messages
//1 - only very basic messages (recommended)
//2 - more output on opening/closing sound devices
//3 - lots of messages on open/close actions
#define DEBUG_HIJACKER 1
#define DBG_0(fmt, args...) fprintf(stderr,"dsp_hijacker: " fmt "\n", ## args );

#if DEBUG_HIJACKER > 0
#define DBG_1(fmt, args...) DBG_0(fmt, ## args )
#define DBGL_1(fmt, lbl, args...) { DBG_0(fmt, ## args ) goto lbl;}
#define LBL_1(lbl) lbl:
#else
#define DBG_1(fmt, args...) ;
#define DBGL_1(fmt, args...) ;
#define LBL_1(lbl)
#endif

#if DEBUG_HIJACKER > 1
#define DBG_2(fmt, args...) DBG_0(fmt, ## args )
#define DBGL_2(fmt, lbl, args...) { DBG_0(fmt, ## args ) goto lbl;}
#define LBL_2(lbl) lbl:
#else
#define DBG_2(fmt, args...) ;
#define DBGL_2(fmt, args...) ;
#define LBL_2(lbl)
#endif

#if DEBUG_HIJACKER > 2
#define DBG_3(fmt, args...) DBG_0(fmt, ## args )
#define DBGL_3(fmt, lbl, args...) { DBG_0(fmt, ## args ) goto lbl;}
#define LBL_3(lbl) lbl:
#else
#define DBG_3(fmt, args...) ;
#define DBGL_3(fmt, args...) ;
#define LBL_3(lbl)
#endif

static int micfd = -1, speakerfd = -1;
static char *final_mic,	*final_speaker, *final_mixer, *dsp, *mixer;

//original C Library functions
static ssize_t (*orig_read)(int, void *, size_t);
static int (*orig_ioctl)(int, unsigned long, ...);
static int (*orig_close)(int);
static int (*orig_open)(const char *, int, ...);

ssize_t read(int fd, void *buf, size_t count)
{
	//reroute reads to mic (that can be other device than speaker)
	if (fd == speakerfd){
		DBG_2("read(%d,,%d) from mic fd %d", fd, count, micfd)
		fd = micfd;
	} else
		DBG_3("read(%d,,%d)", fd, count)
	return orig_read(fd, buf, count);
}

int ioctl(int fd, int request, char *argp)
{
	//clone or redirect ioctl of speaker to mic if needed
	if(fd == speakerfd){
		switch (request){
		case SNDCTL_DSP_GETIPTR: DBGL_2("ioctl(%d, SNDCTL_DSP_GETIPTR,)", lbl1, fd)
		case SNDCTL_DSP_GETISPACE: DBG_2("ioctl(%d, SNDCTL_DSP_GETISPACE,)", fd)
			LBL_2(lbl1)
			fd = micfd;
			break;
		case SNDCTL_DSP_GETODELAY: DBGL_2("ioctl(%d, SNDCTL_DSP_GETODELAY,)", lbl2, fd)
		case SNDCTL_DSP_GETOPTR: DBGL_2("ioctl(%d, SNDCTL_DSP_GETOPTR,)", lbl2, fd)
		case SNDCTL_DSP_GETOSPACE: DBGL_2("ioctl(%d, SNDCTL_DSP_GETOSPACE,)", lbl2, fd)
		case SNDCTL_DSP_GETFMTS: DBGL_2("ioctl(%d, SNDCTL_DSP_GETFMTS,)", lbl2, fd)
		case SNDCTL_DSP_GETBLKSIZE: DBG_2("ioctl(%d, SNDCTL_DSP_GETBLKSIZE,)", fd)
			LBL_2(lbl2)				
			break;
		case SNDCTL_DSP_GETCAPS:
			DBG_2("ioctl(%d, SNDCTL_DSP_GETCAPS,)", fd)
			(void) orig_ioctl(fd, request, argp);
			*(int *)argp &= ~(DSP_CAP_MMAP|DSP_CAP_TRIGGER);
			return 0;
		case SNDCTL_DSP_GETTRIGGER: DBGL_2("ioctl(%d, SNDCTL_DSP_GETTRIGGER,)", lbl4, fd)
		case SNDCTL_DSP_SETTRIGGER: DBGL_2("ioctl(%d, SNDCTL_DSP_SETTRIGGER,)", lbl4, fd)
		case SNDCTL_DSP_MAPINBUF: DBGL_2("ioctl(%d, SNDCTL_DSP_MAPINBUF,)", lbl4, fd)
		case SNDCTL_DSP_MAPOUTBUF: DBGL_2("ioctl(%d, SNDCTL_DSP_MAPOUTBUF,)", lbl4, fd)
		case SNDCTL_DSP_SETSYNCRO: DBGL_2("ioctl(%d, SNDCTL_DSP_SETSYNCRO,)", lbl4, fd)
		case SNDCTL_DSP_NONBLOCK: DBGL_2("ioctl(%d, SNDCTL_DSP_NONBLOCK,)", lbl4, fd)
		case SNDCTL_DSP_SUBDIVIDE: DBGL_2("ioctl(%d, SNDCTL_DSP_SUBDIVIDE,)",lbl4, fd)
		case SNDCTL_DSP_SETDUPLEX: DBG_2("ioctl(%d, SNDCTL_DSP_SETDUPLEX,)", fd)
			LBL_2(lbl4)
			DBG_2("not implemented ioctl returning -1");
			errno = EINVAL;
			return -1;
#if DEBUG_HIJACKER > 1
		case SNDCTL_DSP_RESET: DBGL_2("ioctl(%d, SNDCTL_DSP_RESET,)", lbl5, fd)
		case SNDCTL_DSP_SYNC: DBGL_2("ioctl(%d, SNDCTL_DSP_SYNC,)", lbl5, fd)
		case SNDCTL_DSP_POST: DBGL_2("ioctl(%d, SNDCTL_DSP_POST,)", lbl5, fd)
		case SNDCTL_DSP_SETFRAGMENT: DBGL_2("ioctl(%d, SNDCTL_DSP_SETFRAGMENT,)", lbl5, fd)
		case SNDCTL_DSP_CHANNELS: DBGL_2("ioctl(%d, SNDCTL_DSP_CHANNELS,)", lbl5, fd)
		case SNDCTL_DSP_STEREO: DBGL_2("ioctl(%d, SNDCTL_DSP_STEREO,)", lbl5, fd)
		case SNDCTL_DSP_SETFMT: DBGL_2("ioctl(%d, SNDCTL_DSP_SETFMT,)", lbl5, fd)
		case SNDCTL_DSP_SPEED: DBGL_2("ioctl(%d, SNDCTL_DSP_SPEED,)", lbl5, fd)
#endif
		default: DBG_2("ioctl(%d,0x%x,)", fd, request);
			LBL_2(lbl5)
			DBG_2("to both speaker and mic");
			(void) orig_ioctl(micfd, request, argp);
		}
	} else
		DBG_3("ioctl(%d,0x%x,)", fd, request)
	return orig_ioctl(fd, request, argp);
}

int close(int fd)
{
	if(fd == speakerfd){
		register int ofd = micfd;
		DBG_1("close(%d) closing mic fd %d and dsp fd %d",
		      fd, micfd, fd);
		micfd = speakerfd = -1;
		if(ofd >= 0)
			(void) orig_close(ofd);
	} else if(fd == micfd){
		DBG_1("close(%d) wrong fd !", fd)
		return 0;
	} else
		DBG_3("close(%d)", fd)
	return orig_close(fd);
}

int open(const char *pathname, int flags, ...)
{
	mode_t mode = 0;
	va_list args;
	va_start(args,flags);
	if(flags & O_CREAT){
		if(sizeof(int) >= sizeof(mode_t))
			mode = va_arg(args, int);
		else
			mode = va_arg(args, mode_t);
	}
	va_end(args);

	/*
	 * If 'open' is trying to open the configured dsp device, it gets a new
	 * pathname of the chosen sound device. The same with the mixer
	 * device.
	 */
	if(!strcmp(pathname, dsp)){
		if(flags & O_RDWR){
			int oerrno;
			if(speakerfd >= 0){//bad skype behaviour
				DBG_1("open(%s,%d,) DSP wasn't closed",
				      pathname, flags);
				close(speakerfd);
			}
			if((speakerfd = orig_open(final_speaker,
						  O_WRONLY, mode)) >= 0){
				if((micfd = orig_open(final_mic,
						      O_RDONLY, mode)) < 0){
					oerrno = errno;
					(void) close(speakerfd);
				} else
					oerrno = 0;
			} else
				oerrno = errno;
			
			DBG_1("open(%s,%d,) speaker %s fd %d mic %s fd %d",
			      pathname, flags,
			      final_speaker, speakerfd,
			      final_mic, micfd);
			
			if(oerrno)
				errno = oerrno;
			//return speaker fd that will be later reference for bot micfd & speakerfd
			return speakerfd;
		}
	} else if(!strcmp(pathname, mixer)){
		int oerrno;
		int fd = orig_open (final_mixer, flags, mode);//original open
		oerrno = errno;
		DBG_1("open(%s,%d) opened %s fd %d", pathname, flags, final_mixer, fd);
                if (oerrno)
			errno = oerrno;
		return fd;
	}
	return orig_open (pathname, flags, mode);//original open
}

static void initialize() __attribute__ ((constructor));
static void initialize()
{
	//save original functions
	orig_open = dlsym(RTLD_NEXT,"open");
	orig_close = dlsym(RTLD_NEXT,"close");
	orig_read = dlsym(RTLD_NEXT,"read");
	orig_ioctl = dlsym(RTLD_NEXT,"ioctl");
	
	if(!(dsp=getenv("HIJACKDSP")))
		dsp=HIJACKDSP;
	
	if(!(mixer=getenv("HIJACKMIXER")))
		mixer=HIJACKMIXER;
	
	if(!(final_mixer = getenv("MIXERDEV")))
		final_mixer = MIXERDEV;
	
	if(!(final_mic = getenv("MICDEV")))
		final_mic = MICDEV;
	
	if(!(final_speaker = getenv("SPEAKERDEV")))
		final_speaker = SPEAKERDEV;
	
	DBG_1("version v%s debug level %d", HIJACKER_VERSION, DEBUG_HIJACKER);
	DBG_1("dsp %s uses mic %s and speaker %s", dsp, final_mic, final_speaker);
	DBG_1("mixer %s uses %s", mixer, final_mixer);
}
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Alsa-user mailing list
Alsa-user@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-user

[Index of Archives]     [ALSA Devel]     [Linux Audio Users]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]

  Powered by Linux