added initial implementation of file dump cutting, re #3

This commit is contained in:
darkeye 2007-01-14 16:12:32 +00:00
parent cf2d4c85f0
commit ee4ae648d0
28 changed files with 462 additions and 124 deletions

View File

@ -1,12 +1,14 @@
DarkIce next release DarkIce next release
o added logging facility - [file-X] targets will cut the saved file
and rename it as needed when darkice recieves the SIGUSR1 signal
o added default configuration file handling - if no configuration file o added default configuration file handling - if no configuration file
is specified, /etc/darkice.cfg is used is specified, /etc/darkice.cfg is used
o fix to enable compiling on 64 bit platforms o fix to enable compiling on 64 bit platforms
thanks to Alexander Vlasov <zulu@galaradio.com> and thanks to Alexander Vlasov <zulu@galaradio.com> and
Mariusz Mazur <mmazur@kernel.pl> Mariusz Mazur <mmazur@kernel.pl>
o fix to enable file dump feature using ogg vorbis. o fix to enable file dump feature using ogg vorbis.
thanks to <derrick@csociety.org> thanks to <derrick@csociety.org>
19-05-2006 DarkIce 0.17.1 released 19-05-2006 DarkIce 0.17.1 released

View File

@ -71,6 +71,11 @@ class AudioEncoder : public Sink, public virtual Referable
private: private:
/**
* The Sink to dump the encoded data to
*/
Ref<Sink> sink;
/** /**
* Sample rate of the input. * Sample rate of the input.
*/ */
@ -119,6 +124,7 @@ class AudioEncoder : public Sink, public virtual Referable
/** /**
* Initialize the object. * Initialize the object.
* *
* @param sink the sink to send encoded output to
* @param inSampleRate sample rate of the input. * @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input. * @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input. * @param inChannel number of channels of the input.
@ -130,7 +136,8 @@ class AudioEncoder : public Sink, public virtual Referable
* @exception Exception * @exception Exception
*/ */
inline void inline void
init ( unsigned int inSampleRate, init ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample, unsigned int inBitsPerSample,
unsigned int inChannel, unsigned int inChannel,
bool inBigEndian, bool inBigEndian,
@ -140,6 +147,7 @@ class AudioEncoder : public Sink, public virtual Referable
unsigned int outSampleRate, unsigned int outSampleRate,
unsigned int outChannel ) throw ( Exception ) unsigned int outChannel ) throw ( Exception )
{ {
this->sink = sink;
this->inSampleRate = inSampleRate; this->inSampleRate = inSampleRate;
this->inBitsPerSample = inBitsPerSample; this->inBitsPerSample = inBitsPerSample;
this->inChannel = inChannel; this->inChannel = inChannel;
@ -182,6 +190,7 @@ class AudioEncoder : public Sink, public virtual Referable
/** /**
* Constructor. * Constructor.
* *
* @param sink the sink to send encoded output to
* @param inSampleRate sample rate of the input. * @param inSampleRate sample rate of the input.
* @param inBitsPerSample number of bits per sample of the input. * @param inBitsPerSample number of bits per sample of the input.
* @param inChannel number of channels of the input. * @param inChannel number of channels of the input.
@ -196,7 +205,8 @@ class AudioEncoder : public Sink, public virtual Referable
* @exception Exception * @exception Exception
*/ */
inline inline
AudioEncoder ( unsigned int inSampleRate, AudioEncoder ( Sink * sink,
unsigned int inSampleRate,
unsigned int inBitsPerSample, unsigned int inBitsPerSample,
unsigned int inChannel, unsigned int inChannel,
bool inBigEndian, bool inBigEndian,
@ -207,7 +217,8 @@ class AudioEncoder : public Sink, public virtual Referable
unsigned int outChannel = 0 ) unsigned int outChannel = 0 )
throw ( Exception ) throw ( Exception )
{ {
init ( inSampleRate, init ( sink,
inSampleRate,
inBitsPerSample, inBitsPerSample,
inChannel, inChannel,
inBigEndian, inBigEndian,
@ -221,6 +232,7 @@ class AudioEncoder : public Sink, public virtual Referable
/** /**
* Constructor. * Constructor.
* *
* @param sink the sink to send encoded output to
* @param as get input sample rate, bits per sample and channels * @param as get input sample rate, bits per sample and channels
* from this AudioSource. * from this AudioSource.
* @param outBitrateMode the bit rate mode of the output. * @param outBitrateMode the bit rate mode of the output.
@ -233,7 +245,8 @@ class AudioEncoder : public Sink, public virtual Referable
* @exception Exception * @exception Exception
*/ */
inline inline
AudioEncoder ( const AudioSource * as, AudioEncoder ( Sink * sink,
const AudioSource * as,
BitrateMode outBitrateMode, BitrateMode outBitrateMode,
unsigned int outBitrate, unsigned int outBitrate,
double outQuality, double outQuality,
@ -241,7 +254,8 @@ class AudioEncoder : public Sink, public virtual Referable
unsigned int outChannel = 0 ) unsigned int outChannel = 0 )
throw ( Exception) throw ( Exception)
{ {
init( as->getSampleRate(), init( sink,
as->getSampleRate(),
as->getBitsPerSample(), as->getBitsPerSample(),
as->getChannel(), as->getChannel(),
as->isBigEndian(), as->isBigEndian(),
@ -260,7 +274,8 @@ class AudioEncoder : public Sink, public virtual Referable
inline inline
AudioEncoder ( const AudioEncoder & encoder ) throw ( Exception ) AudioEncoder ( const AudioEncoder & encoder ) throw ( Exception )
{ {
init ( encoder.inSampleRate, init ( encoder.sink.get(),
encoder.inSampleRate,
encoder.inBitsPerSample, encoder.inBitsPerSample,
encoder.inChannel, encoder.inChannel,
encoder.inBigEndian, encoder.inBigEndian,
@ -284,7 +299,8 @@ class AudioEncoder : public Sink, public virtual Referable
if ( this != &encoder ) { if ( this != &encoder ) {
strip(); strip();
init ( encoder.inSampleRate, init ( encoder.sink.get(),
encoder.inSampleRate,
encoder.inBitsPerSample, encoder.inBitsPerSample,
encoder.inChannel, encoder.inChannel,
encoder.inBigEndian, encoder.inBigEndian,
@ -312,6 +328,17 @@ class AudioEncoder : public Sink, public virtual Referable
strip(); strip();
} }
/**
* Get the underlying sink, that the encoded content is sent to.
*
* @return the underlying sink
*/
inline virtual Ref<Sink>
getSink(void) throw ()
{
return sink;
}
/** /**
* Get the number of channels of the input. * Get the number of channels of the input.
* *
@ -438,6 +465,20 @@ class AudioEncoder : public Sink, public virtual Referable
*/ */
virtual void virtual void
stop ( void ) throw ( Exception ) = 0; stop ( void ) throw ( Exception ) = 0;
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*
* Typically this action is delegated to the underlying sink.
*/
inline virtual void
cut ( void ) throw ()
{
sink->cut();
}
}; };

View File

@ -366,6 +366,18 @@ class BufferedSink : public Sink, public virtual Reporter
write( b, 0); write( b, 0);
} }
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
inline virtual void
cut ( void ) throw ()
{
flush();
sink->cut();
}
/** /**
* Close the BufferedSink. Closes the underlying Sink. * Close the BufferedSink. Closes the underlying Sink.
* *

View File

@ -362,6 +362,19 @@ class CastSink : public Sink, public virtual Reporter
return getSink()->flush(); return getSink()->flush();
} }
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
inline virtual void
cut ( void ) throw ()
{
if ( streamDump != 0 ) {
streamDump->cut();
}
}
/** /**
* Close the CastSink. * Close the CastSink.
* *

View File

@ -325,6 +325,22 @@ Connector :: transfer ( unsigned long bytes,
} }
/*------------------------------------------------------------------------------
* Signal to each sink to cut what they've done so far, and start anew.
*----------------------------------------------------------------------------*/
void
Connector :: cut ( void ) throw ()
{
unsigned int u;
for ( u = 0; u < numSinks; ++u ) {
if ( sinks[u]->isOpen() ) {
sinks[u]->cut();
}
}
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Close the source and all the sinks if needed * Close the source and all the sinks if needed
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/

View File

@ -234,6 +234,15 @@ class Connector : public virtual Referable, public virtual Reporter
unsigned int sec, unsigned int sec,
unsigned int usec ) throw ( Exception ); unsigned int usec ) throw ( Exception );
/**
* Signal to each sink we have that they need to cut what they are
* doing, and start again. For FileSinks, this usually means to
* save the archive file recorded so far, and start a new archive
* file.
*/
virtual void
cut ( void ) throw ();
/** /**
* Close the Connector. The Source and all Sinks are closed. * Close the Connector. The Source and all Sinks are closed.
* *

View File

@ -1137,6 +1137,20 @@ DarkIce :: run ( void ) throw ( Exception )
} }
/*------------------------------------------------------------------------------
* Tell each sink to cut what they are doing, and start again.
*----------------------------------------------------------------------------*/
void
DarkIce :: cut ( void ) throw ()
{
reportEvent( 5, "cutting");
encConnector->cut();
reportEvent( 5, "cutting ends");
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
$Source$ $Source$

View File

@ -296,6 +296,15 @@ class DarkIce : public virtual Referable, public virtual Reporter
virtual int virtual int
run ( void ) throw ( Exception ); run ( void ) throw ( Exception );
/**
* Signal to each sink we have that they need to cut what they are
* doing, and start again. For FileSinks, this usually means to
* save the archive file recorded so far, and start a new archive
* file.
*/
virtual void
cut ( void ) throw ();
}; };

View File

@ -71,7 +71,7 @@ FaacEncoder :: open ( void )
} }
// open the underlying sink // open the underlying sink
if ( !sink->open() ) { if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"faac lib opening underlying sink error"); "faac lib opening underlying sink error");
} }
@ -145,7 +145,7 @@ FaacEncoder :: write ( const void * buf,
inSamples, inSamples,
faacBuf, faacBuf,
maxOutputBytes); maxOutputBytes);
sink->write(faacBuf, outputBytes); getSink()->write(faacBuf, outputBytes);
processedSamples += inSamples; processedSamples += inSamples;
} }
@ -167,7 +167,7 @@ FaacEncoder :: flush ( void )
return; return;
} }
sink->flush(); getSink()->flush();
} }
@ -182,7 +182,7 @@ FaacEncoder :: close ( void ) throw ( Exception )
faacEncClose(encoderHandle); faacEncClose(encoderHandle);
faacOpen = false; faacOpen = false;
sink->close(); getSink()->close();
} }
} }

View File

@ -98,15 +98,9 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
*/ */
int lowpass; int lowpass;
/**
* The Sink to dump mp3 data to
*/
Ref<Sink> sink;
/** /**
* Initialize the object. * Initialize the object.
* *
* @param sink the sink to send mp3 output to
* @param lowpass frequency threshold for the lowpass filter. * @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut. * Input above this frequency is cut.
* If 0, faac's default values are used, * If 0, faac's default values are used,
@ -114,11 +108,9 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
* @exception Exception * @exception Exception
*/ */
inline void inline void
init ( Sink * sink, init ( int lowpass) throw (Exception)
int lowpass) throw (Exception)
{ {
this->faacOpen = false; this->faacOpen = false;
this->sink = sink;
this->lowpass = lowpass; this->lowpass = lowpass;
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) { if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
@ -205,7 +197,8 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
int lowpass = 0) int lowpass = 0)
throw ( Exception ) throw ( Exception )
: AudioEncoder ( inSampleRate, : AudioEncoder ( sink,
inSampleRate,
inBitsPerSample, inBitsPerSample,
inChannel, inChannel,
inBigEndian, inBigEndian,
@ -215,7 +208,7 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink, lowpass); init( lowpass);
} }
/** /**
@ -248,14 +241,15 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
int lowpass = 0) int lowpass = 0)
throw ( Exception ) throw ( Exception )
: AudioEncoder ( as, : AudioEncoder ( sink,
as,
outBitrateMode, outBitrateMode,
outBitrate, outBitrate,
outQuality, outQuality,
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink, lowpass); init( lowpass);
} }
/** /**
@ -268,7 +262,7 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
throw ( Exception ) throw ( Exception )
: AudioEncoder( encoder ) : AudioEncoder( encoder )
{ {
init( encoder.sink.get(), encoder.lowpass); init( encoder.lowpass);
} }
@ -299,7 +293,7 @@ class FaacEncoder : public AudioEncoder, public virtual Reporter
if ( this != &encoder ) { if ( this != &encoder ) {
strip(); strip();
AudioEncoder::operator=( encoder); AudioEncoder::operator=( encoder);
init( encoder.sink.get(), encoder.lowpass); init( encoder.lowpass);
} }
return *this; return *this;

View File

@ -238,6 +238,17 @@ class FileCast : public CastSink
return targetFile->flush(); return targetFile->flush();
} }
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
inline virtual void
cut ( void ) throw ()
{
targetFile->cut();
}
/** /**
* Close the FileCast. * Close the FileCast.
* *

View File

@ -81,6 +81,17 @@
#error need string.h #error need string.h
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#include <iostream>
#include <sstream>
#include <fstream>
#include "Util.h" #include "Util.h"
#include "Exception.h" #include "Exception.h"
@ -242,7 +253,8 @@ FileSink :: canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception ) unsigned int usec ) throw ( Exception )
{ {
fd_set fdset; fd_set fdset;
struct timeval tv; struct timespec timespec;
sigset_t sigset;
int ret; int ret;
if ( !isOpen() ) { if ( !isOpen() ) {
@ -251,10 +263,15 @@ FileSink :: canWrite ( unsigned int sec,
FD_ZERO( &fdset); FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset); FD_SET( fileDescriptor, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( fileDescriptor + 1, NULL, &fdset, NULL, &tv); timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, NULL, &fdset, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");
@ -291,6 +308,58 @@ FileSink :: write ( const void * buf,
} }
/*------------------------------------------------------------------------------
* Get the file name to where to move the data saved so far.
* The trick is to read the file name from a file named
* /tmp/darkice.$PID , where $PID is the current process id
*----------------------------------------------------------------------------*/
std::string
FileSink :: getArchiveFileName ( void ) throw ( Exception )
{
pid_t pid = getpid();
std::stringstream metaFileName;
metaFileName << "/tmp/darkice." << pid;
std::ifstream ifs(metaFileName.str().c_str());
if (!ifs.good()) {
throw Exception(__FILE__, __LINE__,
"can't find file ", metaFileName.str().c_str(), 0);
}
std::string archiveFileName;
ifs >> archiveFileName;
ifs.close();
return archiveFileName;
}
/*------------------------------------------------------------------------------
* Cut what we've done so far, and start anew.
*----------------------------------------------------------------------------*/
void
FileSink :: cut ( void ) throw ()
{
flush();
close();
try {
std::string archiveFileName = getArchiveFileName();
if (::rename(fileName, archiveFileName.c_str()) != 0) {
reportEvent(2, "couldn't move file", fileName,
"to", archiveFileName);
}
} catch ( Exception &e ) {
reportEvent(2, "error during archive cut", e);
}
create();
open();
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Close the FileSink * Close the FileSink
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/

View File

@ -80,6 +80,16 @@ class FileSink : public Sink, public virtual Reporter
void void
strip ( void ) throw ( Exception ); strip ( void ) throw ( Exception );
/**
* Get the file name to where to move the data saved so far.
* Used in cut().
*
* @return the file name where to move the data saved so far.
* @throws Exception on file operation errors
*/
std::string
getArchiveFileName( void ) throw ( Exception );
protected: protected:
@ -227,6 +237,14 @@ class FileSink : public Sink, public virtual Reporter
{ {
} }
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
virtual void
cut ( void ) throw ();
/** /**
* Close the FileSink. * Close the FileSink.
* *

View File

@ -69,6 +69,12 @@
#error need string.h #error need string.h
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#include "Exception.h" #include "Exception.h"
#include "Util.h" #include "Util.h"
@ -197,7 +203,8 @@ FileSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception ) unsigned int usec ) throw ( Exception )
{ {
fd_set fdset; fd_set fdset;
struct timeval tv; struct timespec timespec;
sigset_t sigset;
int ret; int ret;
if ( !isOpen() ) { if ( !isOpen() ) {
@ -206,10 +213,15 @@ FileSource :: canRead ( unsigned int sec,
FD_ZERO( &fdset); FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset); FD_SET( fileDescriptor, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( fileDescriptor + 1, &fdset, NULL, NULL, &tv); timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");

View File

@ -71,7 +71,7 @@ LameLibEncoder :: open ( void )
} }
// open the underlying sink // open the underlying sink
if ( !sink->open() ) { if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"lame lib opening underlying sink error"); "lame lib opening underlying sink error");
} }
@ -331,7 +331,7 @@ LameLibEncoder :: write ( const void * buf,
return 0; return 0;
} }
unsigned int written = sink->write( mp3Buf, ret); unsigned int written = getSink()->write( mp3Buf, ret);
delete[] mp3Buf; delete[] mp3Buf;
// just let go data that could not be written // just let go data that could not be written
if ( written < (unsigned int) ret ) { if ( written < (unsigned int) ret ) {
@ -362,7 +362,7 @@ LameLibEncoder :: flush ( void )
ret = lame_encode_flush( lameGlobalFlags, mp3Buf, mp3Size ); ret = lame_encode_flush( lameGlobalFlags, mp3Buf, mp3Size );
unsigned int written = sink->write( mp3Buf, ret); unsigned int written = getSink()->write( mp3Buf, ret);
delete[] mp3Buf; delete[] mp3Buf;
// just let go data that could not be written // just let go data that could not be written
@ -372,7 +372,7 @@ LameLibEncoder :: flush ( void )
ret - written); ret - written);
} }
sink->flush(); getSink()->flush();
} }
@ -387,7 +387,7 @@ LameLibEncoder :: close ( void ) throw ( Exception )
lame_close( lameGlobalFlags); lame_close( lameGlobalFlags);
lameGlobalFlags = 0; lameGlobalFlags = 0;
sink->close(); getSink()->close();
} }
} }

View File

@ -78,11 +78,6 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
*/ */
lame_global_flags * lameGlobalFlags; lame_global_flags * lameGlobalFlags;
/**
* The Sink to dump mp3 data to
*/
Ref<Sink> sink;
/** /**
* Lowpass filter. Sound frequency in Hz, from where up the * Lowpass filter. Sound frequency in Hz, from where up the
* input is cut. * input is cut.
@ -98,7 +93,6 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
/** /**
* Initialize the object. * Initialize the object.
* *
* @param sink the sink to send mp3 output to
* @param lowpass frequency threshold for the lowpass filter. * @param lowpass frequency threshold for the lowpass filter.
* Input above this frequency is cut. * Input above this frequency is cut.
* If 0, lame's default values are used, * If 0, lame's default values are used,
@ -110,12 +104,10 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
* @exception Exception * @exception Exception
*/ */
inline void inline void
init ( Sink * sink, init ( int lowpass,
int lowpass,
int highpass ) throw ( Exception ) int highpass ) throw ( Exception )
{ {
this->lameGlobalFlags = NULL; this->lameGlobalFlags = NULL;
this->sink = sink;
this->lowpass = lowpass; this->lowpass = lowpass;
this->highpass = highpass; this->highpass = highpass;
@ -209,7 +201,8 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
int highpass = 0 ) int highpass = 0 )
throw ( Exception ) throw ( Exception )
: AudioEncoder ( inSampleRate, : AudioEncoder ( sink,
inSampleRate,
inBitsPerSample, inBitsPerSample,
inChannel, inChannel,
inBigEndian, inBigEndian,
@ -219,7 +212,7 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink, lowpass, highpass); init( lowpass, highpass);
} }
/** /**
@ -257,14 +250,15 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
int highpass = 0 ) int highpass = 0 )
throw ( Exception ) throw ( Exception )
: AudioEncoder ( as, : AudioEncoder ( sink,
as,
outBitrateMode, outBitrateMode,
outBitrate, outBitrate,
outQuality, outQuality,
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink, lowpass, highpass); init( lowpass, highpass);
} }
/** /**
@ -277,7 +271,7 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
throw ( Exception ) throw ( Exception )
: AudioEncoder( encoder ) : AudioEncoder( encoder )
{ {
init( encoder.sink.get(), encoder.lowpass, encoder.highpass ); init( encoder.lowpass, encoder.highpass );
} }
@ -308,7 +302,7 @@ class LameLibEncoder : public AudioEncoder, public virtual Reporter
if ( this != &encoder ) { if ( this != &encoder ) {
strip(); strip();
AudioEncoder::operator=( encoder); AudioEncoder::operator=( encoder);
init( encoder.sink.get(), encoder.lowpass, encoder.highpass ); init( encoder.lowpass, encoder.highpass );
} }
return *this; return *this;

View File

@ -293,6 +293,11 @@ MultiThreadedConnector :: sinkThread( int ixSink )
break; break;
} }
if ( threadData->cut) {
sink->cut();
threadData->cut = false;
}
if ( threadData->accepting ) { if ( threadData->accepting ) {
if ( sink->canWrite( 0, 0) ) { if ( sink->canWrite( 0, 0) ) {
try { try {
@ -337,6 +342,22 @@ MultiThreadedConnector :: sinkThread( int ixSink )
} }
/*------------------------------------------------------------------------------
* Signal to each sink to cut what they've done so far, and start anew.
*----------------------------------------------------------------------------*/
void
MultiThreadedConnector :: cut ( void ) throw ()
{
for ( unsigned int i = 0; i < numSinks; ++i ) {
threads[i].cut = true;
}
// TODO: it might be more appropriate to signal all the threads here
// but, they'll get signaled on new data anyway, and it might be
// enough for them to cut at that time
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Stop the treads * Stop the treads
* Close the source and all the sinks if needed * Close the source and all the sinks if needed

View File

@ -107,6 +107,12 @@ class MultiThreadedConnector : public virtual Connector
*/ */
bool isDone; bool isDone;
/**
* A flag to show that the sink should be made to cut in the
* next iteration.
*/
bool cut;
/** /**
* Default constructor. * Default constructor.
*/ */
@ -118,6 +124,7 @@ class MultiThreadedConnector : public virtual Connector
this->thread = 0; this->thread = 0;
this->accepting = false; this->accepting = false;
this->isDone = false; this->isDone = false;
this->cut = false;
} }
/** /**
@ -313,6 +320,15 @@ class MultiThreadedConnector : public virtual Connector
unsigned int sec, unsigned int sec,
unsigned int usec ) throw ( Exception ); unsigned int usec ) throw ( Exception );
/**
* Signal to each sink we have that they need to cut what they are
* doing, and start again. For FileSinks, this usually means to
* save the archive file recorded so far, and start a new archive
* file.
*/
virtual void
cut ( void ) throw ();
/** /**
* Close the Connector. The Source and all Sinks are closed. * Close the Connector. The Source and all Sinks are closed.
* *
@ -322,7 +338,7 @@ class MultiThreadedConnector : public virtual Connector
close ( void ) throw ( Exception ); close ( void ) throw ( Exception );
/** /**
* This is the function for each thread. * This is the worker function for each thread.
* This function has to return fast * This function has to return fast
* *
* @param ixSink the index of the sink this thread works on. * @param ixSink the index of the sink this thread works on.

View File

@ -80,6 +80,12 @@
#error need sys/ioctl.h #error need sys/ioctl.h
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#ifdef HAVE_SYS_SOUNDCARD_H #ifdef HAVE_SYS_SOUNDCARD_H
#include <sys/soundcard.h> #include <sys/soundcard.h>
#else #else
@ -230,7 +236,8 @@ OssDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception ) unsigned int usec ) throw ( Exception )
{ {
fd_set fdset; fd_set fdset;
struct timeval tv; struct timespec timespec;
sigset_t sigset;
int ret; int ret;
if ( !isOpen() ) { if ( !isOpen() ) {
@ -247,10 +254,15 @@ OssDspSource :: canRead ( unsigned int sec,
FD_ZERO( &fdset); FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset); FD_SET( fileDescriptor, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( fileDescriptor + 1, &fdset, NULL, NULL, &tv); timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");

View File

@ -156,6 +156,14 @@ class Sink : public virtual Referable
virtual void virtual void
flush ( void ) throw ( Exception ) = 0; flush ( void ) throw ( Exception ) = 0;
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*/
virtual void
cut ( void ) throw () = 0;
/** /**
* Close the Sink. * Close the Sink.
* *

View File

@ -80,6 +80,12 @@
#error need sys/ioctl.h #error need sys/ioctl.h
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#if defined( HAVE_SYS_AUDIO_H ) #if defined( HAVE_SYS_AUDIO_H )
#include <sys/audio.h> #include <sys/audio.h>
#elif defined( HAVE_SYS_AUDIOIO_H ) #elif defined( HAVE_SYS_AUDIOIO_H )
@ -202,7 +208,8 @@ SolarisDspSource :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception ) unsigned int usec ) throw ( Exception )
{ {
fd_set fdset; fd_set fdset;
struct timeval tv; struct timespec timespec;
sigset_t sigset;
int ret; int ret;
if ( !isOpen() ) { if ( !isOpen() ) {
@ -211,10 +218,15 @@ SolarisDspSource :: canRead ( unsigned int sec,
FD_ZERO( &fdset); FD_ZERO( &fdset);
FD_SET( fileDescriptor, &fdset); FD_SET( fileDescriptor, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( fileDescriptor + 1, &fdset, NULL, NULL, &tv); timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( fileDescriptor + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");

View File

@ -81,6 +81,12 @@
#error need sys/time.h #error need sys/time.h
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error need signal.h
#endif
#include "Util.h" #include "Util.h"
#include "Exception.h" #include "Exception.h"
@ -243,7 +249,8 @@ TcpSocket :: canRead ( unsigned int sec,
unsigned int usec ) throw ( Exception ) unsigned int usec ) throw ( Exception )
{ {
fd_set fdset; fd_set fdset;
struct timeval tv; struct timespec timespec;
sigset_t sigset;
int ret; int ret;
if ( !isOpen() ) { if ( !isOpen() ) {
@ -252,11 +259,16 @@ TcpSocket :: canRead ( unsigned int sec,
FD_ZERO( &fdset); FD_ZERO( &fdset);
FD_SET( sockfd, &fdset); FD_SET( sockfd, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( sockfd + 1, &fdset, NULL, NULL, &tv); timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( sockfd + 1, &fdset, NULL, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");
} }
@ -305,7 +317,8 @@ TcpSocket :: canWrite ( unsigned int sec,
unsigned int usec ) throw ( Exception ) unsigned int usec ) throw ( Exception )
{ {
fd_set fdset; fd_set fdset;
struct timeval tv; struct timespec timespec;
sigset_t sigset;
int ret; int ret;
if ( !isOpen() ) { if ( !isOpen() ) {
@ -314,10 +327,15 @@ TcpSocket :: canWrite ( unsigned int sec,
FD_ZERO( &fdset); FD_ZERO( &fdset);
FD_SET( sockfd, &fdset); FD_SET( sockfd, &fdset);
tv.tv_sec = sec;
tv.tv_usec = usec;
ret = select( sockfd + 1, NULL, &fdset, NULL, &tv); timespec.tv_sec = sec;
timespec.tv_nsec = usec * 1000L;
// mask out SIGUSR1, as we're expecting that signal for other reasons
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
ret = pselect( sockfd + 1, NULL, &fdset, NULL, &timespec, &sigset);
if ( ret == -1 ) { if ( ret == -1 ) {
throw Exception( __FILE__, __LINE__, "select error"); throw Exception( __FILE__, __LINE__, "select error");

View File

@ -258,6 +258,18 @@ class TcpSocket : public Source, public Sink
{ {
} }
/**
* Cut what the sink has been doing so far, and start anew.
* This usually means separating the data sent to the sink up
* until now, and start saving a new chunk of data.
*
* For TcpSocket, this is a no-op.
*/
inline virtual void
cut ( void ) throw ()
{
}
/** /**
* Close the TcpSocket. * Close the TcpSocket.
* *

View File

@ -65,10 +65,9 @@ static const char fileid[] = "$Id$";
* Initialize the object * Initialize the object
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void void
TwoLameLibEncoder :: init ( Sink * sink ) throw ( Exception ) TwoLameLibEncoder :: init ( void ) throw ( Exception )
{ {
this->twolame_opts = NULL; this->twolame_opts = NULL;
this->sink = sink;
if ( getInBitsPerSample() != 16 ) { if ( getInBitsPerSample() != 16 ) {
throw Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
@ -106,7 +105,7 @@ TwoLameLibEncoder :: open ( void )
} }
// open the underlying sink // open the underlying sink
if ( !sink->open() ) { if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"TwoLAME lib opening underlying sink error"); "TwoLAME lib opening underlying sink error");
} }
@ -239,7 +238,7 @@ TwoLameLibEncoder :: write ( const void * buf,
return 0; return 0;
} }
unsigned int written = sink->write( mp2Buf, ret); unsigned int written = getSink()->write( mp2Buf, ret);
delete[] mp2Buf; delete[] mp2Buf;
// just let go data that could not be written // just let go data that could not be written
if ( written < (unsigned int) ret ) { if ( written < (unsigned int) ret ) {
@ -270,7 +269,7 @@ TwoLameLibEncoder :: flush ( void )
ret = twolame_encode_flush( twolame_opts, mp2Buf, mp2Size ); ret = twolame_encode_flush( twolame_opts, mp2Buf, mp2Size );
unsigned int written = sink->write( mp2Buf, ret); unsigned int written = getSink()->write( mp2Buf, ret);
delete[] mp2Buf; delete[] mp2Buf;
// just let go data that could not be written // just let go data that could not be written
@ -280,7 +279,7 @@ TwoLameLibEncoder :: flush ( void )
ret - written); ret - written);
} }
sink->flush(); getSink()->flush();
} }
@ -293,7 +292,7 @@ TwoLameLibEncoder :: close ( void ) throw ( Exception )
if ( isOpen() ) { if ( isOpen() ) {
flush(); flush();
twolame_close( &twolame_opts ); twolame_close( &twolame_opts );
sink->close(); getSink()->close();
} }
} }

View File

@ -78,11 +78,6 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
*/ */
twolame_options * twolame_opts; twolame_options * twolame_opts;
/**
* The Sink to dump mp2 data to
*/
Ref<Sink> sink;
/** /**
* Initialize the object. * Initialize the object.
* *
@ -90,7 +85,7 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
* @exception Exception * @exception Exception
*/ */
void void
init ( Sink * sink ) throw ( Exception ); init ( void ) throw ( Exception );
/** /**
* De-initialize the object. * De-initialize the object.
@ -147,7 +142,8 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
unsigned int outChannel = 0 ) unsigned int outChannel = 0 )
throw ( Exception ) throw ( Exception )
: AudioEncoder ( inSampleRate, : AudioEncoder ( sink,
inSampleRate,
inBitsPerSample, inBitsPerSample,
inChannel, inChannel,
inBigEndian, inBigEndian,
@ -157,7 +153,7 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink ); init();
} }
/** /**
@ -183,14 +179,15 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
unsigned int outChannel = 0 ) unsigned int outChannel = 0 )
throw ( Exception ) throw ( Exception )
: AudioEncoder ( as, : AudioEncoder ( sink,
as,
outBitrateMode, outBitrateMode,
outBitrate, outBitrate,
0.0f, // outQuality 0.0f, // outQuality
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink ); init();
} }
/** /**
@ -203,7 +200,7 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
throw ( Exception ) throw ( Exception )
: AudioEncoder( encoder ) : AudioEncoder( encoder )
{ {
init( encoder.sink.get() ); init();
} }
@ -234,7 +231,7 @@ class TwoLameLibEncoder : public AudioEncoder, public virtual Reporter
if ( this != &encoder ) { if ( this != &encoder ) {
strip(); strip();
AudioEncoder::operator=( encoder); AudioEncoder::operator=( encoder);
init( encoder.sink.get() ); init();
} }
return *this; return *this;

View File

@ -62,11 +62,9 @@ static const char fileid[] = "$Id$";
* Initialize the encoder * Initialize the encoder
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void void
VorbisLibEncoder :: init ( CastSink * sink, VorbisLibEncoder :: init ( unsigned int outMaxBitrate )
unsigned int outMaxBitrate )
throw ( Exception ) throw ( Exception )
{ {
this->sink = sink;
this->outMaxBitrate = outMaxBitrate; this->outMaxBitrate = outMaxBitrate;
if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) { if ( getInBitsPerSample() != 16 && getInBitsPerSample() != 8 ) {
@ -140,7 +138,7 @@ VorbisLibEncoder :: open ( void )
} }
// open the underlying sink // open the underlying sink
if ( !sink->open() ) { if ( !getSink()->open() ) {
throw Exception( __FILE__, __LINE__, throw Exception( __FILE__, __LINE__,
"vorbis lib opening underlying sink error"); "vorbis lib opening underlying sink error");
} }
@ -206,11 +204,17 @@ VorbisLibEncoder :: open ( void )
// create an empty vorbis_comment structure // create an empty vorbis_comment structure
vorbis_comment_init( &vorbisComment); vorbis_comment_init( &vorbisComment);
/* FIXME: removed title metadata when the sink type was changed from
* CastSink to the more generic Sink.
* make sure to add metadata somehow
// Add comment to vorbis headers to show title in players // Add comment to vorbis headers to show title in players
// stupid cast to (char*) because of stupid vorbis API // stupid cast to (char*) because of stupid vorbis API
if ( sink->getName() ) { if ( getSink()->getName() ) {
vorbis_comment_add_tag(&vorbisComment, "TITLE", (char*)sink->getName()); vorbis_comment_add_tag(&vorbisComment,
"TITLE",
(char*) getSink()->getName());
} }
*/
// create the vorbis stream headers and send them to the underlying sink // create the vorbis stream headers and send them to the underlying sink
ogg_packet header; ogg_packet header;
@ -231,8 +235,8 @@ VorbisLibEncoder :: open ( void )
ogg_page oggPage; ogg_page oggPage;
while ( ogg_stream_flush( &oggStreamState, &oggPage) ) { while ( ogg_stream_flush( &oggStreamState, &oggPage) ) {
sink->write( oggPage.header, oggPage.header_len); getSink()->write( oggPage.header, oggPage.header_len);
sink->write( oggPage.body, oggPage.body_len); getSink()->write( oggPage.body, oggPage.body_len);
} }
vorbis_comment_clear( &vorbisComment ); vorbis_comment_clear( &vorbisComment );
@ -346,7 +350,7 @@ VorbisLibEncoder :: flush ( void )
vorbis_analysis_wrote( &vorbisDspState, 0); vorbis_analysis_wrote( &vorbisDspState, 0);
vorbisBlocksOut(); vorbisBlocksOut();
sink->flush(); getSink()->flush();
} }
@ -370,8 +374,8 @@ VorbisLibEncoder :: vorbisBlocksOut ( void ) throw ( Exception )
while ( ogg_stream_pageout( &oggStreamState, &oggPage) ) { while ( ogg_stream_pageout( &oggStreamState, &oggPage) ) {
int written; int written;
written = sink->write( oggPage.header, oggPage.header_len); written = getSink()->write(oggPage.header, oggPage.header_len);
written += sink->write( oggPage.body, oggPage.body_len); written += getSink()->write( oggPage.body, oggPage.body_len);
if ( written < oggPage.header_len + oggPage.body_len ) { if ( written < oggPage.header_len + oggPage.body_len ) {
// just let go data that could not be written // just let go data that could not be written
@ -402,7 +406,7 @@ VorbisLibEncoder :: close ( void ) throw ( Exception )
encoderOpen = false; encoderOpen = false;
sink->close(); getSink()->close();
} }
} }

View File

@ -104,11 +104,6 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
*/ */
ogg_stream_state oggStreamState; ogg_stream_state oggStreamState;
/**
* The Sink to dump encoded data to
*/
Ref<CastSink> sink;
/** /**
* Maximum bitrate of the output in kbits/sec. If 0, don't care. * Maximum bitrate of the output in kbits/sec. If 0, don't care.
*/ */
@ -127,13 +122,11 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
/** /**
* Initialize the object. * Initialize the object.
* *
* @param sink the sink to send encoded output to
* @param the maximum bit rate * @param the maximum bit rate
* @exception Exception * @exception Exception
*/ */
void void
init ( CastSink * sink, init ( unsigned int outMaxBitrate ) throw ( Exception );
unsigned int outMaxBitrate ) throw ( Exception );
/** /**
* De-initialize the object. * De-initialize the object.
@ -204,7 +197,8 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
unsigned int outMaxBitrate = 0 ) unsigned int outMaxBitrate = 0 )
throw ( Exception ) throw ( Exception )
: AudioEncoder ( inSampleRate, : AudioEncoder ( sink,
inSampleRate,
inBitsPerSample, inBitsPerSample,
inChannel, inChannel,
inBigEndian, inBigEndian,
@ -214,7 +208,7 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink, outMaxBitrate); init( outMaxBitrate);
} }
/** /**
@ -245,14 +239,15 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
unsigned int outMaxBitrate = 0 ) unsigned int outMaxBitrate = 0 )
throw ( Exception ) throw ( Exception )
: AudioEncoder ( as, : AudioEncoder ( sink,
as,
outBitrateMode, outBitrateMode,
outBitrate, outBitrate,
outQuality, outQuality,
outSampleRate, outSampleRate,
outChannel ) outChannel )
{ {
init( sink, outMaxBitrate); init( outMaxBitrate);
} }
/** /**
@ -268,7 +263,7 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
if( encoder.isOpen() ) { if( encoder.isOpen() ) {
throw Exception(__FILE__, __LINE__, "don't copy open encoders"); throw Exception(__FILE__, __LINE__, "don't copy open encoders");
} }
init( encoder.sink.get(), encoder.getOutMaxBitrate() ); init( encoder.getOutMaxBitrate() );
} }
/** /**
@ -302,7 +297,7 @@ class VorbisLibEncoder : public AudioEncoder, public virtual Reporter
if ( this != &encoder ) { if ( this != &encoder ) {
strip(); strip();
AudioEncoder::operator=( encoder); AudioEncoder::operator=( encoder);
init( encoder.sink.get(), encoder.getOutMaxBitrate() ); init( encoder.getOutMaxBitrate() );
} }
return *this; return *this;

View File

@ -43,6 +43,12 @@
#error needs stdlib.h #error needs stdlib.h
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#else
#error needs signal.h
#endif
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
@ -54,6 +60,11 @@
/* =================================================== local data structures */ /* =================================================== local data structures */
/*------------------------------------------------------------------------------
* The DarkIce object we're running
*----------------------------------------------------------------------------*/
static Ref<DarkIce> darkice;
/* ================================================ local constants & macros */ /* ================================================ local constants & macros */
@ -76,6 +87,12 @@ static const char *DEFAULT_CONFIG_FILE = "/etc/darkice.cfg";
static void static void
showUsage ( std::ostream & os ); showUsage ( std::ostream & os );
/*------------------------------------------------------------------------------
* Handler for the SIGUSR1 signal
*----------------------------------------------------------------------------*/
static void
sigusr1Handler(int value);
/* ============================================================= module code */ /* ============================================================= module code */
@ -126,9 +143,12 @@ main (
Reporter::setReportVerbosity( verbosity ); Reporter::setReportVerbosity( verbosity );
Reporter::setReportOutputStream( std::cout ); Reporter::setReportOutputStream( std::cout );
Config config( configFile); Config config( configFile);
Ref<DarkIce> di = new DarkIce( config);
res = di->run(); darkice = new DarkIce( config);
signal(SIGUSR1, sigusr1Handler);
res = darkice->run();
} catch ( Exception & e ) { } catch ( Exception & e ) {
std::cout << "DarkIce: " << e << std::endl << std::flush; std::cout << "DarkIce: " << e << std::endl << std::flush;
@ -162,6 +182,16 @@ showUsage ( std::ostream & os )
} }
/*------------------------------------------------------------------------------
* Handle the SIGUSR1 signal here
*----------------------------------------------------------------------------*/
static void
sigusr1Handler(int value)
{
darkice->cut();
}
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
$Source$ $Source$