commited changes to enable Jack support

thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
This commit is contained in:
darkeye 2005-04-04 08:36:18 +00:00
parent 806550e495
commit 09e7e0ab53
18 changed files with 900 additions and 58 deletions

View File

@ -22,4 +22,5 @@ with contributions by:
Robert Lunnon <bobl@optushome.com.au>
Enrico Ardizzoni <craken@users.sourceforge.net>
Deti Fliegl <deti@fliegl.de>
Nicholas J. Humfrey <njh@ecs.soton.ac.uk>

View File

@ -4,6 +4,9 @@ DarkIce next release
since it is not implemented in OpenBSD / NetBSD
o added possibility to downsample from stereo to mono when encoding
to Ogg Vorbis, thanks to Deti Fliegl, <deti@fliegl.de>
o added support for Jack inputs, enabling a lot of interesting usage,
including support for MacOS X.
Thanks to Nicholas J. Humfrey <njh@ecs.soton.ac.uk>
15-02-2004: DarkIce 0.14 released

View File

@ -1,9 +1,11 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(src/DarkIce.cpp)
AM_INIT_AUTOMAKE(darkice, 0.15beta)
AC_INIT(darkice, 0.15beta)
AC_CONFIG_SRCDIR(src/DarkIce.cpp)
AM_CONFIG_HEADER(src/config.h)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
@ -155,6 +157,24 @@ else
fi
dnl-----------------------------------------------------------------------------
dnl link JACK sound server if requested
dnl-----------------------------------------------------------------------------
AC_SUBST(JACK_CFLAGS)
AC_SUBST(JACK_LIBS)
AC_ARG_WITH( jack,
[ --with-jack use JACK audio server [yes] ],
USE_JACK=${withval}, USE_JACK="yes" )
if test "x${USE_JACK}" = "xyes" ; then
PKG_CHECK_MODULES(JACK, jack,
AC_DEFINE( HAVE_JACK_LIB, 1, [build with JACK audio server support] )
)
else
AC_MSG_RESULT( [building without JACK support] )
fi
dnl-----------------------------------------------------------------------------
dnl check for MSG_NOSIGNAL for the send() function in libsocket
dnl-----------------------------------------------------------------------------
@ -171,6 +191,12 @@ AC_TRY_COMPILE([#include <sys/socket.h>], [
])
dnl-----------------------------------------------------------------------------
dnl check for POSIX real-time scheduling
dnl-----------------------------------------------------------------------------
AC_CHECK_FUNCS( sched_getscheduler sched_getparam )
dnl-----------------------------------------------------------------------------
dnl enable compilation with debug flags
dnl-----------------------------------------------------------------------------

View File

@ -90,6 +90,7 @@ Developed with contributions by
Robert Lunnon <bobl@optushome.com.au>
Enrico Ardizzoni <craken@users.sourceforge.net>
Deti Fliegl <deti@fliegl.de>
Nicholas J. Humfrey <njh@ecs.soton.ac.uk>
.SH LINKS
Project homepage:

View File

@ -60,8 +60,12 @@ Required values:
.TP
.I device
OSS DSP audio device to record from (e.g. /dev/dsp) or ALSA DSP device name
(e.g. hwplug:0,0)
Specify the device to record from, which can be an OSS DSP device,
an ALSA source or you can use Jack audio.
- OSS DSP audio device to record from (e.g. /dev/dsp)
- ALSA DSP device name (e.g. hwplug:0,0)
- the string 'jack', to have an unconnected Jack port, or
'jack_auto' to automatically make Jack connect to the first source.
.TP
.I sampleRate
The sample rate to record with, samples per second

View File

@ -260,7 +260,7 @@ AlsaDspSource :: read ( void * buf,
} while (ret == -EAGAIN);
if ( ret < 0 ) {
throw new Exception(__FILE__, __LINE__, snd_strerror(ret));
throw Exception(__FILE__, __LINE__, snd_strerror(ret));
}
running = true;
@ -292,6 +292,10 @@ AlsaDspSource :: close ( void ) throw ( Exception )
$Source$
$Log$
Revision 1.4 2005/04/04 08:36:16 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.3 2005/04/03 05:00:14 jbebel
Fixing code documentation of buffer overruns

View File

@ -65,6 +65,7 @@ AudioSource :: createDspSource( const char * deviceName,
int channel)
throw ( Exception )
{
if ( Util::strEq( deviceName, "/dev", 4) ) {
#if defined( SUPPORT_OSS_DSP )
Reporter::reportEvent( 1, "Using OSS DSP input device:", deviceName);
@ -79,9 +80,21 @@ AudioSource :: createDspSource( const char * deviceName,
bitsPerSample,
channel);
#else
throw new Exception( __FILE__, __LINE__,
throw Exception( __FILE__, __LINE__,
"trying to open OSS or Solaris DSP device "
"without support compiled", deviceName);
#endif
} else if ( Util::strEq( deviceName, "jack", 4) ) {
#if defined( SUPPORT_JACK_DSP )
Reporter::reportEvent( 1, "Using JACK audio server as input device.");
return new JackDspSource( deviceName,
sampleRate,
bitsPerSample,
channel);
#else
throw Exception( __FILE__, __LINE__,
"trying to open JACK device without "
"support compiled", deviceName);
#endif
} else {
#if defined( SUPPORT_ALSA_DSP )
@ -91,7 +104,7 @@ AudioSource :: createDspSource( const char * deviceName,
bitsPerSample,
channel);
#else
throw new Exception( __FILE__, __LINE__,
throw Exception( __FILE__, __LINE__,
"trying to open ALSA DSP device without "
"support compiled", deviceName);
#endif
@ -104,6 +117,10 @@ AudioSource :: createDspSource( const char * deviceName,
$Source$
$Log$
Revision 1.3 2005/04/04 08:36:16 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.2 2004/02/15 22:26:16 darkeye
fixed typo, minimal cosmetic change

View File

@ -33,6 +33,9 @@
#error This is a C++ include file
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* ============================================================ include files */
@ -50,21 +53,27 @@
*----------------------------------------------------------------------------*/
#if defined( HAVE_ALSA_LIB )
// we have an ALSA sound system available
#define SUPPORT_ALSA_DSP
#define SUPPORT_ALSA_DSP 1
#endif
#if defined( HAVE_SYS_SOUNDCARD_H )
// we have an OSS DSP sound source device available
#define SUPPORT_OSS_DSP
#define SUPPORT_OSS_DSP 1
#endif
#if defined( HAVE_SYS_AUDIO_H ) || defined( HAVE_SYS_AUDIOIO_H )
// we have a Solaris DSP sound device available (same for OpenBSD)
#define SUPPORT_SOLARIS_DSP
#define SUPPORT_SOLARIS_DSP 1
#endif
#if defined( HAVE_JACK_LIB )
// we have JACK audio server
#define SUPPORT_JACK_DSP 1
#endif
#if !defined( SUPPORT_ALSA_DSP ) \
&& !defined( SUPPORT_OSS_DSP ) \
&& !defined( SUPPORT_JACK_DSP ) \
&& !defined( SUPPORT_SOLARIS_DSP )
// there was no DSP audio system found
#error No DSP audio input device found on system
@ -212,7 +221,14 @@ class AudioSource : public Source, public virtual Reporter
* @return true if the data is big endian, false if little endian
*/
virtual bool
isBigEndian ( void ) const throw () = 0;
isBigEndian ( void ) const throw ()
{
#ifdef WORDS_BIGENDIAN
return true;
#else
return false;
#endif
}
/**
* Get the sample rate per seconds for this AudioSource.
@ -275,6 +291,9 @@ class AudioSource : public Source, public virtual Reporter
#include "SolarisDspSource.h"
#endif
#if defined( SUPPORT_JACK_DSP )
#include "JackDspSource.h"
#endif
/* ====================================================== function prototypes */
@ -288,6 +307,10 @@ class AudioSource : public Source, public virtual Reporter
$Source$
$Log$
Revision 1.8 2005/04/04 08:36:16 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.7 2004/02/18 21:08:11 darkeye
ported to OpenBSD (real-time scheduling not yet supported)

View File

@ -873,9 +873,8 @@ DarkIce :: configFileCast ( const Config & config )
void
DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
{
// don't include the following on OpenBSD / NetBSD, as the scheduling
// functions are not implemented.
#if !defined( __OpenBSD__ ) && !defined( __NetBSD__ )
// Only if the OS has the POSIX real-time scheduling functions implemented.
#if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
uid_t euid;
euid = geteuid();
@ -921,9 +920,9 @@ DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
"It is recommended that you run this program as super-user");
}
#else
reportEvent( 1, "POSIX scheduling not supported on OpenBSD / NetBSD, "
reportEvent( 1, "POSIX scheduling not supported on this system, "
"this may cause recording skips");
#endif // !__OpenBSD__ && !__NetBSD__
#endif // HAVE_SCHED_GETSCHEDULER && HAVE_SCHED_GETPARAM
}
@ -935,9 +934,8 @@ DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
void
DarkIce :: setOriginalScheduling ( void ) throw ( Exception )
{
// don't include the following on OpenBSD / NetBSD, as the scheduling
// functions are not implemented.
#if !defined( __OpenBSD__ ) && !defined( __NetBSD__ )
// Only if the OS has the POSIX real-time scheduling functions implemented.
#if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
uid_t euid;
euid = geteuid();
@ -957,7 +955,7 @@ DarkIce :: setOriginalScheduling ( void ) throw ( Exception )
reportEvent( 5, "reverted to original scheduling");
}
#endif // !__OpenBSD__ && !__NetBSD__
#endif // HAVE_SCHED_GETSCHEDULER && HAVE_SCHED_GETPARAM
}
@ -1010,6 +1008,10 @@ DarkIce :: run ( void ) throw ( Exception )
$Source$
$Log$
Revision 1.42 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.41 2005/04/03 05:12:20 jbebel
Changed mechanism for testing the presence of the quality value such that
zero is a valid option.

View File

@ -58,7 +58,7 @@
#include "AudioEncoder.h"
#include "TcpSocket.h"
#include "CastSink.h"
#include "Config.h"
#include "DarkIceConfig.h"
/* ================================================================ constants */
@ -309,6 +309,10 @@ class DarkIce : public virtual Referable, public virtual Reporter
$Source$
$Log$
Revision 1.15 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.14 2002/05/28 12:35:41 darkeye
code cleanup: compiles under gcc-c++ 3.1, using -pedantic option

View File

@ -4,7 +4,7 @@
Tyrell Config
File : Config.cpp
File : DarkIceConfig.cpp
Version : $Revision$
Author : $Author$
Location : $Source$
@ -38,7 +38,7 @@
#include <iostream>
#include "Config.h"
#include "DarkIceConfig.h"
/* =================================================== local data structures */
@ -170,6 +170,10 @@ Config :: read ( std::istream & is ) throw ( Exception )
$Source$
$Log$
Revision 1.1 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.7 2002/05/28 12:35:41 darkeye
code cleanup: compiles under gcc-c++ 3.1, using -pedantic option

View File

@ -4,7 +4,7 @@
Tyrell Config
File : Config.h
File : DarkIceConfig.h
Version : $Revision$
Author : $Author$
Location : $Source$
@ -213,6 +213,10 @@ class Config : public virtual Referable
$Source$
$Log$
Revision 1.1 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.5 2002/05/28 12:35:41 darkeye
code cleanup: compiles under gcc-c++ 3.1, using -pedantic option

View File

@ -0,0 +1,454 @@
/*------------------------------------------------------------------------------
Copyright (c) 2005 Nicholas Humfrey. All rights reserved.
Tyrell DarkIce
File : JackDspSource.cpp
Version : $Revision$
Author : $Author$
Location : $Source$
Copyright notice:
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
/* ============================================================ include files */
#include "AudioSource.h"
#ifdef SUPPORT_JACK_DSP
// only compile this code if there is support for it
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistd.h
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#else
#error need string.h
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#else
#error need sys/types.h
#endif
#ifdef HAVE_MATH_H
#include <math.h>
#else
#error need math.h
#endif
#include "Util.h"
#include "Exception.h"
#include "JackDspSource.h"
/* =================================================== local data structures */
/* ================================================ local constants & macros */
/*------------------------------------------------------------------------------
* File identity
*----------------------------------------------------------------------------*/
static const char fileid[] = "$Id$";
/* =============================================== local function prototypes */
/* ============================================================= module code */
/*------------------------------------------------------------------------------
* Initialize the object
*----------------------------------------------------------------------------*/
void
JackDspSource :: init ( const char* name ) throw ( Exception )
{
// Set defaults
ports[0] = NULL; // Left Port
ports[1] = NULL; // Right Port
rb[0] = NULL; // Left Ring Buffer
rb[1] = NULL; // Right Ring Buffer
client = NULL;
auto_connect = false; // Default is to not auto connect the JACK ports
tmp_buffer = NULL; // Buffer big enough for one 'read' of audio
// Auto connect the ports ?
if ( Util::strEq( name, "jack_auto", 9) ) {
auto_connect = true;
}
// Check the sample size
if (getBitsPerSample() != 16) {
throw Exception( __FILE__, __LINE__,
"JackDspSource doesn't support non 16-bit samples");
}
}
/*------------------------------------------------------------------------------
* De-initialize the object
*----------------------------------------------------------------------------*/
void
JackDspSource :: strip ( void ) throw ( Exception )
{
if ( isOpen() ) {
close();
}
// Free the temporary buffer
if (tmp_buffer) {
free(tmp_buffer);
tmp_buffer = NULL;
}
}
/*------------------------------------------------------------------------------
* Attempt to connect up the JACK ports automatically
* - Just connect left&right to the first two output ports we find
*----------------------------------------------------------------------------*/
void
JackDspSource :: do_auto_connect ( void ) throw ( Exception )
{
const char **all_ports;
unsigned int ch = 0;
int i;
Reporter::reportEvent( 10, "JackDspSource :: do_auto_connect");
// Get a list of all the jack ports
all_ports = jack_get_ports (client, NULL, NULL, JackPortIsOutput);
if (!ports) {
throw Exception( __FILE__, __LINE__, "jack_get_ports() returned NULL.");
}
// Step through each port name
for (i = 0; all_ports[i]; ++i) {
const char* in = all_ports[i];
const char* out = jack_port_name( ports[ch] );
Reporter::reportEvent( 2, "Connecting", in, "to", out);
if (jack_connect(client, in, out)) {
throw Exception( __FILE__, __LINE__,
"Failed to jack_connect() ports", in, out);
}
// Found enough ports ?
if (++ch >= getChannel()) break;
}
free( all_ports );
}
/*------------------------------------------------------------------------------
* Open the audio source
*----------------------------------------------------------------------------*/
bool
JackDspSource :: open ( void ) throw ( Exception )
{
char client_name[255];
size_t rb_size;
unsigned int c;
if ( isOpen() ) {
return false;
}
// Register client with Jack
snprintf(client_name, 255, "darkice-%d", getpid());
if ((client = jack_client_new(client_name)) == NULL) {
throw Exception( __FILE__, __LINE__, "JACK server not running?");
}
Reporter::reportEvent( 1, "Registering as JACK client", client_name);
// Check the sample rate is correct
if (jack_get_sample_rate( client ) != (jack_nframes_t)getSampleRate()) {
throw Exception( __FILE__, __LINE__,
"JACK server sample rate is different than "
"sample rate in darkice config file");
}
// Register ports with Jack
if (getChannel() == 1) {
if (!(ports[0] = jack_port_register(client,
"mono",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput,
0))) {
throw Exception( __FILE__, __LINE__,
"Cannot register input port", "mono");
}
} else if (getChannel() == 2) {
if (!(ports[0] = jack_port_register(client,
"left",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput,
0))) {
throw Exception( __FILE__, __LINE__,
"Cannot register input port", "left");
}
if (!(ports[1] = jack_port_register(client,
"right",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0))) {
throw Exception( __FILE__, __LINE__,
"Cannot register input port", "right");
}
} else {
throw Exception( __FILE__, __LINE__,
"Invalid number of channels", getChannel());
}
// Create a ring buffer for each channel
rb_size = 2
* jack_get_sample_rate(client)
* sizeof (jack_default_audio_sample_t);
for (c=0; c<getChannel(); c++) {
rb[c] = jack_ringbuffer_create(rb_size);
if (!rb[c]) {
throw Exception( __FILE__, __LINE__,
"Failed to create ringbuffer for", "channel", c);
}
}
// Set the callbacks
jack_on_shutdown(client, JackDspSource::shutdown_callback, (void*)this);
if (jack_set_process_callback(client,
JackDspSource::process_callback,
(void*)this)) {
throw Exception( __FILE__, __LINE__, "Failed to set process callback");
}
// Activate client
if (jack_activate(client)) {
throw Exception( __FILE__, __LINE__, "Can't activate client");
}
// Attempt to automatically connect up our input ports to something ?
if (auto_connect) {
do_auto_connect();
}
return true;
}
/*------------------------------------------------------------------------------
* Check wether read() would return anything
*----------------------------------------------------------------------------*/
bool
JackDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception )
{
size_t available=0;
if ( !isOpen() ) {
return false;
}
// How many bytes available in ring buffer ?
available = jack_ringbuffer_read_space( rb[0] );
if (available) return true;
// Sleep and check again
// FIXME: should we really sleep the full duration ?
usleep( (sec*1000000) + usec );
available = jack_ringbuffer_read_space( rb[0] );
if (available) {
return true;
} else {
return false;
}
}
/*------------------------------------------------------------------------------
* Read from the audio source
*----------------------------------------------------------------------------*/
unsigned int
JackDspSource :: read ( void * buf,
unsigned int len ) throw ( Exception )
{
jack_nframes_t samples = len / 2 / getChannel();
jack_nframes_t samples_read[2] = {0,0};
short * output = (short*)buf;
unsigned int c, n;
if ( !isOpen() ) {
return 0;
}
// Ensure the temporary buffer is big enough
tmp_buffer = (jack_default_audio_sample_t*)realloc(tmp_buffer,
samples * sizeof( jack_default_audio_sample_t ) );
if (!tmp_buffer) {
throw Exception( __FILE__, __LINE__, "realloc on tmp_buffer failed");
}
for (c=0; c<getChannel(); c++)
{
// Copy frames from ring buffer to temporary buffer
// and then convert samples to output buffer
int bytes_read = jack_ringbuffer_read(rb[c],
(char*)tmp_buffer,
samples * sizeof( jack_default_audio_sample_t ));
samples_read[c] = bytes_read / sizeof( jack_default_audio_sample_t );
// Convert samples from float to short and put in output buffer
for(n=0; n<samples_read[c]; n++) {
int tmp = lrintf(tmp_buffer[n] * 32768.0f);
if (tmp > SHRT_MAX) {
output[n*getChannel()+c] = SHRT_MAX;
} else if (tmp < SHRT_MIN) {
output[n*getChannel()+c] = SHRT_MIN;
} else {
output[n*getChannel()+c] = (short) tmp;
}
}
}
// Didn't get as many samples as we wanted ?
if (getChannel() == 2 && samples_read[0] != samples_read[1]) {
Reporter::reportEvent( 2,
"Warning: Read a different number of samples "
"for left and right channels");
}
// Return the number of bytes put in the output buffer
return samples_read[0] * 2 * getChannel();
}
/*------------------------------------------------------------------------------
* Close the audio source
*----------------------------------------------------------------------------*/
void
JackDspSource :: close ( void ) throw ( Exception )
{
unsigned int i;
if ( !isOpen() ) {
return;
}
for(i = 0; i < getChannel(); i++) {
// Close the port for channel
if ( ports[i] ) {
jack_port_unregister( client, ports[i] );
ports[i] = NULL;
}
// Free up the ring buffer for channel
if ( rb[i] ) {
jack_ringbuffer_free( rb[i] );
rb[i] = NULL;
}
}
/* Leave the jack graph */
if (client) {
jack_client_close(client);
client = NULL;
}
}
/*------------------------------------------------------------------------------
* Callback called by JACK when audio is available
*
* Don't do anything too expensive here
* - just shove audio samples in ring buffer
*----------------------------------------------------------------------------*/
int
JackDspSource :: process_callback( jack_nframes_t nframes, void *arg )
{
JackDspSource* self = (JackDspSource*)arg;
size_t to_write = sizeof (jack_default_audio_sample_t) * nframes;
unsigned int c;
// Wait until it is ready
if (self->client == NULL) {
return 0;
}
/* copy data to ringbuffer; one per channel */
for (c=0; c < self->getChannel(); c++) {
char *buf = (char*)jack_port_get_buffer(self->ports[c], nframes);
size_t len = jack_ringbuffer_write(self->rb[c], buf, to_write);
if (len < to_write) {
Reporter::reportEvent( 1, "failed to write to ring ruffer");
return 1;
}
}
// Success
return 0;
}
/*------------------------------------------------------------------------------
* Callback called when
*----------------------------------------------------------------------------*/
void
JackDspSource :: shutdown_callback( void *arg )
{
//JackDspSource* self = (JackDspSource*)arg;
Reporter::reportEvent( 1, "JackDspSource :: shutdown_callback");
}
#endif // SUPPORT_JACK_DSP
/*------------------------------------------------------------------------------
$Source$
$Log$
Revision 1.1 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
------------------------------------------------------------------------------*/

View File

@ -0,0 +1,289 @@
/*------------------------------------------------------------------------------
Copyright (c) 2005 Nicholas Humfrey. All rights reserved.
Tyrell DarkIce
File : JackDspSource.h
Version : $Revision$
Author : $Author$
Location : $Source$
Copyright notice:
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
------------------------------------------------------------------------------*/
#ifndef JACK_DSP_SOURCE_H
#define JACK_DSP_SOURCE_H
#ifndef __cplusplus
#error This is a C++ include file
#endif
/* ============================================================ include files */
#include "Reporter.h"
#include "AudioSource.h"
#if defined( HAVE_JACK_LIB )
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#else
#error configure for JACK
#endif
/* ================================================================ constants */
/* =================================================================== macros */
/* =============================================================== data types */
/**
* An audio input based on JACK
*
* @author $Author$
* @version $Revision$
*/
class JackDspSource : public AudioSource, public virtual Reporter
{
private:
/**
* The jack port
*/
jack_port_t * ports[2];
/**
* The jack ring buffer.
*/
jack_ringbuffer_t * rb[2];
/**
* The jack client.
*/
jack_client_t * client;
/**
* The jack audio sample buffer.
*/
jack_default_audio_sample_t * tmp_buffer;
/**
* Automatically connect the jack ports ? (default is to not)
*/
bool auto_connect;
protected:
/**
* Default constructor. Always throws an Exception.
*
* @exception Exception
*/
inline
JackDspSource ( void ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__);
}
/**
* Initialize the object
*
* @exception Exception
*/
void
init ( const char* name ) throw ( Exception );
/**
* De-initialize the object
*
* @exception Exception
*/
void
strip ( void ) throw ( Exception );
/**
* Attempt to connect up the JACK ports automatically
*/
void
do_auto_connect( ) throw ( Exception );
/**
* Callback called by JACK when audio is available
*/
static int
process_callback( jack_nframes_t nframes, void *arg );
/**
* Callback called by JACK when jackd is shutting down
*/
static void
shutdown_callback( void *arg );
public:
/**
* Constructor.
*
* @param name the name of the jack device
* @param sampleRate samples per second (e.g. 44100 for 44.1kHz).
* @param bitsPerSample bits per sample (e.g. 16 bits).
* @param channels number of channels of the audio source
* (e.g. 1 for mono, 2 for stereo, etc.).
* @exception Exception
*/
inline
JackDspSource ( const char * name,
int sampleRate = 44100,
int bitsPerSample = 16,
int channels = 2 )
throw ( Exception )
: AudioSource( sampleRate, bitsPerSample, channels )
{
init( name );
}
/**
* Copy Constructor.
*
* @param source the object to copy.
* @exception Exception
*/
inline
JackDspSource ( const JackDspSource & ds ) throw ( Exception )
: AudioSource( ds )
{
throw Exception( __FILE__, __LINE__, "JackDspSource doesn't copy");
}
/**
* Destructor.
*
* @exception Exception
*/
inline virtual
~JackDspSource ( void ) throw ( Exception )
{
strip();
}
/**
* Assignment operator.
*
* @param ds the object to assign to this one.
* @return a reference to this object.
* @exception Exception
*/
inline virtual JackDspSource &
operator= ( const JackDspSource & ds ) throw ( Exception )
{
throw Exception( __FILE__, __LINE__, "JackDspSource doesn't assign");
}
/**
* Open the JackDspSource.
* This does not put the Jack DSP device into recording mode.
* To start getting samples, call either canRead() or read().
*
* @return true if opening was successful, false otherwise
* @exception Exception
*
* @see #canRead
* @see #read
*/
virtual bool
open ( void ) throw ( Exception );
/**
* Check if the JackDspSource is registered
*
* @return true if Jack client is setup
*/
inline virtual bool
isOpen ( void ) const throw ()
{
return client != NULL;
}
/**
* Check if the JackDspSource can be read from.
* Blocks until the specified time for data to be available.
* Puts the Jack DSP device into recording mode.
*
* @param sec the maximum seconds to block.
* @param usec micro seconds to block after the full seconds.
* @return true if the JackDspSource is ready to be read from,
* false otherwise.
* @exception Exception
*/
virtual bool
canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception );
/**
* Read from the JackDspSource.
* Puts the Jack DSP device into recording mode.
*
* @param buf the buffer to read into.
* @param len the number of bytes to read into buf
* @return the number of bytes read (may be less than len).
* @exception Exception
*/
virtual unsigned int
read ( void * buf,
unsigned int len ) throw ( Exception );
/**
* Close the JackDspSource.
*
* @exception Exception
*/
virtual void
close ( void ) throw ( Exception );
};
/* ================================================= external data structures */
/* ====================================================== function prototypes */
#endif /* JACK_DSP_SOURCE_H */
/*------------------------------------------------------------------------------
$Source$
$Log$
Revision 1.1 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
------------------------------------------------------------------------------*/

View File

@ -1,7 +1,7 @@
bin_PROGRAMS = darkice
CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@ @JACK_CFLAGS@
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @ALSA_INCFLAGS@
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @ALSA_LDFLAGS@
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @ALSA_LDFLAGS@ @JACK_LIBS@
darkice_SOURCES = AudioEncoder.h\
AudioSource.h\
@ -52,11 +52,13 @@ darkice_SOURCES = AudioEncoder.h\
Util.h\
ConfigSection.h\
ConfigSection.cpp\
Config.h\
Config.cpp\
DarkIceConfig.h\
DarkIceConfig.cpp\
Reporter.h\
Reporter.cpp\
AlsaDspSource.h\
AlsaDspSource.cpp\
JackDspSource.h\
JackDspSource.cpp\
main.cpp

View File

@ -43,7 +43,7 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
#error need unistdt.h
#error need unistd.h
#endif
#ifdef HAVE_TIME_H
@ -309,6 +309,10 @@ class Reporter
$Source$
$Log$
Revision 1.9 2005/04/04 08:36:17 darkeye
commited changes to enable Jack support
thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
Revision 1.8 2005/04/03 05:14:07 jbebel
Changed timestamp on reported events to include date in addition to time.

View File

@ -123,8 +123,8 @@ aflibConverter::aflibConverter(
largeFilter = high_quality;
linearInterp = linear_interpolation;
_I = NULL;
_J = NULL;
_II = NULL;
_JJ = NULL;
_vol = 1.0;
}
@ -140,19 +140,19 @@ aflibConverter::deleteMemory()
int i;
// Delete memory for the input and output arrays
if (_I != NULL)
if (_II != NULL)
{
for (i = 0; i < _nChans; i++)
{
delete [] _I[i];
_I[i] = NULL;
delete [] _J[i];
_J[i] = NULL;
delete [] _II[i];
_II[i] = NULL;
delete [] _JJ[i];
_JJ[i] = NULL;
}
delete [] _I;
_I = NULL;
delete [] _J;
_J = NULL;
delete [] _II;
_II = NULL;
delete [] _JJ;
_JJ = NULL;
}
}
@ -180,15 +180,15 @@ aflibConverter::initialize(
_vol = volume;
// Allocate all new memory
_I = new short * [_nChans];
_J = new short * [_nChans];
_II = new short * [_nChans];
_JJ = new short * [_nChans];
for (i = 0; i < _nChans; i++)
{
// Add extra to allow of offset of input data (Xoff in main routine)
_I[i] = new short[IBUFFSIZE + 256];
_J[i] = new short[(int)(((double)IBUFFSIZE)*_factor)];
memset(_I[i], 0, sizeof(short) * (IBUFFSIZE + 256));
_II[i] = new short[IBUFFSIZE + 256];
_JJ[i] = new short[(int)(((double)IBUFFSIZE)*_factor)];
memset(_II[i], 0, sizeof(short) * (IBUFFSIZE + 256));
}
}
@ -467,7 +467,7 @@ aflibConverter::resampleFast( /* number of output samples returned */
do {
if (!last) /* If haven't read last sample yet */
{
last = readData(inCount, inArray, _I,
last = readData(inCount, inArray, _II,
IBUFFSIZE, (int)Xread,first_pass);
first_pass = FALSE;
if (last && (last-Xoff<Nx)) { /* If last sample has been read... */
@ -487,7 +487,7 @@ aflibConverter::resampleFast( /* number of output samples returned */
orig_Nx = Nx;
Time2 = _Time;
/* Resample stuff in input buffer */
Nout=SrcLinear(_I[c],_J[c],_factor,&Time2,orig_Nx,maxOutput);
Nout=SrcLinear(_II[c],_JJ[c],_factor,&Time2,orig_Nx,maxOutput);
}
Nx = orig_Nx;
_Time = Time2;
@ -504,7 +504,7 @@ aflibConverter::resampleFast( /* number of output samples returned */
for (c = 0; c < _nChans; c++)
{
for (i=0; i<IBUFFSIZE-Xp+Xoff; i++) { /* Copy part of input signal */
_I[c][i] = _I[c][i+Xp-Xoff]; /* that must be re-used */
_II[c][i] = _II[c][i+Xp-Xoff]; /* that must be re-used */
}
}
if (last) { /* If near end of sample... */
@ -526,7 +526,7 @@ aflibConverter::resampleFast( /* number of output samples returned */
for (c = 0; c < _nChans; c++)
for (i = 0; i < Nout; i++)
outArray[c * outCount + i + Ycount - Nout] = _J[c][i];
outArray[c * outCount + i + Ycount - Nout] = _JJ[c][i];
total_inCount += Nx;
@ -583,7 +583,7 @@ aflibConverter::resampleWithFilter( /* number of output samples returned */
do {
if (!last) /* If haven't read last sample yet */
{
last = readData(inCount, inArray, _I,
last = readData(inCount, inArray, _II,
IBUFFSIZE, (int)Xread,first_pass);
first_pass = FALSE;
if (last && (last-Xoff<Nx)) { /* If last sample has been read... */
@ -604,11 +604,11 @@ aflibConverter::resampleWithFilter( /* number of output samples returned */
Time2 = _Time;
/* Resample stuff in input buffer */
if (_factor >= 1) { /* SrcUp() is faster if we can use it */
Nout=SrcUp(_I[c],_J[c],_factor,
Nout=SrcUp(_II[c],_JJ[c],_factor,
&Time2,Nx,maxOutput,Nwing,LpScl,Imp,ImpD,interpFilt);
}
else {
Nout=SrcUD(_I[c],_J[c],_factor,
Nout=SrcUD(_II[c],_JJ[c],_factor,
&Time2,Nx,maxOutput,Nwing,LpScl,Imp,ImpD,interpFilt);
}
}
@ -642,7 +642,7 @@ aflibConverter::resampleWithFilter( /* number of output samples returned */
{
for (i = 0; i < Nout; i++)
{
outArray[c * outCount + i + Ycount - Nout] = _J[c][i];
outArray[c * outCount + i + Ycount - Nout] = _JJ[c][i];
}
}
@ -651,7 +651,7 @@ aflibConverter::resampleWithFilter( /* number of output samples returned */
for (c = 0; c < _nChans; c++)
{
for (i=0; i<IBUFFSIZE-act_incount+Xoff; i++) { /* Copy part of input signal */
_I[c][i] = _I[c][i+act_incount]; /* that must be re-used */
_II[c][i] = _II[c][i+act_incount]; /* that must be re-used */
}
}
Xread = IBUFFSIZE - Nx; /* Pos in input buff to read new data into */

View File

@ -27,7 +27,7 @@
#define _AFLIBCONVERTER_H_
#ifdef HAVE_CONFIG_H
#include <config.h>
#include "config.h"
#endif
#ifndef MAX
@ -222,8 +222,8 @@ static short LARGE_FILTER_IMP[];
bool interpFilt;
bool largeFilter;
bool linearInterp;
short ** _I;
short ** _J;
short ** _II;
short ** _JJ;
unsigned int _Time;
double _factor;
int _nChans;