synced with trunk

This commit is contained in:
rafael@riseup.net 2010-05-10 00:07:25 +00:00
parent 27cf3ff79d
commit f27514b4f5
17 changed files with 520 additions and 74 deletions

View File

@ -39,4 +39,6 @@ with contributions by:
Daniel Hazelbaker <daniel@highdesertchurch.com> Daniel Hazelbaker <daniel@highdesertchurch.com>
Alessandro Beretta <alessandro.baretta@radiomaria.org> Alessandro Beretta <alessandro.baretta@radiomaria.org>
Roland Hermans <roland.hermans@omroepvenray.nl> Roland Hermans <roland.hermans@omroepvenray.nl>
Sergiy <piratfm@gmail.com>
Clemens Ladisch <clemens@ladisch.de>
Edwin van den Oetelaar <oetelaar.automatisering@gmail.com>

View File

@ -1,3 +1,19 @@
Next release
o fixed a bug in BufferedSink.cpp that leads to some buffers
being written twice, causing corruption of datastream,
thanks to Edwin van den Oetelaar <oetelaar.automatisering@gmail.com>
o implemented samplerate conversion for all codecs using libsamplerate,
and keeping internal aflibConverter as fallback,
thanks to Sergiy <piratfm@gmail.com>
o bugfix: fix for alsa driver - closes ticked #8
thanks to Clemens Ladisch <clemens@ladisch.de>
o Implemented CoreAudio driver for MacOS X
14-11-2009 Darkice 0.20.1 released
o added rc.darkice init script
thanks to Niels Dettenbach <nd@syndicat.com>
o bugfix: fix for gcc 4.4
05-11-2009 Darkice 0.20 released 05-11-2009 Darkice 0.20 released
o new maintainer: Rafael Diniz <rafael@riseup.net> o new maintainer: Rafael Diniz <rafael@riseup.net>

View File

@ -6,7 +6,7 @@ SUBDIRS = src man
sysconf_DATA = darkice.cfg sysconf_DATA = darkice.cfg
EXTRA_DIST = $(DOC_DIR) darkice.cfg INSTALL.lame INSTALL.vorbis FAQ EXTRA_DIST = $(DOC_DIR) darkice.cfg INSTALL.lame INSTALL.vorbis FAQ rc.darkice
.PHONY: doc .PHONY: doc

View File

@ -270,6 +270,7 @@ dnl link JACK sound server if requested
dnl----------------------------------------------------------------------------- dnl-----------------------------------------------------------------------------
AC_SUBST(JACK_CFLAGS) AC_SUBST(JACK_CFLAGS)
AC_SUBST(JACK_LDFLAGS) AC_SUBST(JACK_LDFLAGS)
AC_SUBST(JACK_INCFLAGS)
AC_ARG_WITH(jack, AC_ARG_WITH(jack,
[ --with-jack use JACK sound system [yes] ], [ --with-jack use JACK sound system [yes] ],
@ -315,6 +316,43 @@ AC_ARG_WITH(core, [ --with-core = choose CoreAudio API support (mac only)], [
dnl-----------------------------------------------------------------------------
dnl link Secret Rabbit Code (aka libsamplerate) if requested
dnl-----------------------------------------------------------------------------
AC_SUBST(SRC_CFLAGS)
AC_SUBST(SRC_LDFLAGS)
AC_SUBST(SRC_INCFLAGS)
AC_ARG_WITH(samplerate,
[ --with-samplerate use Secret Rabbit Code (aka libsamplerate) for samplerate conversion [yes] ],
USE_SRC=${withval}, USE_SRC="yes" )
AC_ARG_WITH(samplerate-prefix,
[ --with-samplerate-prefix=DIR alternate location for samplerate [/usr]
look for libraries in SRC-PREFIX/lib,
for headers in SRC-PREFIX/include],
CONFIG_SRC_PREFIX="${withval}", CONFIG_SRC_PREFIX="/usr")
if test "x${USE_SRC}" = "xyes" ; then
AC_MSG_CHECKING( [for samplerate libraries at ${CONFIG_SRC_PREFIX}] )
LA_SEARCH_LIB( SRC_LIB_LOC, SRC_INC_LOC, libsamplerate.la libsamplerate.so libsamplerate.dylib, samplerate.h,
${CONFIG_SRC_PREFIX})
if test "x${SRC_LIB_LOC}" != "x" ; then
AC_DEFINE( HAVE_SRC_LIB, 1, [build with samplerate conversion through libsamplerate] )
if test "x${SRC_INC_LOC}" != "x${SYSTEM_INCLUDE}" ; then
SRC_INCFLAGS="-I${SRC_INC_LOC}"
fi
SRC_LDFLAGS="-L${SRC_LIB_LOC} -lsamplerate"
AC_MSG_RESULT( [found at ${CONFIG_SRC_PREFIX}] )
else
AC_MSG_WARN( [not found, building libsamplerate support])
fi
else
AC_MSG_RESULT( [building without libsamplerate support] )
fi
AM_CONDITIONAL(HAVE_SRC_LIB, test "x${SRC_LIB_LOC}" != "x")
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-----------------------------------------------------------------------------

View File

@ -114,7 +114,7 @@ Developed with contributions by
.SH LINKS .SH LINKS
Project homepage: Project homepage:
.I http://darkice.tyrell.hu/ .I http://code.google.com/p/darkice/
.B IceCast .B IceCast
homepage: homepage:

View File

@ -655,7 +655,7 @@ Akos Maroy
.SH LINKS .SH LINKS
Project homepage: Project homepage:
.I http://darkice.tyrell.hu/ .I http://code.google.com/p/darkice/
.B IceCast .B IceCast
homepage: homepage:

View File

@ -173,8 +173,8 @@ AlsaDspSource :: open ( void ) throw ( Exception )
throw Exception( __FILE__, __LINE__, "can't set channels", u); throw Exception( __FILE__, __LINE__, "can't set channels", u);
} }
u = getBufferTime() / 4; u = 4;
if (snd_pcm_hw_params_set_period_time_near(captureHandle, hwParams, &u, 0) if (snd_pcm_hw_params_set_periods_near(captureHandle, hwParams, &u, 0)
< 0) { < 0) {
snd_pcm_hw_params_free(hwParams); snd_pcm_hw_params_free(hwParams);
close(); close();

View File

@ -330,9 +330,14 @@ BufferedSink :: write ( const void * buf,
// the internal buffer is empty, try to write the fresh data // the internal buffer is empty, try to write the fresh data
soFar = 0; soFar = 0;
if ( inp != outp ) { if ( inp == outp ) {
while ( soFar < len && sink->canWrite( 0, 0) ) { while ( soFar < len && sink->canWrite( 0, 0) ) {
try {
soFar += sink->write( b + soFar, len - soFar); soFar += sink->write( b + soFar, len - soFar);
} catch (Exception &e) {
reportEvent(3,"Exception caught in BufferedSink :: write3\n");
throw; /* up a level */
}
} }
} }
length = soFar; length = soFar;

View File

@ -81,7 +81,7 @@ FaacEncoder :: open ( void )
faacEncGetVersion(&faacVersion, &faacCopyright); faacEncGetVersion(&faacVersion, &faacCopyright);
reportEvent(1, "Using faac codec version", faacVersion); reportEvent(1, "Using faac codec version", faacVersion);
encoderHandle = faacEncOpen(getInSampleRate(), encoderHandle = faacEncOpen(getOutSampleRate(),
getInChannel(), getInChannel(),
&inputSamples, &inputSamples,
&maxOutputBytes); &maxOutputBytes);
@ -107,6 +107,31 @@ FaacEncoder :: open ( void )
"error configuring faac library"); "error configuring faac library");
} }
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
if ((int) inputSamples > getInChannel() * converterData.output_frames) {
resampledOffset = new float[2 * inputSamples];
} else {
resampledOffset = new float[2 * getInChannel() * converterData.input_frames];
}
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
//needed 2x(converted input samples) to handle offsets
int outCount = 2 * getInChannel() * (inputSamples + 1);
if (resampleRatio > 1)
outCount = (int) (outCount * resampleRatio);
resampledOffset = new short int[outCount];
#endif
resampledOffsetSize = 0;
}
faacOpen = true; faacOpen = true;
return true; return true;
@ -134,6 +159,68 @@ FaacEncoder :: write ( const void * buf,
int samples = (int) nSamples * channels; int samples = (int) nSamples * channels;
int processedSamples = 0; int processedSamples = 0;
if ( converter ) {
unsigned int converted;
#ifdef HAVE_SRC_LIB
src_short_to_float_array ((short *) b, converterData.data_in, samples);
converterData.input_frames = nSamples;
converterData.data_out = resampledOffset + (resampledOffsetSize * channels);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
#else
int inCount = nSamples;
short int * shortBuffer = new short int[samples];
int outCount = (int) (inCount * resampleRatio);
Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
converted = converter->resample( inCount,
outCount+1,
shortBuffer,
&resampledOffset[resampledOffsetSize*channels]);
delete[] shortBuffer;
#endif
resampledOffsetSize += converted;
// encode samples (if enough)
while(resampledOffsetSize - processedSamples >= inputSamples/channels) {
int outputBytes;
#ifdef HAVE_SRC_LIB
short *shortData = new short[inputSamples];
src_float_to_short_array(resampledOffset + (processedSamples * channels),
shortData, inputSamples) ;
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) shortData,
inputSamples,
faacBuf,
maxOutputBytes);
delete [] shortData;
#else
outputBytes = faacEncEncode(encoderHandle,
(int32_t*) &resampledOffset[processedSamples*channels],
inputSamples,
faacBuf,
maxOutputBytes);
#endif
getSink()->write(faacBuf, outputBytes);
processedSamples+=inputSamples/channels;
}
if (processedSamples && (int) resampledOffsetSize >= processedSamples) {
resampledOffsetSize -= processedSamples;
//move least part of resampled data to beginning
if(resampledOffsetSize)
#ifdef HAVE_SRC_LIB
resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*channels*sizeof(float));
#else
resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*sampleSize);
#endif
}
} else {
while (processedSamples < samples) { while (processedSamples < samples) {
int outputBytes; int outputBytes;
int inSamples = samples - processedSamples < (int) inputSamples int inSamples = samples - processedSamples < (int) inputSamples
@ -149,10 +236,12 @@ FaacEncoder :: write ( const void * buf,
processedSamples += inSamples; processedSamples += inSamples;
} }
}
delete[] faacBuf; delete[] faacBuf;
return processedSamples; // return processedSamples;
return samples;
} }

View File

@ -52,6 +52,11 @@
#include "Reporter.h" #include "Reporter.h"
#include "AudioEncoder.h" #include "AudioEncoder.h"
#include "Sink.h" #include "Sink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h"
#endif
/* ================================================================ constants */ /* ================================================================ constants */
@ -98,6 +103,24 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
*/ */
int lowpass; int lowpass;
/**
* Resample ratio
*/
double resampleRatio;
/**
* sample rate converter object for possible resampling
*/
#ifdef HAVE_SRC_LIB
SRC_STATE *converter;
SRC_DATA converterData;
float *resampledOffset;
#else
aflibConverter *converter;
short *resampledOffset;
#endif
unsigned int resampledOffsetSize;
/** /**
* Initialize the object. * Initialize the object.
* *
@ -133,6 +156,58 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
throw Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"input channels and output channels do not match"); "input channels and output channels do not match");
} }
if ( getOutSampleRate() == getInSampleRate() ) {
resampleRatio = 1;
converter = 0;
} else if (getInBitsPerSample() == 16) {
resampleRatio = ( (double) getOutSampleRate() /
(double) getInSampleRate() );
// Determine if we can use linear interpolation.
// The inverse of the ratio must be a power of two for linear mode to
// be of sufficient quality.
bool useLinear = true;
double inverse = 1 / resampleRatio;
int integer = (int) inverse;
// Check that the inverse of the ratio is an integer
if( integer == inverse ) {
while( useLinear && integer ) { // Loop through the bits
// If the lowest order bit is not the only one set
if( integer & 1 && integer != 1 ) {
// Not a power of two; cannot use linear
useLinear = false;
} else {
// Shift all the bits over and try again
integer >>= 1;
}
}
} else {
useLinear = false;
}
// If we get here and useLinear is still true, then we have
// a power of two.
// open the aflibConverter in
// - high quality
// - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false);
#endif
} else {
throw Exception( __FILE__, __LINE__,
"specified bits per sample with samplerate conversion not supported",
getInBitsPerSample() );
}
} }
/** /**
@ -143,6 +218,15 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
inline void inline void
strip ( void ) throw ( Exception ) strip ( void ) throw ( Exception )
{ {
if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
src_delete (converter);
#else
delete converter;
#endif
delete [] resampledOffset;
}
} }

View File

@ -190,7 +190,7 @@ IceCast2 :: sendLogin ( void ) throw ( Exception )
} }
// send user agent info // send user agent info
str = "\nUser-Agent: DarkIce/" VERSION " (http://darkice.tyrell.hu/)"; str = "\nUser-Agent: DarkIce/" VERSION " (http://code.google.com/p/darkice/)";
sink->write( str, strlen( str)); sink->write( str, strlen( str));
// send the ice- headers // send the ice- headers

View File

@ -1,9 +1,21 @@
bin_PROGRAMS = darkice bin_PROGRAMS = darkice
AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@ AM_CXXFLAGS = -O2 -pedantic -Wall @DEBUG_CXXFLAGS@ @PTHREAD_CFLAGS@
@JACK_CFLAGS@ @JACK_CFLAGS@
INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ @ALSA_INCFLAGS@ INCLUDES = @LAME_INCFLAGS@ @VORBIS_INCFLAGS@ @FAAC_INCFLAGS@ @AACPLUS_INCFLAGS@ @TWOLAME_INCFLAGS@ \
@ALSA_INCFLAGS@ @JACK_INCFLAGS@ @SRC_INCFLAGS@
LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \ LDADD = @PTHREAD_LIBS@ @LAME_LDFLAGS@ @VORBIS_LDFLAGS@ @FAAC_LDFLAGS@ @AACPLUS_LDFLAGS@ @TWOLAME_LDFLAGS@ \
@ALSA_LDFLAGS@ @JACK_LDFLAGS@ @COREAUDIO_LDFLAGS@ @ALSA_LDFLAGS@ @JACK_LDFLAGS@ @SRC_LDFLAGS@ @COREAUDIO_LDFLAGS@
if HAVE_SRC_LIB
AFLIB_SOURCE =
else
AFLIB_SOURCE = aflibDebug.h\
aflibDebug.cc\
aflibConverter.h\
aflibConverter.cc\
aflibConverterLargeFilter.h\
aflibConverterSmallFilter.h
endif
darkice_SOURCES = AudioEncoder.h\ darkice_SOURCES = AudioEncoder.h\
AudioSource.h\ AudioSource.h\
@ -40,12 +52,6 @@ darkice_SOURCES = AudioEncoder.h\
FaacEncoder.h\ FaacEncoder.h\
aacPlusEncoder.cpp\ aacPlusEncoder.cpp\
aacPlusEncoder.h\ aacPlusEncoder.h\
aflibDebug.h\
aflibDebug.cc\
aflibConverter.h\
aflibConverter.cc\
aflibConverterLargeFilter.h\
aflibConverterSmallFilter.h\
OssDspSource.cpp\ OssDspSource.cpp\
OssDspSource.h\ OssDspSource.h\
SerialUlaw.cpp\ SerialUlaw.cpp\
@ -72,5 +78,12 @@ darkice_SOURCES = AudioEncoder.h\
JackDspSource.cpp\ JackDspSource.cpp\
CoreAudioDspSource.h\ CoreAudioDspSource.h\
CoreAudioDspSource.cpp\ CoreAudioDspSource.cpp\
main.cpp main.cpp\
$(AFLIB_SOURCE)
EXTRA_darkice_SOURCES = aflibDebug.h\
aflibDebug.cc\
aflibConverter.h\
aflibConverter.cc\
aflibConverterLargeFilter.h\
aflibConverterSmallFilter.h

View File

@ -117,7 +117,15 @@ VorbisLibEncoder :: init ( unsigned int outMaxBitrate )
// - high quality // - high quality
// - linear or quadratic (non-linear) based on algorithm // - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation // - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false); converter = new aflibConverter( true, useLinear, false);
#endif
} }
encoderOpen = false; encoderOpen = false;
@ -243,7 +251,16 @@ VorbisLibEncoder :: open ( void )
// initialize the resampling coverter if needed // initialize the resampling coverter if needed
if ( converter ) { if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
converterData.data_out = new float[getInChannel() * converterData.output_frames];
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel()); converter->initialize( resampleRatio, getInChannel());
#endif
} }
encoderOpen = true; encoderOpen = true;
@ -307,13 +324,24 @@ VorbisLibEncoder :: write ( const void * buf,
// resample if needed // resample if needed
int inCount = nSamples; int inCount = nSamples;
int outCount = (int) (inCount * resampleRatio); int outCount = (int) (inCount * resampleRatio);
short int * resampledBuffer = new short int[outCount * channels]; short int * resampledBuffer = new short int[(outCount+1)* channels];
int converted; int converted;
#ifdef HAVE_SRC_LIB
converterData.input_frames = nSamples;
src_short_to_float_array (shortBuffer, converterData.data_in, totalSamples);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
src_float_to_short_array(converterData.data_out, resampledBuffer, converted*channels);
#else
converted = converter->resample( inCount, converted = converter->resample( inCount,
outCount, outCount,
shortBuffer, shortBuffer,
resampledBuffer ); resampledBuffer );
#endif
vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState, vorbisBuffer = vorbis_analysis_buffer( &vorbisDspState,
converted); converted);

View File

@ -52,7 +52,11 @@
#include "Reporter.h" #include "Reporter.h"
#include "AudioEncoder.h" #include "AudioEncoder.h"
#include "CastSink.h" #include "CastSink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h" #include "aflibConverter.h"
#endif
/* ================================================================ constants */ /* ================================================================ constants */
@ -115,9 +119,14 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
double resampleRatio; double resampleRatio;
/** /**
* aflibConverter object for possible resampling * sample rate converter object for possible resampling
*/ */
#ifdef HAVE_SRC_LIB
SRC_STATE * converter;
SRC_DATA converterData;
#else
aflibConverter * converter; aflibConverter * converter;
#endif
/** /**
* Initialize the object. * Initialize the object.
@ -137,7 +146,13 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
strip ( void ) throw ( Exception ) strip ( void ) throw ( Exception )
{ {
if ( converter ) { if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
delete [] converterData.data_out;
src_delete (converter);
#else
delete converter; delete converter;
#endif
} }
} }

View File

@ -113,7 +113,7 @@ aacPlusEncoder :: open ( void )
writeOffset += IIR21_reSampler[0].delay*MAX_CHANNELS; writeOffset += IIR21_reSampler[0].delay*MAX_CHANNELS;
} }
sampleRateAAC = getInSampleRate(); sampleRateAAC = getOutSampleRate();
config.bitRate = bitrate; config.bitRate = bitrate;
config.nChannelsIn=getInChannel(); config.nChannelsIn=getInChannel();
config.nChannelsOut=nChannelsAAC; config.nChannelsOut=nChannelsAAC;
@ -152,6 +152,31 @@ aacPlusEncoder :: open ( void )
inSamples = AACENC_BLOCKSIZE * getInChannel() * 2; inSamples = AACENC_BLOCKSIZE * getInChannel() * 2;
// initialize the resampling coverter if needed
if ( converter ) {
#ifdef HAVE_SRC_LIB
converterData.input_frames = 4096/((getInBitsPerSample() / 8) * getInChannel());
converterData.data_in = new float[converterData.input_frames*getInChannel()];
converterData.output_frames = (int) (converterData.input_frames * resampleRatio + 1);
if ((int) inSamples > getInChannel() * converterData.output_frames) {
resampledOffset = new float[2 * inSamples];
} else {
resampledOffset = new float[2 * getInChannel() * converterData.input_frames];
}
converterData.src_ratio = resampleRatio;
converterData.end_of_input = 0;
#else
converter->initialize( resampleRatio, getInChannel());
//needed 2x(converted input samples) to handle offsets
int outCount = 2 * getInChannel() * (inSamples + 1);
if (resampleRatio > 1)
outCount = (int) (outCount * resampleRatio);
resampledOffset = new short int[outCount];
#endif
resampledOffsetSize = 0;
}
aacplusOpen = true; aacplusOpen = true;
reportEvent(10, "bitrate=", bitrate); reportEvent(10, "bitrate=", bitrate);
reportEvent(10, "nChannelsIn", getInChannel()); reportEvent(10, "nChannelsIn", getInChannel());
@ -181,34 +206,84 @@ aacPlusEncoder :: write ( const void * buf,
unsigned int processed = len - (len % sampleSize); unsigned int processed = len - (len % sampleSize);
unsigned int nSamples = processed / sampleSize; unsigned int nSamples = processed / sampleSize;
unsigned int samples = (unsigned int) nSamples * channels; unsigned int samples = (unsigned int) nSamples * channels;
int processedSamples = 0;
if ( converter ) {
unsigned int converted;
#ifdef HAVE_SRC_LIB
src_short_to_float_array ((short *) buf, converterData.data_in, samples);
converterData.input_frames = nSamples;
converterData.data_out = resampledOffset + (resampledOffsetSize * channels);
int srcError = src_process (converter, &converterData);
if (srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
converted = converterData.output_frames_gen;
#else
int inCount = nSamples;
short int * shortBuffer = new short int[samples];
int outCount = (int) (inCount * resampleRatio);
unsigned char * b = (unsigned char*) buf;
Util::conv( bitsPerSample, b, processed, shortBuffer, isInBigEndian());
converted = converter->resample( inCount,
outCount+1,
shortBuffer,
&resampledOffset[resampledOffsetSize*channels]);
delete[] shortBuffer;
#endif
resampledOffsetSize += converted;
// encode samples (if enough)
while(resampledOffsetSize - processedSamples >= inSamples/channels) {
#ifdef HAVE_SRC_LIB
short *shortData = new short[inSamples];
src_float_to_short_array(resampledOffset + (processedSamples * channels),
shortData, inSamples) ;
encodeAacSamples (shortData, inSamples, channels);
delete [] shortData;
#else
encodeAacSamples (&resampledOffset[processedSamples*channels], inSamples, channels);
#endif
processedSamples+=inSamples/channels;
}
if (processedSamples && (int) resampledOffsetSize >= processedSamples) {
resampledOffsetSize -= processedSamples;
//move least part of resampled data to beginning
if(resampledOffsetSize)
#ifdef HAVE_SRC_LIB
resampledOffset = (float *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*channels*sizeof(float));
#else
resampledOffset = (short *) memmove(resampledOffset, &resampledOffset[processedSamples*channels],
resampledOffsetSize*sampleSize);
#endif
}
} else {
encodeAacSamples ((short *) buf, samples, channels);
}
return samples;
}
void
aacPlusEncoder :: encodeAacSamples (short *TimeDataPcm, unsigned int samples, int channels)
throw ( Exception )
{
unsigned int i; unsigned int i;
int ch, outSamples, numOutBytes; int ch, outSamples, numOutBytes;
reportEvent(10, "converting short to float");
short *TimeDataPcm = (short *) buf;
if(channels == 2) {
for (i=0; i<samples; i++) for (i=0; i<samples; i++)
inBuf[i+writeOffset+writtenSamples] = (float) TimeDataPcm[i]; inBuf[(2/channels)*i+writeOffset+writtenSamples] = (float) TimeDataPcm[i];
} else {
/* using only left channel buffer for mono encoder */
for (i=0; i<samples; i++)
inBuf[writeOffset+2*writtenSamples+2*i] = (float) TimeDataPcm[i];
}
writtenSamples+=samples; writtenSamples+=samples;
reportEvent(10, "writtenSamples", writtenSamples);
if (writtenSamples < inSamples) if (writtenSamples < inSamples)
return samples; return;
/* encode one SBR frame */ /* encode one SBR frame */
reportEvent(10, "encode one SBR frame");
EnvEncodeFrame( hEnvEnc, EnvEncodeFrame( hEnvEnc,
inBuf + envReadOffset, inBuf + envReadOffset,
inBuf + coreWriteOffset, inBuf + coreWriteOffset,
@ -216,11 +291,8 @@ aacPlusEncoder :: write ( const void * buf,
&numAncDataBytes, &numAncDataBytes,
ancDataBytes); ancDataBytes);
reportEvent(10, "numAncDataBytes=", numAncDataBytes);
/* 2:1 downsampling for AAC core */ /* 2:1 downsampling for AAC core */
if (!useParametricStereo) { if (!useParametricStereo) {
reportEvent(10, "2:1 downsampling for AAC core");
for( ch=0; ch<nChannelsAAC; ch++ ) for( ch=0; ch<nChannelsAAC; ch++ )
IIR21_Downsample( &(IIR21_reSampler[ch]), IIR21_Downsample( &(IIR21_reSampler[ch]),
inBuf + writeOffset+ch, inBuf + writeOffset+ch,
@ -229,12 +301,9 @@ aacPlusEncoder :: write ( const void * buf,
inBuf+ch, inBuf+ch,
&outSamples, &outSamples,
MAX_CHANNELS); MAX_CHANNELS);
reportEvent(10, "outSamples=", outSamples);
} }
/* encode one AAC frame */ /* encode one AAC frame */
reportEvent(10, "encode one AAC frame");
AacEncEncode( aacEnc, AacEncEncode( aacEnc,
inBuf, inBuf,
useParametricStereo ? 1 : MAX_CHANNELS, /* stride (step) */ useParametricStereo ? 1 : MAX_CHANNELS, /* stride (step) */
@ -250,17 +319,15 @@ aacPlusEncoder :: write ( const void * buf,
/* Write one frame of encoded audio */ /* Write one frame of encoded audio */
if (numOutBytes) { if (numOutBytes) {
reportEvent(10, "Write one frame of encoded audio:", numOutBytes+ADTS_HEADER_SIZE);
adts_hdr_up(outBuf, numOutBytes); adts_hdr_up(outBuf, numOutBytes);
sink->write(outBuf, numOutBytes+ADTS_HEADER_SIZE); sink->write(outBuf, numOutBytes+ADTS_HEADER_SIZE);
} }
writtenSamples=0; writtenSamples=0;
return samples; return;
} }
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Flush the data from the encoder * Flush the data from the encoder
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/

View File

@ -65,6 +65,11 @@ extern "C" {
#include "Reporter.h" #include "Reporter.h"
#include "AudioEncoder.h" #include "AudioEncoder.h"
#include "Sink.h" #include "Sink.h"
#ifdef HAVE_SRC_LIB
#include <samplerate.h>
#else
#include "aflibConverter.h"
#endif
/* ================================================================ constants */ /* ================================================================ constants */
@ -96,6 +101,24 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
*/ */
bool aacplusOpen; bool aacplusOpen;
/**
* Resample ratio
*/
double resampleRatio;
/**
* sample rate converter object for possible resampling
*/
#ifdef HAVE_SRC_LIB
SRC_STATE *converter;
SRC_DATA converterData;
float *resampledOffset;
#else
aflibConverter *converter;
short *resampledOffset;
#endif
unsigned int resampledOffsetSize;
/** /**
* The Sink to dump aac+ data to * The Sink to dump aac+ data to
*/ */
@ -162,6 +185,59 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
"input channels and output channels do not match"); "input channels and output channels do not match");
} }
if ( getOutSampleRate() == getInSampleRate() ) {
resampleRatio = 1;
converter = 0;
} else if (getInBitsPerSample() == 16) {
resampleRatio = ( (double) getOutSampleRate() /
(double) getInSampleRate() );
// Determine if we can use linear interpolation.
// The inverse of the ratio must be a power of two for linear mode to
// be of sufficient quality.
bool useLinear = true;
double inverse = 1 / resampleRatio;
int integer = (int) inverse;
// Check that the inverse of the ratio is an integer
if( integer == inverse ) {
while( useLinear && integer ) { // Loop through the bits
// If the lowest order bit is not the only one set
if( integer & 1 && integer != 1 ) {
// Not a power of two; cannot use linear
useLinear = false;
} else {
// Shift all the bits over and try again
integer >>= 1;
}
}
} else {
useLinear = false;
}
// If we get here and useLinear is still true, then we have
// a power of two.
// open the aflibConverter in
// - high quality
// - linear or quadratic (non-linear) based on algorithm
// - not filter interpolation
#ifdef HAVE_SRC_LIB
int srcError = 0;
converter = src_new(useLinear == true ? SRC_LINEAR : SRC_SINC_FASTEST,
getInChannel(), &srcError);
if(srcError)
throw Exception (__FILE__, __LINE__, "libsamplerate error: ", src_strerror (srcError));
#else
converter = new aflibConverter( true, useLinear, false);
#endif
} else {
throw Exception( __FILE__, __LINE__,
"specified bits per sample with samplerate conversion not supported",
getInBitsPerSample() );
}
bitrate = getOutBitrate() * 1000; bitrate = getOutBitrate() * 1000;
bandwidth = 0; bandwidth = 0;
useParametricStereo = 0; useParametricStereo = 0;
@ -172,7 +248,6 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
writtenSamples = 0; writtenSamples = 0;
aacEnc = NULL; aacEnc = NULL;
hEnvEnc=NULL; hEnvEnc=NULL;
} }
/** /**
@ -183,8 +258,20 @@ class aacPlusEncoder : public AudioEncoder, public virtual Reporter
inline void inline void
strip ( void ) throw ( Exception ) strip ( void ) throw ( Exception )
{ {
if ( converter ) {
#ifdef HAVE_SRC_LIB
delete [] converterData.data_in;
src_delete (converter);
#else
delete converter;
#endif
delete [] resampledOffset;
}
} }
void
encodeAacSamples (short *TimeDataPcm, unsigned int samples, int channels)
throw ( Exception );
protected: protected:

View File

@ -107,9 +107,11 @@ main (
int res = -1; int res = -1;
std::cout << "DarkIce " << VERSION std::cout << "DarkIce " << VERSION
<< " live audio streamer, http://darkice.tyrell.hu/" << " live audio streamer, http://code.google.com/p/darkice/"
<< std::endl << std::endl
<< "Copyright (c) 2000-2007, Tyrell Hungary, http://tyrell.hu/" << "Copyright (c) 2000-2007, Tyrell Hungary, http://tyrell.hu/"
<< std::endl
<< "Copyright (c) 2008-2009, Akos Maroy and Rafael Diniz"
<< std::endl << std::endl; << std::endl << std::endl;
try { try {