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> Robert Lunnon <bobl@optushome.com.au>
Enrico Ardizzoni <craken@users.sourceforge.net> Enrico Ardizzoni <craken@users.sourceforge.net>
Deti Fliegl <deti@fliegl.de> 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 since it is not implemented in OpenBSD / NetBSD
o added possibility to downsample from stereo to mono when encoding o added possibility to downsample from stereo to mono when encoding
to Ogg Vorbis, thanks to Deti Fliegl, <deti@fliegl.de> 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 15-02-2004: DarkIce 0.14 released

View File

@ -1,9 +1,11 @@
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_INIT(src/DarkIce.cpp) AC_INIT(darkice, 0.15beta)
AM_INIT_AUTOMAKE(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_CXX
AC_PROG_INSTALL AC_PROG_INSTALL
@ -155,6 +157,24 @@ else
fi 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-----------------------------------------------------------------------------
dnl check for MSG_NOSIGNAL for the send() function in libsocket dnl check for MSG_NOSIGNAL for the send() function in libsocket
dnl----------------------------------------------------------------------------- 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-----------------------------------------------------------------------------
dnl enable compilation with debug flags dnl enable compilation with debug flags
dnl----------------------------------------------------------------------------- dnl-----------------------------------------------------------------------------

View File

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

View File

@ -60,8 +60,12 @@ Required values:
.TP .TP
.I device .I device
OSS DSP audio device to record from (e.g. /dev/dsp) or ALSA DSP device name Specify the device to record from, which can be an OSS DSP device,
(e.g. hwplug:0,0) 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 .TP
.I sampleRate .I sampleRate
The sample rate to record with, samples per second The sample rate to record with, samples per second

View File

@ -260,7 +260,7 @@ AlsaDspSource :: read ( void * buf,
} while (ret == -EAGAIN); } while (ret == -EAGAIN);
if ( ret < 0 ) { if ( ret < 0 ) {
throw new Exception(__FILE__, __LINE__, snd_strerror(ret)); throw Exception(__FILE__, __LINE__, snd_strerror(ret));
} }
running = true; running = true;
@ -292,6 +292,10 @@ AlsaDspSource :: close ( void ) throw ( Exception )
$Source$ $Source$
$Log$ $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 Revision 1.3 2005/04/03 05:00:14 jbebel
Fixing code documentation of buffer overruns Fixing code documentation of buffer overruns

View File

@ -65,6 +65,7 @@ AudioSource :: createDspSource( const char * deviceName,
int channel) int channel)
throw ( Exception ) throw ( Exception )
{ {
if ( Util::strEq( deviceName, "/dev", 4) ) { if ( Util::strEq( deviceName, "/dev", 4) ) {
#if defined( SUPPORT_OSS_DSP ) #if defined( SUPPORT_OSS_DSP )
Reporter::reportEvent( 1, "Using OSS DSP input device:", deviceName); Reporter::reportEvent( 1, "Using OSS DSP input device:", deviceName);
@ -79,9 +80,21 @@ AudioSource :: createDspSource( const char * deviceName,
bitsPerSample, bitsPerSample,
channel); channel);
#else #else
throw new Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"trying to open OSS or Solaris DSP device " "trying to open OSS or Solaris DSP device "
"without support compiled", deviceName); "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 #endif
} else { } else {
#if defined( SUPPORT_ALSA_DSP ) #if defined( SUPPORT_ALSA_DSP )
@ -91,7 +104,7 @@ AudioSource :: createDspSource( const char * deviceName,
bitsPerSample, bitsPerSample,
channel); channel);
#else #else
throw new Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"trying to open ALSA DSP device without " "trying to open ALSA DSP device without "
"support compiled", deviceName); "support compiled", deviceName);
#endif #endif
@ -104,6 +117,10 @@ AudioSource :: createDspSource( const char * deviceName,
$Source$ $Source$
$Log$ $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 Revision 1.2 2004/02/15 22:26:16 darkeye
fixed typo, minimal cosmetic change fixed typo, minimal cosmetic change

View File

@ -33,6 +33,9 @@
#error This is a C++ include file #error This is a C++ include file
#endif #endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/* ============================================================ include files */ /* ============================================================ include files */
@ -50,21 +53,27 @@
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
#if defined( HAVE_ALSA_LIB ) #if defined( HAVE_ALSA_LIB )
// we have an ALSA sound system available // we have an ALSA sound system available
#define SUPPORT_ALSA_DSP #define SUPPORT_ALSA_DSP 1
#endif #endif
#if defined( HAVE_SYS_SOUNDCARD_H ) #if defined( HAVE_SYS_SOUNDCARD_H )
// we have an OSS DSP sound source device available // we have an OSS DSP sound source device available
#define SUPPORT_OSS_DSP #define SUPPORT_OSS_DSP 1
#endif #endif
#if defined( HAVE_SYS_AUDIO_H ) || defined( HAVE_SYS_AUDIOIO_H ) #if defined( HAVE_SYS_AUDIO_H ) || defined( HAVE_SYS_AUDIOIO_H )
// we have a Solaris DSP sound device available (same for OpenBSD) // 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 #endif
#if !defined( SUPPORT_ALSA_DSP ) \ #if !defined( SUPPORT_ALSA_DSP ) \
&& !defined( SUPPORT_OSS_DSP ) \ && !defined( SUPPORT_OSS_DSP ) \
&& !defined( SUPPORT_JACK_DSP ) \
&& !defined( SUPPORT_SOLARIS_DSP ) && !defined( SUPPORT_SOLARIS_DSP )
// there was no DSP audio system found // there was no DSP audio system found
#error No DSP audio input device found on system #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 * @return true if the data is big endian, false if little endian
*/ */
virtual bool 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. * Get the sample rate per seconds for this AudioSource.
@ -275,6 +291,9 @@ class AudioSource : public Source, public virtual Reporter
#include "SolarisDspSource.h" #include "SolarisDspSource.h"
#endif #endif
#if defined( SUPPORT_JACK_DSP )
#include "JackDspSource.h"
#endif
/* ====================================================== function prototypes */ /* ====================================================== function prototypes */
@ -288,6 +307,10 @@ class AudioSource : public Source, public virtual Reporter
$Source$ $Source$
$Log$ $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 Revision 1.7 2004/02/18 21:08:11 darkeye
ported to OpenBSD (real-time scheduling not yet supported) ported to OpenBSD (real-time scheduling not yet supported)

View File

@ -873,9 +873,8 @@ DarkIce :: configFileCast ( const Config & config )
void void
DarkIce :: setRealTimeScheduling ( void ) throw ( Exception ) DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
{ {
// don't include the following on OpenBSD / NetBSD, as the scheduling // Only if the OS has the POSIX real-time scheduling functions implemented.
// functions are not implemented. #if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
#if !defined( __OpenBSD__ ) && !defined( __NetBSD__ )
uid_t euid; uid_t euid;
euid = geteuid(); euid = geteuid();
@ -921,9 +920,9 @@ DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
"It is recommended that you run this program as super-user"); "It is recommended that you run this program as super-user");
} }
#else #else
reportEvent( 1, "POSIX scheduling not supported on OpenBSD / NetBSD, " reportEvent( 1, "POSIX scheduling not supported on this system, "
"this may cause recording skips"); "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 void
DarkIce :: setOriginalScheduling ( void ) throw ( Exception ) DarkIce :: setOriginalScheduling ( void ) throw ( Exception )
{ {
// don't include the following on OpenBSD / NetBSD, as the scheduling // Only if the OS has the POSIX real-time scheduling functions implemented.
// functions are not implemented. #if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
#if !defined( __OpenBSD__ ) && !defined( __NetBSD__ )
uid_t euid; uid_t euid;
euid = geteuid(); euid = geteuid();
@ -957,7 +955,7 @@ DarkIce :: setOriginalScheduling ( void ) throw ( Exception )
reportEvent( 5, "reverted to original scheduling"); 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$ $Source$
$Log$ $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 Revision 1.41 2005/04/03 05:12:20 jbebel
Changed mechanism for testing the presence of the quality value such that Changed mechanism for testing the presence of the quality value such that
zero is a valid option. zero is a valid option.

View File

@ -58,7 +58,7 @@
#include "AudioEncoder.h" #include "AudioEncoder.h"
#include "TcpSocket.h" #include "TcpSocket.h"
#include "CastSink.h" #include "CastSink.h"
#include "Config.h" #include "DarkIceConfig.h"
/* ================================================================ constants */ /* ================================================================ constants */
@ -309,6 +309,10 @@ class DarkIce : public virtual Referable, public virtual Reporter
$Source$ $Source$
$Log$ $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 Revision 1.14 2002/05/28 12:35:41 darkeye
code cleanup: compiles under gcc-c++ 3.1, using -pedantic option code cleanup: compiles under gcc-c++ 3.1, using -pedantic option

View File

@ -4,7 +4,7 @@
Tyrell Config Tyrell Config
File : Config.cpp File : DarkIceConfig.cpp
Version : $Revision$ Version : $Revision$
Author : $Author$ Author : $Author$
Location : $Source$ Location : $Source$
@ -38,7 +38,7 @@
#include <iostream> #include <iostream>
#include "Config.h" #include "DarkIceConfig.h"
/* =================================================== local data structures */ /* =================================================== local data structures */
@ -170,6 +170,10 @@ Config :: read ( std::istream & is ) throw ( Exception )
$Source$ $Source$
$Log$ $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 Revision 1.7 2002/05/28 12:35:41 darkeye
code cleanup: compiles under gcc-c++ 3.1, using -pedantic option code cleanup: compiles under gcc-c++ 3.1, using -pedantic option

View File

@ -4,7 +4,7 @@
Tyrell Config Tyrell Config
File : Config.h File : DarkIceConfig.h
Version : $Revision$ Version : $Revision$
Author : $Author$ Author : $Author$
Location : $Source$ Location : $Source$
@ -213,6 +213,10 @@ class Config : public virtual Referable
$Source$ $Source$
$Log$ $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 Revision 1.5 2002/05/28 12:35:41 darkeye
code cleanup: compiles under gcc-c++ 3.1, using -pedantic option 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 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@ 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\ darkice_SOURCES = AudioEncoder.h\
AudioSource.h\ AudioSource.h\
@ -52,11 +52,13 @@ darkice_SOURCES = AudioEncoder.h\
Util.h\ Util.h\
ConfigSection.h\ ConfigSection.h\
ConfigSection.cpp\ ConfigSection.cpp\
Config.h\ DarkIceConfig.h\
Config.cpp\ DarkIceConfig.cpp\
Reporter.h\ Reporter.h\
Reporter.cpp\ Reporter.cpp\
AlsaDspSource.h\ AlsaDspSource.h\
AlsaDspSource.cpp\ AlsaDspSource.cpp\
JackDspSource.h\
JackDspSource.cpp\
main.cpp main.cpp

View File

@ -43,7 +43,7 @@
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#else #else
#error need unistdt.h #error need unistd.h
#endif #endif
#ifdef HAVE_TIME_H #ifdef HAVE_TIME_H
@ -309,6 +309,10 @@ class Reporter
$Source$ $Source$
$Log$ $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 Revision 1.8 2005/04/03 05:14:07 jbebel
Changed timestamp on reported events to include date in addition to time. Changed timestamp on reported events to include date in addition to time.

View File

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

View File

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