Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

DarkIce.cpp

Go to the documentation of this file.
00001 /*------------------------------------------------------------------------------
00002 
00003    Copyright (c) 2000 Tyrell Corporation. All rights reserved.
00004 
00005    Tyrell DarkIce
00006 
00007    File     : DarkIce.cpp
00008    Version  : $Revision: 1.43 $
00009    Author   : $Author: darkeye $
00010    Location : $Source: /cvsroot/darkice/darkice/src/DarkIce.cpp,v $
00011    
00012 
00013    Copyright notice:
00014 
00015     This program is free software; you can redistribute it and/or
00016     modify it under the terms of the GNU General Public License  
00017     as published by the Free Software Foundation; either version 2
00018     of the License, or (at your option) any later version.
00019    
00020     This program is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of 
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
00023     GNU General Public License for more details.
00024    
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00028 
00029 ------------------------------------------------------------------------------*/
00030 
00031 /* ============================================================ include files */
00032 
00033 #ifdef HAVE_CONFIG_H
00034 #include "config.h"
00035 #endif
00036 
00037 #ifdef HAVE_STDLIB_H
00038 #include <stdlib.h>
00039 #else
00040 #error need stdlib.h
00041 #endif
00042 
00043 #ifdef HAVE_UNISTD_H
00044 #include <unistd.h>
00045 #else
00046 #error need unistd.h
00047 #endif
00048 
00049 #ifdef HAVE_SYS_TYPES_H
00050 #include <sys/types.h>
00051 #else
00052 #error need sys/types.h
00053 #endif
00054 
00055 #ifdef HAVE_SYS_WAIT_H
00056 #include <sys/wait.h>
00057 #else
00058 #error need sys/wait.h
00059 #endif
00060 
00061 #ifdef HAVE_ERRNO_H
00062 #include <errno.h>
00063 #else
00064 #error need errno.h
00065 #endif
00066 
00067 #ifdef HAVE_SCHED_H
00068 #include <sched.h>
00069 #else
00070 #error need sched.h
00071 #endif
00072 
00073 
00074 
00075 #include "Util.h"
00076 #include "IceCast.h"
00077 #include "IceCast2.h"
00078 #include "ShoutCast.h"
00079 #include "FileCast.h"
00080 #include "MultiThreadedConnector.h"
00081 #include "DarkIce.h"
00082 
00083 #ifdef HAVE_LAME_LIB
00084 #include "LameLibEncoder.h"
00085 #endif
00086 
00087 #ifdef HAVE_VORBIS_LIB
00088 #include "VorbisLibEncoder.h"
00089 #endif
00090 
00091 
00092 /* ===================================================  local data structures */
00093 
00094 
00095 /* ================================================  local constants & macros */
00096 
00097 /*------------------------------------------------------------------------------
00098  *  File identity
00099  *----------------------------------------------------------------------------*/
00100 static const char fileid[] = "$Id: DarkIce.cpp,v 1.43 2005/04/11 19:27:43 darkeye Exp $";
00101 
00102 
00103 /*------------------------------------------------------------------------------
00104  *  Make sure wait-related stuff is what we expect
00105  *----------------------------------------------------------------------------*/
00106 #ifndef WEXITSTATUS
00107 # define WEXITSTATUS(stat_val)      ((unsigned)(stat_val) >> 8)
00108 #endif
00109 #ifndef WIFEXITED
00110 # define WIFEXITED(stat_val)        (((stat_val) & 255) == 0)
00111 #endif
00112 
00113 
00114 
00115 /* ===============================================  local function prototypes */
00116 
00117 
00118 /* =============================================================  module code */
00119 
00120 /*------------------------------------------------------------------------------
00121  *  Initialize the object
00122  *----------------------------------------------------------------------------*/
00123 void
00124 DarkIce :: init ( const Config      & config )              throw ( Exception )
00125 {
00126     unsigned int             bufferSecs;
00127     const ConfigSection    * cs;
00128     const char             * str;
00129     unsigned int             sampleRate;
00130     unsigned int             bitsPerSample;
00131     unsigned int             channel;
00132     bool                     reconnect;
00133     const char             * device;
00134 
00135     // the [general] section
00136     if ( !(cs = config.get( "general")) ) {
00137         throw Exception( __FILE__, __LINE__, "no section [general] in config");
00138     }
00139     str = cs->getForSure( "duration", " missing in section [general]");
00140     duration = Util::strToL( str);
00141     str = cs->getForSure( "bufferSecs", " missing in section [general]");
00142     bufferSecs = Util::strToL( str);
00143     str           = cs->get( "reconnect");
00144     reconnect     = str ? (Util::strEq( str, "yes") ? true : false) : true;
00145 
00146 
00147     // the [input] section
00148     if ( !(cs = config.get( "input")) ) {
00149         throw Exception( __FILE__, __LINE__, "no section [general] in config");
00150     }
00151     
00152     str        = cs->getForSure( "sampleRate", " missing in section [input]");
00153     sampleRate = Util::strToL( str);
00154     str       = cs->getForSure( "bitsPerSample", " missing in section [input]");
00155     bitsPerSample = Util::strToL( str);
00156     str           = cs->getForSure( "channel", " missing in section [input]");
00157     channel       = Util::strToL( str);
00158     device        = cs->getForSure( "device", " missing in section [input]");
00159 
00160     dsp             = AudioSource::createDspSource( device,
00161                                                     sampleRate,
00162                                                     bitsPerSample,
00163                                                     channel );
00164     encConnector    = new MultiThreadedConnector( dsp.get(), reconnect );
00165 
00166     noAudioOuts = 0;
00167     configIceCast( config, bufferSecs);
00168     configIceCast2( config, bufferSecs);
00169     configShoutCast( config, bufferSecs);
00170     configFileCast( config);
00171 }
00172 
00173 
00174 /*------------------------------------------------------------------------------
00175  *  Look for the IceCast stream outputs in the config file
00176  *----------------------------------------------------------------------------*/
00177 void
00178 DarkIce :: configIceCast (  const Config      & config,
00179                             unsigned int        bufferSecs  )
00180                                                         throw ( Exception )
00181 {
00182     // look for IceCast encoder output streams,
00183     // sections [icecast-0], [icecast-1], ...
00184     char            stream[]        = "icecast- ";
00185     size_t          streamLen       = Util::strLen( stream);
00186     unsigned int    u;
00187 
00188     for ( u = noAudioOuts; u < maxOutput; ++u ) {
00189         const ConfigSection    * cs;
00190 
00191         // ugly hack to change the section name to "stream0", "stream1", etc.
00192         stream[streamLen-1] = '0' + (u - noAudioOuts);
00193 
00194         if ( !(cs = config.get( stream)) ) {
00195             break;
00196         }
00197 
00198 #ifndef HAVE_LAME_LIB
00199         throw Exception( __FILE__, __LINE__,
00200                          "DarkIce not compiled with lame support, "
00201                          "thus can't connect to IceCast 1.x, stream: ",
00202                          stream);
00203 #else
00204 
00205         const char                * str;
00206 
00207         unsigned int                sampleRate      = 0;
00208         unsigned int                channel         = 0;
00209         AudioEncoder::BitrateMode   bitrateMode;
00210         unsigned int                bitrate         = 0;
00211         double                      quality         = 0.0;
00212         const char                * server          = 0;
00213         unsigned int                port            = 0;
00214         const char                * password        = 0;
00215         const char                * mountPoint      = 0;
00216         const char                * remoteDumpFile  = 0;
00217         const char                * name            = 0;
00218         const char                * description     = 0;
00219         const char                * url             = 0;
00220         const char                * genre           = 0;
00221         bool                        isPublic        = false;
00222         int                         lowpass         = 0;
00223         int                         highpass        = 0;
00224         const char                * localDumpName   = 0;
00225         FileSink                  * localDumpFile   = 0;
00226         bool                        fileAddDate     = false;
00227 
00228         str         = cs->get( "sampleRate");
00229         sampleRate  = str ? Util::strToL( str) : dsp->getSampleRate();
00230         str         = cs->get( "channel");
00231         channel     = str ? Util::strToL( str) : dsp->getChannel();
00232 
00233         str         = cs->get( "bitrate");
00234         bitrate     = str ? Util::strToL( str) : 0;
00235         str         = cs->get( "quality");
00236         quality     = str ? Util::strToD( str) : 0.0;
00237         
00238         str         = cs->getForSure( "bitrateMode",
00239                                       " not specified in section ",
00240                                       stream);
00241         if ( Util::strEq( str, "cbr") ) {
00242             bitrateMode = AudioEncoder::cbr;
00243             
00244             if ( bitrate == 0 ) {
00245                 throw Exception( __FILE__, __LINE__,
00246                                  "bitrate not specified for CBR encoding");
00247             }
00248             if ( cs->get( "quality" ) == 0 ) {
00249                 throw Exception( __FILE__, __LINE__,
00250                                  "quality not specified for CBR encoding");
00251             }
00252         } else if ( Util::strEq( str, "abr") ) {
00253             bitrateMode = AudioEncoder::abr;
00254 
00255             if ( bitrate == 0 ) {
00256                 throw Exception( __FILE__, __LINE__,
00257                                  "bitrate not specified for ABR encoding");
00258             }
00259         } else if ( Util::strEq( str, "vbr") ) {
00260             bitrateMode = AudioEncoder::vbr;
00261 
00262             if ( cs->get( "quality" ) == 0 ) {
00263                 throw Exception( __FILE__, __LINE__,
00264                                  "quality not specified for VBR encoding");
00265             }
00266         } else {
00267             throw Exception( __FILE__, __LINE__,
00268                              "invalid bitrate mode: ", str);
00269         }
00270 
00271         server      = cs->getForSure( "server", " missing in section ", stream);
00272         str         = cs->getForSure( "port", " missing in section ", stream);
00273         port        = Util::strToL( str);
00274         password    = cs->getForSure("password"," missing in section ",stream);
00275         mountPoint  = cs->getForSure( "mountPoint",
00276                                       " missing in section ",
00277                                       stream);
00278         remoteDumpFile = cs->get( "remoteDumpFile");
00279         name        = cs->get( "name");
00280         description = cs->get("description");
00281         url         = cs->get( "url");
00282         genre       = cs->get( "genre");
00283         str         = cs->get( "public");
00284         isPublic    = str ? (Util::strEq( str, "yes") ? true : false) : false;
00285         str         = cs->get( "lowpass");
00286         lowpass     = str ? Util::strToL( str) : 0;
00287         str         = cs->get( "highpass");
00288         highpass    = str ? Util::strToL( str) : 0;
00289         str         = cs->get("fileAddDate");
00290         fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
00291 
00292         localDumpName = cs->get( "localDumpFile");
00293 
00294         // go on and create the things
00295 
00296         // check for and create the local dump file if needed
00297         if ( localDumpName != 0 ) {
00298             if ( fileAddDate ) {
00299                 localDumpName = Util::fileAddDate(localDumpName);
00300             }
00301 
00302             localDumpFile = new FileSink( localDumpName);
00303             if ( !localDumpFile->exists() ) {
00304                 if ( !localDumpFile->create() ) {
00305                     reportEvent( 1, "can't create local dump file",
00306                                     localDumpName);
00307                     localDumpFile = 0;
00308                 }
00309             }
00310             if ( fileAddDate ) {
00311                 delete[] localDumpFile;
00312             }
00313         }
00314         // streaming related stuff
00315         audioOuts[u].socket = new TcpSocket( server, port);
00316         audioOuts[u].server = new IceCast( audioOuts[u].socket.get(),
00317                                            password,
00318                                            mountPoint,
00319                                            bitrate,
00320                                            name,
00321                                            description,
00322                                            url,
00323                                            genre,
00324                                            isPublic,
00325                                            remoteDumpFile,
00326                                            localDumpFile,
00327                                            bufferSecs );
00328 
00329         audioOuts[u].encoder = new LameLibEncoder( audioOuts[u].server.get(),
00330                                                    dsp.get(),
00331                                                    bitrateMode,
00332                                                    bitrate,
00333                                                    quality,
00334                                                    sampleRate,
00335                                                    channel,
00336                                                    lowpass,
00337                                                    highpass );
00338 
00339         encConnector->attach( audioOuts[u].encoder.get());
00340 #endif // HAVE_LAME_LIB
00341     }
00342 
00343     noAudioOuts += u;
00344 }
00345 
00346 
00347 /*------------------------------------------------------------------------------
00348  *  Look for the IceCast2 stream outputs in the config file
00349  *----------------------------------------------------------------------------*/
00350 void
00351 DarkIce :: configIceCast2 (  const Config      & config,
00352                              unsigned int        bufferSecs  )
00353                                                         throw ( Exception )
00354 {
00355     // look for IceCast2 encoder output streams,
00356     // sections [icecast2-0], [icecast2-1], ...
00357     char            stream[]        = "icecast2- ";
00358     size_t          streamLen       = Util::strLen( stream);
00359     unsigned int    u;
00360 
00361     for ( u = noAudioOuts; u < maxOutput; ++u ) {
00362         const ConfigSection    * cs;
00363 
00364         // ugly hack to change the section name to "stream0", "stream1", etc.
00365         stream[streamLen-1] = '0' + (u - noAudioOuts);
00366 
00367         if ( !(cs = config.get( stream)) ) {
00368             break;
00369         }
00370 
00371         const char                * str;
00372 
00373         IceCast2::StreamFormat      format;
00374         unsigned int                sampleRate      = 0;
00375         unsigned int                channel         = 0;
00376         AudioEncoder::BitrateMode   bitrateMode;
00377         unsigned int                bitrate         = 0;
00378         unsigned int                maxBitrate      = 0;
00379         double                      quality         = 0.0;
00380         const char                * server          = 0;
00381         unsigned int                port            = 0;
00382         const char                * password        = 0;
00383         const char                * mountPoint      = 0;
00384         const char                * name            = 0;
00385         const char                * description     = 0;
00386         const char                * url             = 0;
00387         const char                * genre           = 0;
00388         bool                        isPublic        = false;
00389         const char                * localDumpName   = 0;
00390         FileSink                  * localDumpFile   = 0;
00391         bool                        fileAddDate     = false;
00392 
00393         str         = cs->getForSure( "format", " missing in section ", stream);
00394         if ( Util::strEq( str, "vorbis") ) {
00395             format = IceCast2::oggVorbis;
00396         } else if ( Util::strEq( str, "mp3") ) {
00397             format = IceCast2::mp3;
00398         } else {
00399             throw Exception( __FILE__, __LINE__,
00400                              "unsupported stream format: ", str);
00401         }
00402                 
00403         str         = cs->get( "sampleRate");
00404         sampleRate  = str ? Util::strToL( str) : dsp->getSampleRate();
00405         str         = cs->get( "channel");
00406         channel     = str ? Util::strToL( str) : dsp->getChannel();
00407 
00408         // determine fixed bitrate or variable bitrate quality
00409         str         = cs->get( "bitrate");
00410         bitrate     = str ? Util::strToL( str) : 0;
00411         str         = cs->get( "maxBitrate");
00412         maxBitrate  = str ? Util::strToL( str) : 0;
00413         str         = cs->get( "quality");
00414         quality     = str ? Util::strToD( str) : 0.0;
00415         
00416         str         = cs->getForSure( "bitrateMode",
00417                                       " not specified in section ",
00418                                       stream);
00419         if ( Util::strEq( str, "cbr") ) {
00420             bitrateMode = AudioEncoder::cbr;
00421             
00422             if ( bitrate == 0 ) {
00423                 throw Exception( __FILE__, __LINE__,
00424                                  "bitrate not specified for CBR encoding");
00425             }
00426         } else if ( Util::strEq( str, "abr") ) {
00427             bitrateMode = AudioEncoder::abr;
00428 
00429             if ( bitrate == 0 ) {
00430                 throw Exception( __FILE__, __LINE__,
00431                                  "bitrate not specified for ABR encoding");
00432             }
00433         } else if ( Util::strEq( str, "vbr") ) {
00434             bitrateMode = AudioEncoder::vbr;
00435 
00436             if ( cs->get( "quality" ) == 0 ) {
00437                 throw Exception( __FILE__, __LINE__,
00438                                  "quality not specified for VBR encoding");
00439             }
00440         } else {
00441             throw Exception( __FILE__, __LINE__,
00442                              "invalid bitrate mode: ", str);
00443         }
00444 
00445         server      = cs->getForSure( "server", " missing in section ", stream);
00446         str         = cs->getForSure( "port", " missing in section ", stream);
00447         port        = Util::strToL( str);
00448         password    = cs->getForSure("password"," missing in section ",stream);
00449         mountPoint  = cs->getForSure( "mountPoint",
00450                                       " missing in section ",
00451                                       stream);
00452         name        = cs->get( "name");
00453         description = cs->get( "description");
00454         url         = cs->get( "url");
00455         genre       = cs->get( "genre");
00456         str         = cs->get( "public");
00457         isPublic    = str ? (Util::strEq( str, "yes") ? true : false) : false;
00458         str         = cs->get( "fileAddDate");
00459         fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
00460         
00461         localDumpName = cs->get( "localDumpFile");
00462 
00463         // go on and create the things
00464 
00465         // check for and create the local dump file if needed
00466         if ( localDumpName != 0 ) {
00467             if ( fileAddDate ) {
00468                 localDumpName = Util::fileAddDate(localDumpName);
00469             }
00470 
00471             localDumpFile = new FileSink( localDumpName);
00472             if ( !localDumpFile->exists() ) {
00473                 if ( !localDumpFile->create() ) {
00474                     reportEvent( 1, "can't create local dump file",
00475                                     localDumpName);
00476                     localDumpFile = 0;
00477                 }
00478             }
00479             if ( fileAddDate ) {
00480                 delete[] localDumpName;
00481             }
00482         }
00483 
00484         // streaming related stuff
00485         audioOuts[u].socket = new TcpSocket( server, port);
00486         audioOuts[u].server = new IceCast2( audioOuts[u].socket.get(),
00487                                             password,
00488                                             mountPoint,
00489                                             format,
00490                                             bitrate,
00491                                             name,
00492                                             description,
00493                                             url,
00494                                             genre,
00495                                             isPublic,
00496                                             localDumpFile,
00497                                             bufferSecs );
00498 
00499         switch ( format ) {
00500             case IceCast2::mp3:
00501 #ifndef HAVE_LAME_LIB
00502                 throw Exception( __FILE__, __LINE__,
00503                                  "DarkIce not compiled with lame support, "
00504                                  "thus can't create mp3 stream: ",
00505                                  stream);
00506 #else
00507                 audioOuts[u].encoder = new LameLibEncoder(
00508                                                     audioOuts[u].server.get(),
00509                                                     dsp.get(),
00510                                                     bitrateMode,
00511                                                     bitrate,
00512                                                     quality,
00513                                                     sampleRate,
00514                                                     channel );
00515 #endif // HAVE_LAME_LIB
00516                 break;
00517 
00518             case IceCast2::oggVorbis:
00519 #ifndef HAVE_VORBIS_LIB
00520                 throw Exception( __FILE__, __LINE__,
00521                                 "DarkIce not compiled with Ogg Vorbis support, "
00522                                 "thus can't Ogg Vorbis stream: ",
00523                                 stream);
00524 #else
00525                 audioOuts[u].encoder = new VorbisLibEncoder(
00526                                                 audioOuts[u].server.get(),
00527                                                 dsp.get(),
00528                                                 bitrateMode,
00529                                                 bitrate,
00530                                                 quality,
00531                                                 sampleRate,
00532                                                 dsp->getChannel(),
00533                                                 maxBitrate);
00534 #endif // HAVE_VORBIS_LIB
00535                 break;
00536 
00537             default:
00538                 throw Exception( __FILE__, __LINE__,
00539                                 "Illegal stream format: ", format);
00540         }
00541 
00542         encConnector->attach( audioOuts[u].encoder.get());
00543     }
00544 
00545     noAudioOuts += u;
00546 }
00547 
00548 
00549 /*------------------------------------------------------------------------------
00550  *  Look for the ShoutCast stream outputs in the config file
00551  *----------------------------------------------------------------------------*/
00552 void
00553 DarkIce :: configShoutCast (    const Config      & config,
00554                                 unsigned int        bufferSecs  )
00555                                                         throw ( Exception )
00556 {
00557     // look for Shoutcast encoder output streams,
00558     // sections [shoutcast-0], [shoutcast-1], ...
00559     char            stream[]        = "shoutcast- ";
00560     size_t          streamLen       = Util::strLen( stream);
00561     unsigned int    u;
00562 
00563     for ( u = noAudioOuts; u < maxOutput; ++u ) {
00564         const ConfigSection    * cs;
00565 
00566         // ugly hack to change the section name to "stream0", "stream1", etc.
00567         stream[streamLen-1] = '0' + (u - noAudioOuts);
00568 
00569         if ( !(cs = config.get( stream)) ) {
00570             break;
00571         }
00572 
00573 #ifndef HAVE_LAME_LIB
00574         throw Exception( __FILE__, __LINE__,
00575                          "DarkIce not compiled with lame support, "
00576                          "thus can't connect to ShoutCast, stream: ",
00577                          stream);
00578 #else
00579 
00580         const char                * str;
00581 
00582         unsigned int                sampleRate      = 0;
00583         unsigned int                channel         = 0;
00584         AudioEncoder::BitrateMode   bitrateMode;
00585         unsigned int                bitrate         = 0;
00586         double                      quality         = 0.0;
00587         const char                * server          = 0;
00588         unsigned int                port            = 0;
00589         const char                * password        = 0;
00590         const char                * name            = 0;
00591         const char                * url             = 0;
00592         const char                * genre           = 0;
00593         bool                        isPublic        = false;
00594         int                         lowpass         = 0;
00595         int                         highpass        = 0;
00596         const char                * irc             = 0;
00597         const char                * aim             = 0;
00598         const char                * icq             = 0;
00599         const char                * localDumpName   = 0;
00600         FileSink                  * localDumpFile   = 0;
00601         bool                        fileAddDate     = false;
00602 
00603         str         = cs->get( "sampleRate");
00604         sampleRate  = str ? Util::strToL( str) : dsp->getSampleRate();
00605         str         = cs->get( "channel");
00606         channel     = str ? Util::strToL( str) : dsp->getChannel();
00607 
00608         str         = cs->get( "bitrate");
00609         bitrate     = str ? Util::strToL( str) : 0;
00610         str         = cs->get( "quality");
00611         quality     = str ? Util::strToD( str) : 0.0;
00612         
00613         str         = cs->getForSure( "bitrateMode",
00614                                       " not specified in section ",
00615                                       stream);
00616         if ( Util::strEq( str, "cbr") ) {
00617             bitrateMode = AudioEncoder::cbr;
00618             
00619             if ( bitrate == 0 ) {
00620                 throw Exception( __FILE__, __LINE__,
00621                                  "bitrate not specified for CBR encoding");
00622             }
00623             if ( cs->get( "quality" ) == 0 ) {
00624                 throw Exception( __FILE__, __LINE__,
00625                                  "quality not specified for CBR encoding");
00626             }
00627         } else if ( Util::strEq( str, "abr") ) {
00628             bitrateMode = AudioEncoder::abr;
00629 
00630             if ( bitrate == 0 ) {
00631                 throw Exception( __FILE__, __LINE__,
00632                                  "bitrate not specified for ABR encoding");
00633             }
00634         } else if ( Util::strEq( str, "vbr") ) {
00635             bitrateMode = AudioEncoder::vbr;
00636 
00637             if ( cs->get( "quality" ) == 0 ) {
00638                 throw Exception( __FILE__, __LINE__,
00639                                  "quality not specified for VBR encoding");
00640             }
00641         } else {
00642             throw Exception( __FILE__, __LINE__,
00643                              "invalid bitrate mode: ", str);
00644         }
00645 
00646         server      = cs->getForSure( "server", " missing in section ", stream);
00647         str         = cs->getForSure( "port", " missing in section ", stream);
00648         port        = Util::strToL( str);
00649         password    = cs->getForSure("password"," missing in section ",stream);
00650         name        = cs->get( "name");
00651         url         = cs->get( "url");
00652         genre       = cs->get( "genre");
00653         str         = cs->get( "public");
00654         isPublic    = str ? (Util::strEq( str, "yes") ? true : false) : false;
00655         str         = cs->get( "lowpass");
00656         lowpass     = str ? Util::strToL( str) : 0;
00657         str         = cs->get( "highpass");
00658         highpass    = str ? Util::strToL( str) : 0;
00659         irc         = cs->get( "irc");
00660         aim         = cs->get( "aim");
00661         icq         = cs->get( "icq");
00662         str         = cs->get("fileAddDate");
00663         fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
00664 
00665         localDumpName = cs->get( "localDumpFile");
00666 
00667         // go on and create the things
00668 
00669         // check for and create the local dump file if needed
00670         if ( localDumpName != 0 ) {
00671             if ( fileAddDate ) {
00672                 localDumpName = Util::fileAddDate(localDumpName);
00673             }
00674 
00675             localDumpFile = new FileSink( localDumpName);
00676             if ( !localDumpFile->exists() ) {
00677                 if ( !localDumpFile->create() ) {
00678                     reportEvent( 1, "can't create local dump file",
00679                                     localDumpName);
00680                     localDumpFile = 0;
00681                 }
00682             }
00683             if ( fileAddDate ) {
00684                 delete[] localDumpFile;
00685             }
00686         }
00687 
00688         // streaming related stuff
00689         audioOuts[u].socket = new TcpSocket( server, port);
00690         audioOuts[u].server = new ShoutCast( audioOuts[u].socket.get(),
00691                                              password,
00692                                              bitrate,
00693                                              name,
00694                                              url,
00695                                              genre,
00696                                              isPublic,
00697                                              irc,
00698                                              aim,
00699                                              icq,
00700                                              localDumpFile,
00701                                              bufferSecs );
00702 
00703         audioOuts[u].encoder = new LameLibEncoder( audioOuts[u].server.get(),
00704                                                    dsp.get(),
00705                                                    bitrateMode,
00706                                                    bitrate,
00707                                                    quality,
00708                                                    sampleRate,
00709                                                    channel,
00710                                                    lowpass,
00711                                                    highpass );
00712 
00713         encConnector->attach( audioOuts[u].encoder.get());
00714 #endif // HAVE_LAME_LIB
00715     }
00716 
00717     noAudioOuts += u;
00718 }
00719 
00720 
00721 /*------------------------------------------------------------------------------
00722  *  Look for the FileCast stream outputs in the config file
00723  *----------------------------------------------------------------------------*/
00724 void
00725 DarkIce :: configFileCast (  const Config      & config )
00726                                                         throw ( Exception )
00727 {
00728     // look for FileCast encoder output streams,
00729     // sections [file-0], [file-1], ...
00730     char            stream[]        = "file- ";
00731     size_t          streamLen       = Util::strLen( stream);
00732     unsigned int    u;
00733 
00734     for ( u = noAudioOuts; u < maxOutput; ++u ) {
00735         const ConfigSection    * cs;
00736 
00737         // ugly hack to change the section name to "stream0", "stream1", etc.
00738         stream[streamLen-1] = '0' + (u - noAudioOuts);
00739 
00740         if ( !(cs = config.get( stream)) ) {
00741             break;
00742         }
00743 
00744         const char                * str;
00745 
00746         const char                * format          = 0;
00747         AudioEncoder::BitrateMode   bitrateMode;
00748         unsigned int                bitrate         = 0;
00749         double                      quality         = 0.0;
00750         const char                * targetFileName  = 0;
00751         unsigned int                sampleRate      = 0;
00752         int                         lowpass         = 0;
00753         int                         highpass        = 0;
00754 
00755         format      = cs->getForSure( "format", " missing in section ", stream);
00756         if ( !Util::strEq( format, "vorbis") && !Util::strEq( format, "mp3") ) {
00757             throw Exception( __FILE__, __LINE__,
00758                              "unsupported stream format: ", format);
00759         }
00760 
00761         str         = cs->getForSure("bitrate", " missing in section ", stream);
00762         bitrate     = Util::strToL( str);
00763         targetFileName    = cs->getForSure( "fileName",
00764                                             " missing in section ",
00765                                             stream);
00766         str         = cs->get( "sampleRate");
00767         sampleRate  = str ? Util::strToL( str) : dsp->getSampleRate();
00768 
00769         str         = cs->get( "bitrate");
00770         bitrate     = str ? Util::strToL( str) : 0;
00771         str         = cs->get( "quality");
00772         quality     = str ? Util::strToD( str) : 0.0;
00773         
00774         str         = cs->getForSure( "bitrateMode",
00775                                       " not specified in section ",
00776                                       stream);
00777         if ( Util::strEq( str, "cbr") ) {
00778             bitrateMode = AudioEncoder::cbr;
00779             
00780             if ( bitrate == 0 ) {
00781                 throw Exception( __FILE__, __LINE__,
00782                                  "bitrate not specified for CBR encoding");
00783             }
00784             if ( cs->get( "quality" ) == 0 ) {
00785                 throw Exception( __FILE__, __LINE__,
00786                                  "quality not specified for CBR encoding");
00787             }
00788         } else if ( Util::strEq( str, "abr") ) {
00789             bitrateMode = AudioEncoder::abr;
00790 
00791             if ( bitrate == 0 ) {
00792                 throw Exception( __FILE__, __LINE__,
00793                                  "bitrate not specified for ABR encoding");
00794             }
00795         } else if ( Util::strEq( str, "vbr") ) {
00796             bitrateMode = AudioEncoder::vbr;
00797 
00798             if ( cs->get( "quality" ) == 0 ) {
00799                 throw Exception( __FILE__, __LINE__,
00800                                  "quality not specified for VBR encoding");
00801             }
00802         } else {
00803             throw Exception( __FILE__, __LINE__,
00804                              "invalid bitrate mode: ", str);
00805         }
00806 
00807         str         = cs->get( "lowpass");
00808         lowpass     = str ? Util::strToL( str) : 0;
00809         str         = cs->get( "highpass");
00810         highpass    = str ? Util::strToL( str) : 0;
00811 
00812         // go on and create the things
00813 
00814         // the underlying file
00815         FileSink  * targetFile = new FileSink( targetFileName);
00816         if ( !targetFile->exists() ) {
00817             if ( !targetFile->create() ) {
00818                 throw Exception( __FILE__, __LINE__,
00819                                  "can't create output file", targetFileName);
00820             }
00821         }
00822 
00823         // streaming related stuff
00824         audioOuts[u].socket = 0;
00825         audioOuts[u].server = new FileCast( targetFile );
00826 
00827         if ( Util::strEq( format, "mp3") ) {
00828 #ifndef HAVE_LAME_LIB
00829                 throw Exception( __FILE__, __LINE__,
00830                                  "DarkIce not compiled with lame support, "
00831                                  "thus can't create mp3 stream: ",
00832                                  stream);
00833 #else
00834                 audioOuts[u].encoder = new LameLibEncoder(
00835                                                     audioOuts[u].server.get(),
00836                                                     dsp.get(),
00837                                                     bitrateMode,
00838                                                     bitrate,
00839                                                     quality,
00840                                                     sampleRate,
00841                                                     dsp->getChannel(),
00842                                                     lowpass,
00843                                                     highpass );
00844 #endif // HAVE_LAME_LIB
00845         } else if ( Util::strEq( format, "vorbis") ) {
00846 #ifndef HAVE_VORBIS_LIB
00847                 throw Exception( __FILE__, __LINE__,
00848                                 "DarkIce not compiled with Ogg Vorbis support, "
00849                                 "thus can't Ogg Vorbis stream: ",
00850                                 stream);
00851 #else
00852                 audioOuts[u].encoder = new VorbisLibEncoder(
00853                                                     audioOuts[u].server.get(),
00854                                                     dsp.get(),
00855                                                     bitrateMode,
00856                                                     bitrate,
00857                                                     quality,
00858                                                     dsp->getSampleRate(),
00859                                                     dsp->getChannel() );
00860 #endif // HAVE_VORBIS_LIB
00861         } else {
00862                 throw Exception( __FILE__, __LINE__,
00863                                 "Illegal stream format: ", format);
00864         }
00865 
00866         encConnector->attach( audioOuts[u].encoder.get());
00867     }
00868 
00869     noAudioOuts += u;
00870 }
00871 
00872 
00873 /*------------------------------------------------------------------------------
00874  *  Set POSIX real-time scheduling, if super-user
00875  *----------------------------------------------------------------------------*/
00876 void
00877 DarkIce :: setRealTimeScheduling ( void )               throw ( Exception )
00878 {
00879 // Only if the OS has the POSIX real-time scheduling functions implemented.
00880 #if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
00881     uid_t   euid;
00882 
00883     euid = geteuid();
00884 
00885     if ( euid == 0 ) {
00886         int                 high_priority;
00887         struct sched_param  param;
00888 
00889         /* store the old scheduling parameters */
00890         if ( (origSchedPolicy = sched_getscheduler(0)) == -1 ) {
00891             throw Exception( __FILE__, __LINE__, "sched_getscheduler", errno);
00892         }
00893 
00894         if ( sched_getparam( 0, &param) == -1 ) {
00895             throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
00896         }
00897         origSchedPriority = param.sched_priority;
00898         
00899         /* set SCHED_FIFO with max - 1 priority */
00900         if ( (high_priority = sched_get_priority_max(SCHED_FIFO)) == -1 ) {
00901             throw Exception(__FILE__,__LINE__,"sched_get_priority_max",errno);
00902         }
00903         reportEvent( 8, "scheduler high priority", high_priority);
00904 
00905         param.sched_priority = high_priority - 1;
00906 
00907         if ( sched_setscheduler( 0, SCHED_FIFO, &param) == -1 ) {
00908             throw Exception( __FILE__, __LINE__, "sched_setscheduler", errno);
00909         }
00910 
00911         /* ask the new priortiy and report it */
00912         if ( sched_getparam( 0, &param) == -1 ) {
00913             throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
00914         }
00915 
00916         reportEvent( 1,
00917                      "Using POSIX real-time scheduling, priority",
00918                      param.sched_priority );
00919     } else {
00920         reportEvent( 1,
00921         "Not running as super-user, unable to use POSIX real-time scheduling" );
00922         reportEvent( 1,
00923         "It is recommended that you run this program as super-user");
00924     }
00925 #else
00926     reportEvent( 1, "POSIX scheduling not supported on this system, "
00927                     "this may cause recording skips");
00928 #endif // HAVE_SCHED_GETSCHEDULER && HAVE_SCHED_GETPARAM
00929 }
00930 
00931 
00932 /*------------------------------------------------------------------------------
00933  *  Set the original scheduling of the process, the one prior to the
00934  *  setRealTimeScheduling call.
00935  *  WARNING: make sure you don't call this before setRealTimeScheduling!!
00936  *----------------------------------------------------------------------------*/
00937 void
00938 DarkIce :: setOriginalScheduling ( void )               throw ( Exception )
00939 {
00940 // Only if the OS has the POSIX real-time scheduling functions implemented.
00941 #if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
00942     uid_t   euid;
00943 
00944     euid = geteuid();
00945 
00946     if ( euid == 0 ) {
00947         struct sched_param  param;
00948 
00949         if ( sched_getparam( 0, &param) == -1 ) {
00950             throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
00951         }
00952 
00953         param.sched_priority = origSchedPriority;
00954 
00955         if ( sched_setscheduler( 0, origSchedPolicy, &param) == -1 ) {
00956             throw Exception( __FILE__, __LINE__, "sched_setscheduler", errno);
00957         }
00958 
00959         reportEvent( 5, "reverted to original scheduling");
00960     }
00961 #endif // HAVE_SCHED_GETSCHEDULER && HAVE_SCHED_GETPARAM
00962 }
00963 
00964 
00965 /*------------------------------------------------------------------------------
00966  *  Run the encoder
00967  *----------------------------------------------------------------------------*/
00968 bool
00969 DarkIce :: encode ( void )                          throw ( Exception )
00970 {
00971     unsigned int       len;
00972     unsigned long      bytes;
00973 
00974     if ( !encConnector->open() ) {
00975         throw Exception( __FILE__, __LINE__, "can't open connector");
00976     }
00977     
00978     bytes = dsp->getSampleRate() *
00979             (dsp->getBitsPerSample() / 8UL) *
00980             dsp->getChannel() *
00981             duration;
00982                                                 
00983     len = encConnector->transfer( bytes, 4096, 1, 0 );
00984 
00985     reportEvent( 1, len, "bytes transfered to the encoders");
00986 
00987     encConnector->close();
00988 
00989     return true;
00990 }
00991 
00992 
00993 /*------------------------------------------------------------------------------
00994  *  Run
00995  *----------------------------------------------------------------------------*/
00996 int
00997 DarkIce :: run ( void )                             throw ( Exception )
00998 {
00999     reportEvent( 3, "encoding");
01000     setRealTimeScheduling();
01001     encode();
01002     setOriginalScheduling();
01003     reportEvent( 3, "encoding ends");
01004 
01005     return 0;
01006 }
01007 
01008 
01009 /*------------------------------------------------------------------------------
01010  
01011   $Source: /cvsroot/darkice/darkice/src/DarkIce.cpp,v $
01012 
01013   $Log: DarkIce.cpp,v $
01014   Revision 1.43  2005/04/11 19:27:43  darkeye
01015   added option to turn off automatic reconnect feature
01016 
01017   Revision 1.42  2005/04/04 08:36:17  darkeye
01018   commited changes to enable Jack support
01019   thanks to Nicholas J. Humfrey, njh@ecs.soton.ac.uk
01020 
01021   Revision 1.41  2005/04/03 05:12:20  jbebel
01022   Changed mechanism for testing the presence of the quality value such that
01023   zero is a valid option.
01024 
01025   Revision 1.40  2004/02/23 19:12:51  darkeye
01026   ported to NetBSD
01027 
01028   Revision 1.39  2004/02/19 06:47:06  darkeye
01029   finalized OpenBSD port
01030 
01031   Revision 1.38  2004/02/18 21:08:11  darkeye
01032   ported to OpenBSD (real-time scheduling not yet supported)
01033 
01034   Revision 1.37  2004/02/15 12:14:38  darkeye
01035   added patch to allow mp3 stream downsampling to mono for icecast2 as well
01036 
01037   Revision 1.36  2004/02/15 12:06:30  darkeye
01038   added ALSA support, thanks to Christian Forster
01039 
01040   Revision 1.35  2003/02/09 13:15:57  darkeye
01041   added feature for setting the TITLE comment field for vorbis streams
01042 
01043   Revision 1.34  2003/02/09 12:57:36  darkeye
01044   cosmetic changes to the fileAddDate option
01045 
01046   Revision 1.33  2002/11/20 16:52:05  wandereq
01047   added fileAddDate function
01048 
01049   Revision 1.32  2002/10/19 12:24:55  darkeye
01050   anged internals so that now each encoding/server connection is
01051   a separate thread
01052 
01053   Revision 1.31  2002/08/20 19:35:37  darkeye
01054   added possibility to specify maximum bitrate for Ogg Vorbis streams
01055 
01056   Revision 1.30  2002/08/20 18:37:49  darkeye
01057   added mp3 streaming possibility for icecast2
01058 
01059   Revision 1.29  2002/08/03 12:41:18  darkeye
01060   added possibility to stream in mono when recording in stereo
01061 
01062   Revision 1.28  2002/07/20 10:59:00  darkeye
01063   added support for Ogg Vorbis 1.0, removed support for rc2
01064 
01065   Revision 1.27  2002/04/13 11:26:00  darkeye
01066   added cbr, abr and vbr setting feature with encoding quality
01067 
01068   Revision 1.26  2002/03/28 16:43:11  darkeye
01069   enabled resampling and variable bitrates for vorbis (icecast2) streams
01070 
01071   Revision 1.25  2002/02/28 09:49:25  darkeye
01072   added possibility to save the encoded stream to a local file only
01073   (no streaming server needed)
01074 
01075   Revision 1.24  2002/02/20 11:54:11  darkeye
01076   added local dump file possibility
01077 
01078   Revision 1.23  2002/02/20 10:35:35  darkeye
01079   updated to work with Ogg Vorbis libs rc3 and current IceCast2 cvs
01080 
01081   Revision 1.22  2001/10/20 10:56:45  darkeye
01082   added possibility to disable highpass and lowpass filters for lame
01083 
01084   Revision 1.21  2001/10/19 12:39:42  darkeye
01085   created configure options to compile with or without lame / Ogg Vorbis
01086 
01087   Revision 1.20  2001/10/19 09:03:39  darkeye
01088   added support for resampling mp3 streams
01089 
01090   Revision 1.19  2001/09/14 19:31:06  darkeye
01091   added IceCast2 / vorbis support
01092 
01093   Revision 1.18  2001/09/11 15:05:21  darkeye
01094   added Solaris support
01095 
01096   Revision 1.17  2001/09/09 11:27:31  darkeye
01097   added support for ShoutCast servers
01098 
01099   Revision 1.16  2001/09/05 20:11:15  darkeye
01100   removed dependency on locally stored SGI STL header files
01101   now compiler-supplied C++ library STL header files are used
01102   compiles under GNU C++ 3
01103   hash_map (an SGI extension to STL) replaced with map
01104   std:: namespace prefix added to all STL class references
01105 
01106   Revision 1.15  2001/08/30 17:25:56  darkeye
01107   renamed configure.h to config.h
01108 
01109   Revision 1.14  2001/08/29 21:08:30  darkeye
01110   made some description options in the darkice config file optional
01111 
01112   Revision 1.13  2001/08/26 20:44:30  darkeye
01113   removed external command-line encoder support
01114   replaced it with a shared-object support for lame with the possibility
01115   of static linkage
01116 
01117   Revision 1.12  2000/12/20 12:36:47  darkeye
01118   added POSIX real-time scheduling
01119 
01120   Revision 1.11  2000/11/18 11:13:27  darkeye
01121   removed direct reference to cout, except from main.cpp
01122   all class use the Reporter interface to report events
01123 
01124   Revision 1.10  2000/11/17 15:50:48  darkeye
01125   added -Wall flag to compiler and eleminated new warnings
01126 
01127   Revision 1.9  2000/11/15 18:37:37  darkeye
01128   changed the transferable number of bytes to unsigned long
01129 
01130   Revision 1.8  2000/11/15 18:08:43  darkeye
01131   added multiple verbosity-level event reporting and verbosity command
01132   line option
01133 
01134   Revision 1.7  2000/11/13 19:38:55  darkeye
01135   moved command line parameter parsing from DarkIce.cpp to main.cpp
01136 
01137   Revision 1.6  2000/11/13 18:46:50  darkeye
01138   added kdoc-style documentation comments
01139 
01140   Revision 1.5  2000/11/10 20:16:21  darkeye
01141   first real tests with multiple streaming
01142 
01143   Revision 1.4  2000/11/09 22:09:46  darkeye
01144   added multiple outputs
01145   added configuration reading
01146   added command line processing
01147 
01148   Revision 1.3  2000/11/08 17:29:50  darkeye
01149   added configuration file reader
01150 
01151   Revision 1.2  2000/11/05 14:08:27  darkeye
01152   changed builting to an automake / autoconf environment
01153 
01154   Revision 1.1.1.1  2000/11/05 10:05:49  darkeye
01155   initial version
01156 
01157   
01158 ------------------------------------------------------------------------------*/
01159 

Generated on Thu Apr 14 13:59:12 2005 for DarkIce by  doxygen 1.4.1