From 84cee897f7c9341e45788b6d44b5d4a52b86c54f Mon Sep 17 00:00:00 2001 From: darkeye Date: Thu, 28 Feb 2002 09:49:25 +0000 Subject: [PATCH] added possibility to save the encoded stream to a local file only (no streaming server needed) --- darkice/trunk/ChangeLog | 5 + darkice/trunk/configure.in | 2 +- darkice/trunk/man/darkice.cfg.5 | 74 ++++++++- darkice/trunk/src/CastSink.cpp | 21 ++- darkice/trunk/src/DarkIce.cpp | 126 ++++++++++++++- darkice/trunk/src/DarkIce.h | 24 ++- darkice/trunk/src/FileCast.cpp | 103 ++++++++++++ darkice/trunk/src/FileCast.h | 277 ++++++++++++++++++++++++++++++++ darkice/trunk/src/Makefile.am | 2 + 9 files changed, 612 insertions(+), 22 deletions(-) create mode 100644 darkice/trunk/src/FileCast.cpp create mode 100644 darkice/trunk/src/FileCast.h diff --git a/darkice/trunk/ChangeLog b/darkice/trunk/ChangeLog index c1f0b45..96b1ce3 100644 --- a/darkice/trunk/ChangeLog +++ b/darkice/trunk/ChangeLog @@ -1,3 +1,8 @@ +DarkIce 0.9 + + o added possibility to simply read from the soundcard, encode, and + save the encoded data into a local file (no streaming server needed) + 20-02-2002: DarkIce 0.8 released o added possibility to disable lowpass and highpass filtering for lame diff --git a/darkice/trunk/configure.in b/darkice/trunk/configure.in index 08afce5..e9f18d0 100644 --- a/darkice/trunk/configure.in +++ b/darkice/trunk/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(src/DarkIce.cpp) -AM_INIT_AUTOMAKE(darkice, 0.8) +AM_INIT_AUTOMAKE(darkice, 0.9beta) AM_CONFIG_HEADER(config.h) diff --git a/darkice/trunk/man/darkice.cfg.5 b/darkice/trunk/man/darkice.cfg.5 index 32503f0..4288f9a 100644 --- a/darkice/trunk/man/darkice.cfg.5 +++ b/darkice/trunk/man/darkice.cfg.5 @@ -1,4 +1,4 @@ -.TH darkice.cfg 5 "February 20, 2002" "DarkIce" "DarkIce live audio streamer" +.TH darkice.cfg 5 "February 28, 2002" "DarkIce" "DarkIce live audio streamer" .SH NAME darkice.cfg \- configuration file for darkice .SH DESCRIPTION @@ -27,11 +27,12 @@ configuration file contains the following sections: [icecast-0] ... [icecast-7] [icecast2-0] ... [icecast2-7] [shoutcast-0] ... [shoutcast-7] +[file-0] ... [file-7] .fi The order of the sections is not important. Sections [general] and [input] -are required, and at least one of [icecast-x], [icecast2-x] -or [shoutcast-x] is needed. +are required, and at least one of [icecast-x], [icecast2-x], [shoutcast-x] +or [file-x] is needed. In particular, the following sections and values are recognized: .PP @@ -154,8 +155,7 @@ disabled. This section describes an output to an .B IceCast2 -server, while encoding -with the ogg vobis encoder. +server, while encoding with the ogg vobis encoder. There may be at most 8 outputs, numbered from 0 ... 7. The number is included in the section name (e.g. [icecast2-0] ... [icecast2-7]). The stream will be reachable at @@ -287,6 +287,47 @@ Dump the same mp3 data sent to the .B ShoutCast server to this local file. +.PP +.B [file-x] + +This section describes an output to a local file in either Ogg Vorbis or +mp3 format. +There may be at most 8 outputs, numbered from 0 ... 7. +The number is included in the section name (e.g. [file-0] ... [file-7]). + +Required values: + +.TP +.I format +Format to encode in. Must be either 'mp3' or 'vorbis'. +.TP +.I bitrate +Bit rate to encode to in kBits / sec (e.g. 96) +.TP +.I fileName +The name of the local file to save the encoded data into. + +.PP +Optional values: + +.TP +.I sampleRate +The sample rate of the encoded mp3 output. If not specified, defaults +to the value of the input sample rate. +Only used if the output format is mp3. +.TP +.I lowpass +Lowpass filter setting for the lame encoder. If not set or set to 0, +the encoder's default behaviour is used. If set to -1, the filter is +disabled. +Only used if the output format is mp3. +.TP +.I highpass +Highpass filter setting for the lame encoder. If not set or set to 0, +the encoder's default behaviour is used. If set to -1, the filter is +disabled. +Only used if the output format is mp3. + .PP A sample configuration file follows. This file makes .B DarkIce @@ -336,6 +377,29 @@ localDumpFile = /tmp/encoder-dump.mp3 .fi +.PP +The following sample configuration file simply encodes the 16 bit stereo +44.1 kHz sound card input into Ogg Vorbis at 96 kb/s for 60 seconds, and saves +it in the local file at /tmp/save.ogg. + +.nf +[general] +duration = 60 +bufferSecs = 5 + +[input] +device = /dev/dsp +sampleRate = 44100 +bitsPerSample = 16 +channel = 2 + +[file-0] +format = vorbis +bitrate = 96 +fileName = /tmp/save.ogg +.fi + + .PP A bit more complicated sample follows. This one makes .B DarkIce diff --git a/darkice/trunk/src/CastSink.cpp b/darkice/trunk/src/CastSink.cpp index 8e10897..18ff083 100644 --- a/darkice/trunk/src/CastSink.cpp +++ b/darkice/trunk/src/CastSink.cpp @@ -67,16 +67,17 @@ CastSink :: init ( TcpSocket * socket, { this->socket = socket; this->streamDump = streamDump; - this->password = Util::strDup( password); + this->password = password ? Util::strDup( password) : 0; this->bitRate = bitRate; - this->name = name ? Util::strDup( name) : 0; - this->url = url ? Util::strDup( url) : 0; - this->genre = genre ? Util::strDup( genre) : 0; + this->name = name ? Util::strDup( name) : 0; + this->url = url ? Util::strDup( url) : 0; + this->genre = genre ? Util::strDup( genre) : 0; this->isPublic = isPublic; this->bufferDuration = bufferDuration; - bufferedSink = new BufferedSink( socket, - (bitRate * 1024 / 8) * bufferDuration); + bufferedSink = socket ? new BufferedSink( socket, + (bitRate * 1024 / 8) * bufferDuration) + : 0; } @@ -91,7 +92,9 @@ CastSink :: strip ( void ) throw ( Exception ) close(); } - delete[] password; + if ( password ) { + delete[] password; + } if ( name ) { delete[] name; } @@ -141,6 +144,10 @@ CastSink :: open ( void ) throw ( Exception ) $Source$ $Log$ + Revision 1.7 2002/02/28 09:49:25 darkeye + added possibility to save the encoded stream to a local file only + (no streaming server needed) + Revision 1.6 2002/02/20 11:54:11 darkeye added local dump file possibility diff --git a/darkice/trunk/src/DarkIce.cpp b/darkice/trunk/src/DarkIce.cpp index 0f7de51..2d487ef 100644 --- a/darkice/trunk/src/DarkIce.cpp +++ b/darkice/trunk/src/DarkIce.cpp @@ -76,7 +76,7 @@ #include "IceCast.h" #include "IceCast2.h" #include "ShoutCast.h" -#include "FileSink.h" +#include "FileCast.h" #include "DarkIce.h" #ifdef HAVE_LAME_LIB @@ -163,6 +163,7 @@ DarkIce :: init ( const Config & config ) throw ( Exception ) configIceCast( config, bufferSecs); configIceCast2( config, bufferSecs); configShoutCast( config, bufferSecs); + configFileCast( config); } @@ -180,11 +181,11 @@ DarkIce :: configIceCast ( const Config & config, size_t streamLen = Util::strLen( stream); unsigned int u; - for ( u = 0; u < maxOutput; ++u ) { + for ( u = noAudioOuts; u < maxOutput; ++u ) { const ConfigSection * cs; // ugly hack to change the section name to "stream0", "stream1", etc. - stream[streamLen-1] = '0' + u; + stream[streamLen-1] = '0' + (u - noAudioOuts); if ( !(cs = config.get( stream)) ) { break; @@ -305,11 +306,11 @@ DarkIce :: configIceCast2 ( const Config & config, size_t streamLen = Util::strLen( stream); unsigned int u; - for ( u = 0; u < maxOutput; ++u ) { + for ( u = noAudioOuts; u < maxOutput; ++u ) { const ConfigSection * cs; // ugly hack to change the section name to "stream0", "stream1", etc. - stream[streamLen-1] = '0' + u; + stream[streamLen-1] = '0' + (u - noAudioOuts); if ( !(cs = config.get( stream)) ) { break; @@ -456,11 +457,11 @@ DarkIce :: configShoutCast ( const Config & config, size_t streamLen = Util::strLen( stream); unsigned int u; - for ( u = 0; u < maxOutput; ++u ) { + for ( u = noAudioOuts; u < maxOutput; ++u ) { const ConfigSection * cs; // ugly hack to change the section name to "stream0", "stream1", etc. - stream[streamLen-1] = '0' + u; + stream[streamLen-1] = '0' + (u - noAudioOuts); if ( !(cs = config.get( stream)) ) { break; @@ -565,6 +566,113 @@ DarkIce :: configShoutCast ( const Config & config, } +/*------------------------------------------------------------------------------ + * Look for the FileCast stream outputs in the config file + *----------------------------------------------------------------------------*/ +void +DarkIce :: configFileCast ( const Config & config ) + throw ( Exception ) +{ + // look for FileCast encoder output streams, + // sections [file-0], [file-1], ... + char stream[] = "file- "; + size_t streamLen = Util::strLen( stream); + unsigned int u; + + for ( u = noAudioOuts; u < maxOutput; ++u ) { + const ConfigSection * cs; + + // ugly hack to change the section name to "stream0", "stream1", etc. + stream[streamLen-1] = '0' + (u - noAudioOuts); + + if ( !(cs = config.get( stream)) ) { + break; + } + + const char * str; + + const char * format = 0; + unsigned int bitrate = 0; + const char * targetFileName = 0; + unsigned int sampleRate = 0; + int lowpass = 0; + int highpass = 0; + + format = cs->getForSure( "format", " missing in section ", stream); + if ( !Util::strEq( format, "vorbis") && !Util::strEq( format, "mp3") ) { + throw Exception( __FILE__, __LINE__, + "unsupported stream format: ", format); + } + + str = cs->getForSure("bitrate", " missing in section ", stream); + bitrate = Util::strToL( str); + targetFileName = cs->getForSure( "fileName", + " missing in section ", + stream); + str = cs->get( "sampleRate"); + sampleRate = str ? Util::strToL( str) : dsp->getSampleRate(); + str = cs->get( "lowpass"); + lowpass = str ? Util::strToL( str) : 0; + str = cs->get( "highpass"); + highpass = str ? Util::strToL( str) : 0; + + // go on and create the things + + // the underlying file + FileSink * targetFile = new FileSink( targetFileName); + if ( !targetFile->exists() ) { + if ( !targetFile->create() ) { + throw Exception( __FILE__, __LINE__, + "can't create output file", targetFileName); + } + } + + // streaming related stuff + audioOuts[u].socket = 0; + audioOuts[u].server = new FileCast( targetFile ); + + if ( Util::strEq( format, "mp3") ) { +#ifndef HAVE_LAME_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with lame support, " + "thus can't create mp3 stream: ", + stream); +#else + audioOuts[u].encoder = new LameLibEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrate, + sampleRate, + dsp->getChannel(), + lowpass, + highpass ); +#endif // HAVE_LAME_LIB + } else if ( Util::strEq( format, "vorbis") ) { +#ifndef HAVE_VORBIS_LIB + throw Exception( __FILE__, __LINE__, + "DarkIce not compiled with Ogg Vorbis support, " + "thus can't Ogg Vorbis stream: ", + stream); +#else + audioOuts[u].encoder = new VorbisLibEncoder( + audioOuts[u].server.get(), + dsp.get(), + bitrate, + dsp->getSampleRate(), + dsp->getChannel() ); +#endif // HAVE_VORBIS_LIB + } else { + throw Exception( __FILE__, __LINE__, + "Illegal stream format: ", format); + } + + encConnector->attach( audioOuts[u].encoder.get()); + } + + noAudioOuts += u; +} + + /*------------------------------------------------------------------------------ * Set POSIX real-time scheduling, if super-user *----------------------------------------------------------------------------*/ @@ -697,6 +805,10 @@ DarkIce :: run ( void ) throw ( Exception ) $Source$ $Log$ + Revision 1.25 2002/02/28 09:49:25 darkeye + added possibility to save the encoded stream to a local file only + (no streaming server needed) + Revision 1.24 2002/02/20 11:54:11 darkeye added local dump file possibility diff --git a/darkice/trunk/src/DarkIce.h b/darkice/trunk/src/DarkIce.h index 39c841f..5fa47f3 100644 --- a/darkice/trunk/src/DarkIce.h +++ b/darkice/trunk/src/DarkIce.h @@ -80,9 +80,10 @@ class DarkIce : public virtual Referable, public virtual Reporter private: /** - * The maximum number of supported outputs. + * The maximum number of supported outputs. This should be + * * */ - static const unsigned int maxOutput = 24; + static const unsigned int maxOutput = 4 * 7; /** * Type describing each lame library output. @@ -144,6 +145,7 @@ class DarkIce : public virtual Referable, public virtual Reporter * * @param config the config Object to read initialization * information from. + * @param bufferSecs number of seconds to buffer audio for * @exception Exception */ void @@ -156,6 +158,7 @@ class DarkIce : public virtual Referable, public virtual Reporter * * @param config the config Object to read initialization * information from. + * @param bufferSecs number of seconds to buffer audio for * @exception Exception */ void @@ -168,12 +171,25 @@ class DarkIce : public virtual Referable, public virtual Reporter * * @param config the config Object to read initialization * information from. + * @param bufferSecs number of seconds to buffer audio for * @exception Exception */ void configShoutCast ( const Config & config, unsigned int bufferSecs ) throw ( Exception ); + /** + * Look for file outputs from the config file. + * Called from init() + * + * @param config the config Object to read initialization + * information from. + * @exception Exception + */ + void + configFileCast ( const Config & config ) + throw ( Exception ); + /** * Set POSIX real-time scheduling for the encoding process, * if user permissions enable it. @@ -293,6 +309,10 @@ class DarkIce : public virtual Referable, public virtual Reporter $Source$ $Log$ + Revision 1.13 2002/02/28 09:49:25 darkeye + added possibility to save the encoded stream to a local file only + (no streaming server needed) + Revision 1.12 2001/09/14 19:31:06 darkeye added IceCast2 / vorbis support diff --git a/darkice/trunk/src/FileCast.cpp b/darkice/trunk/src/FileCast.cpp new file mode 100644 index 0000000..1ce1684 --- /dev/null +++ b/darkice/trunk/src/FileCast.cpp @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2000 Tyrell Corporation. All rights reserved. + + Tyrell DarkIce + + File : FileCast.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 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STDIO_H +#include +#else +#error need stdio.h +#endif + +#ifdef HAVE_STRING_H +#include +#else +#error need string.h +#endif + + +#include "Exception.h" +#include "Source.h" +#include "Sink.h" +#include "Util.h" +#include "FileCast.h" + + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +/*------------------------------------------------------------------------------ + * File identity + *----------------------------------------------------------------------------*/ +static const char fileid[] = "$Id$"; + + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Open the connection + *----------------------------------------------------------------------------*/ +bool +FileCast :: open ( void ) throw ( Exception ) +{ + if ( isOpen() ) { + return false; + } + + if ( !targetFile->open() ) { + return false; + } + + return true; +} + + + +/*------------------------------------------------------------------------------ + + $Source$ + + $Log$ + Revision 1.1 2002/02/28 09:49:25 darkeye + added possibility to save the encoded stream to a local file only + (no streaming server needed) + + + +------------------------------------------------------------------------------*/ + diff --git a/darkice/trunk/src/FileCast.h b/darkice/trunk/src/FileCast.h new file mode 100644 index 0000000..c61afbf --- /dev/null +++ b/darkice/trunk/src/FileCast.h @@ -0,0 +1,277 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2000 Tyrell Corporation. All rights reserved. + + Tyrell DarkIce + + File : FileCast.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 FILE_CAST_H +#define FILE_CAST_H + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#include "Ref.h" +#include "Sink.h" +#include "CastSink.h" +#include "FileSink.h" +#include "FileCast.h" + + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * Class representing output to a local file. + * + * @author $Author$ + * @version $Revision$ + */ +class FileCast : public CastSink +{ + private: + + /** + * The file to send the encoded data to. + */ + Ref targetFile; + + /** + * Initalize the object. + * + * @param targetFile the file to send the encoded data to. + * @exception Exception + */ + inline void + init ( FileSink * targetFile ) + throw ( Exception ) + { + this->targetFile = targetFile; + } + + /** + * De-initalize the object. + * + * @exception Exception + */ + inline void + strip ( void ) throw ( Exception ) + { + if ( isOpen() ) { + close(); + } + } + + + protected: + + /** + * Default constructor. Always throws an Exception. + * + * @exception Exception + */ + inline + FileCast ( void ) throw ( Exception ) + { + throw Exception( __FILE__, __LINE__); + } + + /** + * Log in to the server using the socket avialable. + * No need to log in to a file. + * + * @return true if login was successful, false otherwise. + * @exception Exception + */ + inline virtual bool + sendLogin ( void ) throw ( Exception ) + { + return true; + } + + + public: + + /** + * Constructor. + * + * @param targetFile the file to send all the data to. + * @exception Exception + */ + inline + FileCast ( FileSink * targetFile ) + throw ( Exception ) + : CastSink( 0, 0, 0) + { + init( targetFile ); + } + + /** + * Copy constructor. + * + * @param cs the FileCast to copy. + */ + inline + FileCast( const FileCast & cs ) throw ( Exception ) + { + init( targetFile.get() ); + } + + /** + * Destructor. + * + * @exception Exception + */ + inline virtual + ~FileCast( void ) throw ( Exception ) + { + strip(); + } + + /** + * Assignment operator. + * + * @param cs the FileCast to assign this to. + * @return a reference to this FileCast. + * @exception Exception + */ + inline virtual FileCast & + operator= ( const FileCast & cs ) throw ( Exception ) + { + if ( this != &cs ) { + strip(); + init( targetFile.get() ); + } + return *this; + } + + /** + * Open the FileCast. + * + * @return true if opening was successfull, false otherwise. + * @exception Exception + */ + virtual bool + open ( void ) throw ( Exception ); + + /** + * Check if the FileCast is open. + * + * @return true if the FileCast is open, false otherwise. + */ + inline virtual bool + isOpen ( void ) const throw () + { + return targetFile->isOpen(); + } + + /** + * Check if the FileCast is ready to accept data. + * Blocks until the specified time for data to be available. + * + * @param sec the maximum seconds to block. + * @param usec micro seconds to block after the full seconds. + * @return true if the FileCast is ready to accept data, + * false otherwise. + * @exception Exception + */ + inline virtual bool + canWrite ( unsigned int sec, + unsigned int usec ) throw ( Exception ) + { + return targetFile->canWrite( sec, usec); + } + + /** + * Write data to the FileCast. + * + * @param buf the data to write. + * @param len number of bytes to write from buf. + * @return the number of bytes written (may be less than len). + * @exception Exception + */ + inline virtual unsigned int + write ( const void * buf, + unsigned int len ) throw ( Exception ) + { + return targetFile->write( buf, len); + } + + /** + * Flush all data that was written to the FileCast to the server. + * + * @exception Exception + */ + inline virtual void + flush ( void ) throw ( Exception ) + { + return targetFile->flush(); + } + + /** + * Close the FileCast. + * + * @exception Exception + */ + inline virtual void + close ( void ) throw ( Exception ) + { + return targetFile->close(); + } + +}; + + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + + +#endif /* FILE_CAST_H */ + + +/*------------------------------------------------------------------------------ + + $Source$ + + $Log$ + Revision 1.1 2002/02/28 09:49:25 darkeye + added possibility to save the encoded stream to a local file only + (no streaming server needed) + + + +------------------------------------------------------------------------------*/ + diff --git a/darkice/trunk/src/Makefile.am b/darkice/trunk/src/Makefile.am index de93b4c..ca7ea67 100644 --- a/darkice/trunk/src/Makefile.am +++ b/darkice/trunk/src/Makefile.am @@ -23,6 +23,8 @@ darkice_SOURCES = AudioEncoder.h\ IceCast2.h\ ShoutCast.cpp\ ShoutCast.h\ + FileCast.h\ + FileCast.cpp\ LameLibEncoder.cpp\ LameLibEncoder.h\ VorbisLibEncoder.cpp\