00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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_TWOLAME_LIB
00088 #include "TwoLameLibEncoder.h"
00089 #endif
00090
00091 #ifdef HAVE_VORBIS_LIB
00092 #include "VorbisLibEncoder.h"
00093 #endif
00094
00095 #ifdef HAVE_FAAC_LIB
00096 #include "FaacEncoder.h"
00097 #endif
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 static const char fileid[] = "$Id: DarkIce.cpp,v 1.49 2006/03/23 09:34:57 darkeye Exp $";
00109
00110
00111
00112
00113
00114 #ifndef WEXITSTATUS
00115 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00116 #endif
00117 #ifndef WIFEXITED
00118 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00119 #endif
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 void
00132 DarkIce :: init ( const Config & config ) throw ( Exception )
00133 {
00134 unsigned int bufferSecs;
00135 const ConfigSection * cs;
00136 const char * str;
00137 unsigned int sampleRate;
00138 unsigned int bitsPerSample;
00139 unsigned int channel;
00140 bool reconnect;
00141 const char * device;
00142
00143
00144 if ( !(cs = config.get( "general")) ) {
00145 throw Exception( __FILE__, __LINE__, "no section [general] in config");
00146 }
00147 str = cs->getForSure( "duration", " missing in section [general]");
00148 duration = Util::strToL( str);
00149 str = cs->getForSure( "bufferSecs", " missing in section [general]");
00150 bufferSecs = Util::strToL( str);
00151 if (bufferSecs == 0) {
00152 throw Exception(__FILE__, __LINE__,
00153 "setting bufferSecs to 0 not supported");
00154 }
00155 str = cs->get( "reconnect");
00156 reconnect = str ? (Util::strEq( str, "yes") ? true : false) : true;
00157
00158
00159 str = cs->get( "realtime" );
00160 enableRealTime = str ? (Util::strEq( str, "yes") ? true : false) : true;
00161
00162
00163
00164 if ( !(cs = config.get( "input")) ) {
00165 throw Exception( __FILE__, __LINE__, "no section [input] in config");
00166 }
00167
00168 str = cs->getForSure( "sampleRate", " missing in section [input]");
00169 sampleRate = Util::strToL( str);
00170 str = cs->getForSure( "bitsPerSample", " missing in section [input]");
00171 bitsPerSample = Util::strToL( str);
00172 str = cs->getForSure( "channel", " missing in section [input]");
00173 channel = Util::strToL( str);
00174 device = cs->getForSure( "device", " missing in section [input]");
00175
00176 dsp = AudioSource::createDspSource( device,
00177 sampleRate,
00178 bitsPerSample,
00179 channel );
00180 encConnector = new MultiThreadedConnector( dsp.get(), reconnect );
00181
00182 noAudioOuts = 0;
00183 configIceCast( config, bufferSecs);
00184 configIceCast2( config, bufferSecs);
00185 configShoutCast( config, bufferSecs);
00186 configFileCast( config);
00187 }
00188
00189
00190
00191
00192
00193 void
00194 DarkIce :: configIceCast ( const Config & config,
00195 unsigned int bufferSecs )
00196 throw ( Exception )
00197 {
00198
00199
00200 char stream[] = "icecast- ";
00201 size_t streamLen = Util::strLen( stream);
00202 unsigned int u;
00203
00204 for ( u = noAudioOuts; u < maxOutput; ++u ) {
00205 const ConfigSection * cs;
00206
00207
00208 stream[streamLen-1] = '0' + (u - noAudioOuts);
00209
00210 if ( !(cs = config.get( stream)) ) {
00211 break;
00212 }
00213
00214 #if !defined HAVE_LAME_LIB && !defined HAVE_TWOLAME_LIB
00215 throw Exception( __FILE__, __LINE__,
00216 "DarkIce not compiled with lame or twolame support, "
00217 "thus can't connect to IceCast 1.x, stream: ",
00218 stream);
00219 #else
00220
00221 const char * str;
00222
00223 unsigned int sampleRate = 0;
00224 unsigned int channel = 0;
00225 AudioEncoder::BitrateMode bitrateMode;
00226 unsigned int bitrate = 0;
00227 double quality = 0.0;
00228 const char * server = 0;
00229 unsigned int port = 0;
00230 const char * password = 0;
00231 const char * mountPoint = 0;
00232 const char * remoteDumpFile = 0;
00233 const char * name = 0;
00234 const char * description = 0;
00235 const char * url = 0;
00236 const char * genre = 0;
00237 bool isPublic = false;
00238 int lowpass = 0;
00239 int highpass = 0;
00240 const char * localDumpName = 0;
00241 FileSink * localDumpFile = 0;
00242 bool fileAddDate = false;
00243
00244 str = cs->get( "sampleRate");
00245 sampleRate = str ? Util::strToL( str) : dsp->getSampleRate();
00246 str = cs->get( "channel");
00247 channel = str ? Util::strToL( str) : dsp->getChannel();
00248
00249 str = cs->get( "bitrate");
00250 bitrate = str ? Util::strToL( str) : 0;
00251 str = cs->get( "quality");
00252 quality = str ? Util::strToD( str) : 0.0;
00253
00254 str = cs->getForSure( "bitrateMode",
00255 " not specified in section ",
00256 stream);
00257 if ( Util::strEq( str, "cbr") ) {
00258 bitrateMode = AudioEncoder::cbr;
00259
00260 if ( bitrate == 0 ) {
00261 throw Exception( __FILE__, __LINE__,
00262 "bitrate not specified for CBR encoding");
00263 }
00264 if ( cs->get( "quality" ) == 0 ) {
00265 throw Exception( __FILE__, __LINE__,
00266 "quality not specified for CBR encoding");
00267 }
00268 } else if ( Util::strEq( str, "abr") ) {
00269 bitrateMode = AudioEncoder::abr;
00270
00271 if ( bitrate == 0 ) {
00272 throw Exception( __FILE__, __LINE__,
00273 "bitrate not specified for ABR encoding");
00274 }
00275 } else if ( Util::strEq( str, "vbr") ) {
00276 bitrateMode = AudioEncoder::vbr;
00277
00278 if ( cs->get( "quality" ) == 0 ) {
00279 throw Exception( __FILE__, __LINE__,
00280 "quality not specified for VBR encoding");
00281 }
00282 } else {
00283 throw Exception( __FILE__, __LINE__,
00284 "invalid bitrate mode: ", str);
00285 }
00286
00287
00288
00289 server = cs->getForSure( "server", " missing in section ", stream);
00290 str = cs->getForSure( "port", " missing in section ", stream);
00291 port = Util::strToL( str);
00292 password = cs->getForSure("password"," missing in section ",stream);
00293 mountPoint = cs->getForSure( "mountPoint",
00294 " missing in section ",
00295 stream);
00296 remoteDumpFile = cs->get( "remoteDumpFile");
00297 name = cs->get( "name");
00298 description = cs->get("description");
00299 url = cs->get( "url");
00300 genre = cs->get( "genre");
00301 str = cs->get( "public");
00302 isPublic = str ? (Util::strEq( str, "yes") ? true : false) : false;
00303 str = cs->get( "lowpass");
00304 lowpass = str ? Util::strToL( str) : 0;
00305 str = cs->get( "highpass");
00306 highpass = str ? Util::strToL( str) : 0;
00307 str = cs->get("fileAddDate");
00308 fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
00309
00310 localDumpName = cs->get( "localDumpFile");
00311
00312
00313
00314
00315 if ( localDumpName != 0 ) {
00316 if ( fileAddDate ) {
00317 localDumpName = Util::fileAddDate(localDumpName);
00318 }
00319
00320 localDumpFile = new FileSink( localDumpName);
00321 if ( !localDumpFile->exists() ) {
00322 if ( !localDumpFile->create() ) {
00323 reportEvent( 1, "can't create local dump file",
00324 localDumpName);
00325 localDumpFile = 0;
00326 }
00327 }
00328 if ( fileAddDate ) {
00329 delete[] localDumpFile;
00330 }
00331 }
00332
00333 audioOuts[u].socket = new TcpSocket( server, port);
00334 audioOuts[u].server = new IceCast( audioOuts[u].socket.get(),
00335 password,
00336 mountPoint,
00337 bitrate,
00338 name,
00339 description,
00340 url,
00341 genre,
00342 isPublic,
00343 remoteDumpFile,
00344 localDumpFile,
00345 bufferSecs );
00346
00347 str = cs->getForSure( "format", " missing in section ", stream);
00348
00349 if (!Util::strEq(str, "mp3") && !Util::strEq(str, "mp2")) {
00350 throw Exception( __FILE__, __LINE__,
00351 "unsupported stream format: ", str);
00352
00353 }
00354
00355 #ifdef HAVE_LAME_LIB
00356 if ( Util::strEq( str, "mp3") ) {
00357 audioOuts[u].encoder = new LameLibEncoder( audioOuts[u].server.get(),
00358 dsp.get(),
00359 bitrateMode,
00360 bitrate,
00361 quality,
00362 sampleRate,
00363 channel,
00364 lowpass,
00365 highpass );
00366 }
00367 #endif
00368 #ifdef HAVE_TWOLAME_LIB
00369 if ( Util::strEq( str, "mp2") ) {
00370 audioOuts[u].encoder = new TwoLameLibEncoder(
00371 audioOuts[u].server.get(),
00372 dsp.get(),
00373 bitrateMode,
00374 bitrate,
00375 sampleRate,
00376 channel );
00377 }
00378 #endif
00379
00380 encConnector->attach( audioOuts[u].encoder.get());
00381 #endif // HAVE_LAME_LIB || HAVE_TWOLAME_LIB
00382 }
00383
00384 noAudioOuts += u;
00385 }
00386
00387
00388
00389
00390
00391 void
00392 DarkIce :: configIceCast2 ( const Config & config,
00393 unsigned int bufferSecs )
00394 throw ( Exception )
00395 {
00396
00397
00398 char stream[] = "icecast2- ";
00399 size_t streamLen = Util::strLen( stream);
00400 unsigned int u;
00401
00402 for ( u = noAudioOuts; u < maxOutput; ++u ) {
00403 const ConfigSection * cs;
00404
00405
00406 stream[streamLen-1] = '0' + (u - noAudioOuts);
00407
00408 if ( !(cs = config.get( stream)) ) {
00409 break;
00410 }
00411
00412 const char * str;
00413
00414 IceCast2::StreamFormat format;
00415 unsigned int sampleRate = 0;
00416 unsigned int channel = 0;
00417 AudioEncoder::BitrateMode bitrateMode;
00418 unsigned int bitrate = 0;
00419 unsigned int maxBitrate = 0;
00420 double quality = 0.0;
00421 const char * server = 0;
00422 unsigned int port = 0;
00423 const char * password = 0;
00424 const char * mountPoint = 0;
00425 const char * name = 0;
00426 const char * description = 0;
00427 const char * url = 0;
00428 const char * genre = 0;
00429 bool isPublic = false;
00430 int lowpass = 0;
00431 int highpass = 0;
00432 const char * localDumpName = 0;
00433 FileSink * localDumpFile = 0;
00434 bool fileAddDate = false;
00435
00436 str = cs->getForSure( "format", " missing in section ", stream);
00437 if ( Util::strEq( str, "vorbis") ) {
00438 format = IceCast2::oggVorbis;
00439 } else if ( Util::strEq( str, "mp3") ) {
00440 format = IceCast2::mp3;
00441 } else if ( Util::strEq( str, "mp2") ) {
00442 format = IceCast2::mp2;
00443 } else if ( Util::strEq( str, "aac") ) {
00444 format = IceCast2::aac;
00445 } else {
00446 throw Exception( __FILE__, __LINE__,
00447 "unsupported stream format: ", str);
00448 }
00449
00450 str = cs->get( "sampleRate");
00451 sampleRate = str ? Util::strToL( str) : dsp->getSampleRate();
00452 str = cs->get( "channel");
00453 channel = str ? Util::strToL( str) : dsp->getChannel();
00454
00455
00456 str = cs->get( "bitrate");
00457 bitrate = str ? Util::strToL( str) : 0;
00458 str = cs->get( "maxBitrate");
00459 maxBitrate = str ? Util::strToL( str) : 0;
00460 str = cs->get( "quality");
00461 quality = str ? Util::strToD( str) : 0.0;
00462
00463 str = cs->getForSure( "bitrateMode",
00464 " not specified in section ",
00465 stream);
00466 if ( Util::strEq( str, "cbr") ) {
00467 bitrateMode = AudioEncoder::cbr;
00468
00469 if ( bitrate == 0 ) {
00470 throw Exception( __FILE__, __LINE__,
00471 "bitrate not specified for CBR encoding");
00472 }
00473 } else if ( Util::strEq( str, "abr") ) {
00474 bitrateMode = AudioEncoder::abr;
00475
00476 if ( bitrate == 0 ) {
00477 throw Exception( __FILE__, __LINE__,
00478 "bitrate not specified for ABR encoding");
00479 }
00480 } else if ( Util::strEq( str, "vbr") ) {
00481 bitrateMode = AudioEncoder::vbr;
00482
00483 if ( cs->get( "quality" ) == 0 ) {
00484 throw Exception( __FILE__, __LINE__,
00485 "quality not specified for VBR encoding");
00486 }
00487 } else {
00488 throw Exception( __FILE__, __LINE__,
00489 "invalid bitrate mode: ", str);
00490 }
00491
00492 server = cs->getForSure( "server", " missing in section ", stream);
00493 str = cs->getForSure( "port", " missing in section ", stream);
00494 port = Util::strToL( str);
00495 password = cs->getForSure("password"," missing in section ",stream);
00496 mountPoint = cs->getForSure( "mountPoint",
00497 " missing in section ",
00498 stream);
00499 name = cs->get( "name");
00500 description = cs->get( "description");
00501 url = cs->get( "url");
00502 genre = cs->get( "genre");
00503 str = cs->get( "public");
00504 isPublic = str ? (Util::strEq( str, "yes") ? true : false) : false;
00505 str = cs->get( "lowpass");
00506 lowpass = str ? Util::strToL( str) : 0;
00507 str = cs->get( "highpass");
00508 highpass = str ? Util::strToL( str) : 0;
00509 str = cs->get( "fileAddDate");
00510 fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
00511
00512 localDumpName = cs->get( "localDumpFile");
00513
00514
00515
00516
00517 if ( localDumpName != 0 ) {
00518 if ( fileAddDate ) {
00519 localDumpName = Util::fileAddDate(localDumpName);
00520 }
00521
00522 localDumpFile = new FileSink( localDumpName);
00523 if ( !localDumpFile->exists() ) {
00524 if ( !localDumpFile->create() ) {
00525 reportEvent( 1, "can't create local dump file",
00526 localDumpName);
00527 localDumpFile = 0;
00528 }
00529 }
00530 if ( fileAddDate ) {
00531 delete[] localDumpName;
00532 }
00533 }
00534
00535
00536 audioOuts[u].socket = new TcpSocket( server, port);
00537 audioOuts[u].server = new IceCast2( audioOuts[u].socket.get(),
00538 password,
00539 mountPoint,
00540 format,
00541 bitrate,
00542 name,
00543 description,
00544 url,
00545 genre,
00546 isPublic,
00547 localDumpFile,
00548 bufferSecs );
00549
00550 switch ( format ) {
00551 case IceCast2::mp3:
00552 #ifndef HAVE_LAME_LIB
00553 throw Exception( __FILE__, __LINE__,
00554 "DarkIce not compiled with lame support, "
00555 "thus can't create mp3 stream: ",
00556 stream);
00557 #else
00558 audioOuts[u].encoder = new LameLibEncoder(
00559 audioOuts[u].server.get(),
00560 dsp.get(),
00561 bitrateMode,
00562 bitrate,
00563 quality,
00564 sampleRate,
00565 channel,
00566 lowpass,
00567 highpass );
00568 #endif // HAVE_LAME_LIB
00569 break;
00570
00571
00572 case IceCast2::oggVorbis:
00573 #ifndef HAVE_VORBIS_LIB
00574 throw Exception( __FILE__, __LINE__,
00575 "DarkIce not compiled with Ogg Vorbis support, "
00576 "thus can't Ogg Vorbis stream: ",
00577 stream);
00578 #else
00579 audioOuts[u].encoder = new VorbisLibEncoder(
00580 audioOuts[u].server.get(),
00581 dsp.get(),
00582 bitrateMode,
00583 bitrate,
00584 quality,
00585 sampleRate,
00586 dsp->getChannel(),
00587 maxBitrate);
00588 #endif // HAVE_VORBIS_LIB
00589 break;
00590
00591 case IceCast2::mp2:
00592 #ifndef HAVE_TWOLAME_LIB
00593 throw Exception( __FILE__, __LINE__,
00594 "DarkIce not compiled with TwoLame support, "
00595 "thus can't create mp2 stream: ",
00596 stream);
00597 #else
00598 audioOuts[u].encoder = new TwoLameLibEncoder(
00599 audioOuts[u].server.get(),
00600 dsp.get(),
00601 bitrateMode,
00602 bitrate,
00603 sampleRate,
00604 channel );
00605 #endif // HAVE_TWOLAME_LIB
00606 break;
00607
00608
00609 case IceCast2::aac:
00610 #ifndef HAVE_FAAC_LIB
00611 throw Exception( __FILE__, __LINE__,
00612 "DarkIce not compiled with AAC support, "
00613 "thus can't aac stream: ",
00614 stream);
00615 #else
00616 audioOuts[u].encoder = new FaacEncoder(
00617 audioOuts[u].server.get(),
00618 dsp.get(),
00619 bitrateMode,
00620 bitrate,
00621 quality,
00622 sampleRate,
00623 dsp->getChannel());
00624 #endif // HAVE_FAAC_LIB
00625 break;
00626
00627 default:
00628 throw Exception( __FILE__, __LINE__,
00629 "Illegal stream format: ", format);
00630 }
00631
00632 encConnector->attach( audioOuts[u].encoder.get());
00633 }
00634
00635 noAudioOuts += u;
00636 }
00637
00638
00639
00640
00641
00642 void
00643 DarkIce :: configShoutCast ( const Config & config,
00644 unsigned int bufferSecs )
00645 throw ( Exception )
00646 {
00647
00648
00649 char stream[] = "shoutcast- ";
00650 size_t streamLen = Util::strLen( stream);
00651 unsigned int u;
00652
00653 for ( u = noAudioOuts; u < maxOutput; ++u ) {
00654 const ConfigSection * cs;
00655
00656
00657 stream[streamLen-1] = '0' + (u - noAudioOuts);
00658
00659 if ( !(cs = config.get( stream)) ) {
00660 break;
00661 }
00662
00663 #ifndef HAVE_LAME_LIB
00664 throw Exception( __FILE__, __LINE__,
00665 "DarkIce not compiled with lame support, "
00666 "thus can't connect to ShoutCast, stream: ",
00667 stream);
00668 #else
00669
00670 const char * str;
00671
00672 unsigned int sampleRate = 0;
00673 unsigned int channel = 0;
00674 AudioEncoder::BitrateMode bitrateMode;
00675 unsigned int bitrate = 0;
00676 double quality = 0.0;
00677 const char * server = 0;
00678 unsigned int port = 0;
00679 const char * password = 0;
00680 const char * name = 0;
00681 const char * url = 0;
00682 const char * genre = 0;
00683 bool isPublic = false;
00684 int lowpass = 0;
00685 int highpass = 0;
00686 const char * irc = 0;
00687 const char * aim = 0;
00688 const char * icq = 0;
00689 const char * localDumpName = 0;
00690 FileSink * localDumpFile = 0;
00691 bool fileAddDate = false;
00692
00693 str = cs->get( "sampleRate");
00694 sampleRate = str ? Util::strToL( str) : dsp->getSampleRate();
00695 str = cs->get( "channel");
00696 channel = str ? Util::strToL( str) : dsp->getChannel();
00697
00698 str = cs->get( "bitrate");
00699 bitrate = str ? Util::strToL( str) : 0;
00700 str = cs->get( "quality");
00701 quality = str ? Util::strToD( str) : 0.0;
00702
00703 str = cs->getForSure( "bitrateMode",
00704 " not specified in section ",
00705 stream);
00706 if ( Util::strEq( str, "cbr") ) {
00707 bitrateMode = AudioEncoder::cbr;
00708
00709 if ( bitrate == 0 ) {
00710 throw Exception( __FILE__, __LINE__,
00711 "bitrate not specified for CBR encoding");
00712 }
00713 if ( cs->get( "quality" ) == 0 ) {
00714 throw Exception( __FILE__, __LINE__,
00715 "quality not specified for CBR encoding");
00716 }
00717 } else if ( Util::strEq( str, "abr") ) {
00718 bitrateMode = AudioEncoder::abr;
00719
00720 if ( bitrate == 0 ) {
00721 throw Exception( __FILE__, __LINE__,
00722 "bitrate not specified for ABR encoding");
00723 }
00724 } else if ( Util::strEq( str, "vbr") ) {
00725 bitrateMode = AudioEncoder::vbr;
00726
00727 if ( cs->get( "quality" ) == 0 ) {
00728 throw Exception( __FILE__, __LINE__,
00729 "quality not specified for VBR encoding");
00730 }
00731 } else {
00732 throw Exception( __FILE__, __LINE__,
00733 "invalid bitrate mode: ", str);
00734 }
00735
00736 server = cs->getForSure( "server", " missing in section ", stream);
00737 str = cs->getForSure( "port", " missing in section ", stream);
00738 port = Util::strToL( str);
00739 password = cs->getForSure("password"," missing in section ",stream);
00740 name = cs->get( "name");
00741 url = cs->get( "url");
00742 genre = cs->get( "genre");
00743 str = cs->get( "public");
00744 isPublic = str ? (Util::strEq( str, "yes") ? true : false) : false;
00745 str = cs->get( "lowpass");
00746 lowpass = str ? Util::strToL( str) : 0;
00747 str = cs->get( "highpass");
00748 highpass = str ? Util::strToL( str) : 0;
00749 irc = cs->get( "irc");
00750 aim = cs->get( "aim");
00751 icq = cs->get( "icq");
00752 str = cs->get("fileAddDate");
00753 fileAddDate = str ? (Util::strEq( str, "yes") ? true : false) : false;
00754
00755 localDumpName = cs->get( "localDumpFile");
00756
00757
00758
00759
00760 if ( localDumpName != 0 ) {
00761 if ( fileAddDate ) {
00762 localDumpName = Util::fileAddDate(localDumpName);
00763 }
00764
00765 localDumpFile = new FileSink( localDumpName);
00766 if ( !localDumpFile->exists() ) {
00767 if ( !localDumpFile->create() ) {
00768 reportEvent( 1, "can't create local dump file",
00769 localDumpName);
00770 localDumpFile = 0;
00771 }
00772 }
00773 if ( fileAddDate ) {
00774 delete[] localDumpFile;
00775 }
00776 }
00777
00778
00779 audioOuts[u].socket = new TcpSocket( server, port);
00780 audioOuts[u].server = new ShoutCast( audioOuts[u].socket.get(),
00781 password,
00782 bitrate,
00783 name,
00784 url,
00785 genre,
00786 isPublic,
00787 irc,
00788 aim,
00789 icq,
00790 localDumpFile,
00791 bufferSecs );
00792
00793 audioOuts[u].encoder = new LameLibEncoder( audioOuts[u].server.get(),
00794 dsp.get(),
00795 bitrateMode,
00796 bitrate,
00797 quality,
00798 sampleRate,
00799 channel,
00800 lowpass,
00801 highpass );
00802
00803 encConnector->attach( audioOuts[u].encoder.get());
00804 #endif // HAVE_LAME_LIB
00805 }
00806
00807 noAudioOuts += u;
00808 }
00809
00810
00811
00812
00813
00814 void
00815 DarkIce :: configFileCast ( const Config & config )
00816 throw ( Exception )
00817 {
00818
00819
00820 char stream[] = "file- ";
00821 size_t streamLen = Util::strLen( stream);
00822 unsigned int u;
00823
00824 for ( u = noAudioOuts; u < maxOutput; ++u ) {
00825 const ConfigSection * cs;
00826
00827
00828 stream[streamLen-1] = '0' + (u - noAudioOuts);
00829
00830 if ( !(cs = config.get( stream)) ) {
00831 break;
00832 }
00833
00834 const char * str;
00835
00836 const char * format = 0;
00837 AudioEncoder::BitrateMode bitrateMode;
00838 unsigned int bitrate = 0;
00839 double quality = 0.0;
00840 const char * targetFileName = 0;
00841 unsigned int sampleRate = 0;
00842 int lowpass = 0;
00843 int highpass = 0;
00844
00845 format = cs->getForSure( "format", " missing in section ", stream);
00846 if ( !Util::strEq( format, "vorbis")
00847 && !Util::strEq( format, "mp3")
00848 && !Util::strEq( format, "mp2")
00849 && !Util::strEq( format, "aac") ) {
00850 throw Exception( __FILE__, __LINE__,
00851 "unsupported stream format: ", format);
00852 }
00853
00854 str = cs->getForSure("bitrate", " missing in section ", stream);
00855 bitrate = Util::strToL( str);
00856 targetFileName = cs->getForSure( "fileName",
00857 " missing in section ",
00858 stream);
00859 str = cs->get( "sampleRate");
00860 sampleRate = str ? Util::strToL( str) : dsp->getSampleRate();
00861
00862 str = cs->get( "bitrate");
00863 bitrate = str ? Util::strToL( str) : 0;
00864 str = cs->get( "quality");
00865 quality = str ? Util::strToD( str) : 0.0;
00866
00867 str = cs->getForSure( "bitrateMode",
00868 " not specified in section ",
00869 stream);
00870 if ( Util::strEq( str, "cbr") ) {
00871 bitrateMode = AudioEncoder::cbr;
00872
00873 if ( bitrate == 0 ) {
00874 throw Exception( __FILE__, __LINE__,
00875 "bitrate not specified for CBR encoding");
00876 }
00877 } else if ( Util::strEq( str, "abr") ) {
00878 bitrateMode = AudioEncoder::abr;
00879
00880 if ( bitrate == 0 ) {
00881 throw Exception( __FILE__, __LINE__,
00882 "bitrate not specified for ABR encoding");
00883 }
00884 } else if ( Util::strEq( str, "vbr") ) {
00885 bitrateMode = AudioEncoder::vbr;
00886
00887 if ( cs->get( "quality" ) == 0 ) {
00888 throw Exception( __FILE__, __LINE__,
00889 "quality not specified for VBR encoding");
00890 }
00891 } else {
00892 throw Exception( __FILE__, __LINE__,
00893 "invalid bitrate mode: ", str);
00894 }
00895
00896 if (Util::strEq(format, "aac") && bitrateMode != AudioEncoder::abr) {
00897 throw Exception(__FILE__, __LINE__,
00898 "currently the AAC format only supports "
00899 "average bitrate mode");
00900 }
00901
00902 str = cs->get( "lowpass");
00903 lowpass = str ? Util::strToL( str) : 0;
00904 str = cs->get( "highpass");
00905 highpass = str ? Util::strToL( str) : 0;
00906
00907
00908
00909
00910 FileSink * targetFile = new FileSink( targetFileName);
00911 if ( !targetFile->exists() ) {
00912 if ( !targetFile->create() ) {
00913 throw Exception( __FILE__, __LINE__,
00914 "can't create output file", targetFileName);
00915 }
00916 }
00917
00918
00919 audioOuts[u].socket = 0;
00920 audioOuts[u].server = new FileCast( targetFile );
00921
00922 if ( Util::strEq( format, "mp3") ) {
00923 #ifndef HAVE_LAME_LIB
00924 throw Exception( __FILE__, __LINE__,
00925 "DarkIce not compiled with lame support, "
00926 "thus can't create mp3 stream: ",
00927 stream);
00928 #else
00929 audioOuts[u].encoder = new LameLibEncoder(
00930 audioOuts[u].server.get(),
00931 dsp.get(),
00932 bitrateMode,
00933 bitrate,
00934 quality,
00935 sampleRate,
00936 dsp->getChannel(),
00937 lowpass,
00938 highpass );
00939 #endif // HAVE_TWOLAME_LIB
00940 } else if ( Util::strEq( format, "mp2") ) {
00941 #ifndef HAVE_TWOLAME_LIB
00942 throw Exception( __FILE__, __LINE__,
00943 "DarkIce not compiled with TwoLAME support, "
00944 "thus can't create MPEG Audio Layer 2 stream: ",
00945 stream);
00946 #else
00947 audioOuts[u].encoder = new TwoLameLibEncoder(
00948 audioOuts[u].server.get(),
00949 dsp.get(),
00950 bitrateMode,
00951 bitrate,
00952 sampleRate,
00953 dsp->getChannel() );
00954 #endif // HAVE_TWOLAME_LIB
00955 } else if ( Util::strEq( format, "vorbis") ) {
00956 #ifndef HAVE_VORBIS_LIB
00957 throw Exception( __FILE__, __LINE__,
00958 "DarkIce not compiled with Ogg Vorbis support, "
00959 "thus can't Ogg Vorbis stream: ",
00960 stream);
00961 #else
00962 audioOuts[u].encoder = new VorbisLibEncoder(
00963 audioOuts[u].server.get(),
00964 dsp.get(),
00965 bitrateMode,
00966 bitrate,
00967 dsp->getSampleRate(),
00968 dsp->getChannel() );
00969 #endif // HAVE_VORBIS_LIB
00970 } else if ( Util::strEq( format, "aac") ) {
00971 #ifndef HAVE_FAAC_LIB
00972 throw Exception( __FILE__, __LINE__,
00973 "DarkIce not compiled with AAC support, "
00974 "thus can't aac stream: ",
00975 stream);
00976 #else
00977 audioOuts[u].encoder = new FaacEncoder(
00978 audioOuts[u].server.get(),
00979 dsp.get(),
00980 bitrateMode,
00981 bitrate,
00982 quality,
00983 sampleRate,
00984 dsp->getChannel());
00985 #endif // HAVE_FAAC_LIB
00986 } else {
00987 throw Exception( __FILE__, __LINE__,
00988 "Illegal stream format: ", format);
00989 }
00990
00991 encConnector->attach( audioOuts[u].encoder.get());
00992 }
00993
00994 noAudioOuts += u;
00995 }
00996
00997
00998
00999
01000
01001 void
01002 DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
01003 {
01004
01005 #if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
01006 uid_t euid;
01007
01008 euid = geteuid();
01009
01010 if ( euid == 0 ) {
01011 int high_priority;
01012 struct sched_param param;
01013
01014
01015 if ( (origSchedPolicy = sched_getscheduler(0)) == -1 ) {
01016 throw Exception( __FILE__, __LINE__, "sched_getscheduler", errno);
01017 }
01018
01019 if ( sched_getparam( 0, ¶m) == -1 ) {
01020 throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
01021 }
01022 origSchedPriority = param.sched_priority;
01023
01024
01025 if ( (high_priority = sched_get_priority_max(SCHED_FIFO)) == -1 ) {
01026 throw Exception(__FILE__,__LINE__,"sched_get_priority_max",errno);
01027 }
01028 reportEvent( 8, "scheduler high priority", high_priority);
01029
01030 param.sched_priority = high_priority - 1;
01031
01032 if ( sched_setscheduler( 0, SCHED_FIFO, ¶m) == -1 ) {
01033 throw Exception( __FILE__, __LINE__, "sched_setscheduler", errno);
01034 }
01035
01036
01037 if ( sched_getparam( 0, ¶m) == -1 ) {
01038 throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
01039 }
01040
01041 reportEvent( 1,
01042 "Using POSIX real-time scheduling, priority",
01043 param.sched_priority );
01044 } else {
01045 reportEvent( 1,
01046 "Not running as super-user, unable to use POSIX real-time scheduling" );
01047 reportEvent( 1,
01048 "It is recommended that you run this program as super-user");
01049 }
01050 #else
01051 reportEvent( 1, "POSIX scheduling not supported on this system, "
01052 "this may cause recording skips");
01053 #endif // HAVE_SCHED_GETSCHEDULER && HAVE_SCHED_GETPARAM
01054 }
01055
01056
01057
01058
01059
01060
01061
01062 void
01063 DarkIce :: setOriginalScheduling ( void ) throw ( Exception )
01064 {
01065
01066 #if defined( HAVE_SCHED_GETSCHEDULER ) && defined( HAVE_SCHED_GETPARAM )
01067 uid_t euid;
01068
01069 euid = geteuid();
01070
01071 if ( euid == 0 ) {
01072 struct sched_param param;
01073
01074 if ( sched_getparam( 0, ¶m) == -1 ) {
01075 throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
01076 }
01077
01078 param.sched_priority = origSchedPriority;
01079
01080 if ( sched_setscheduler( 0, origSchedPolicy, ¶m) == -1 ) {
01081 throw Exception( __FILE__, __LINE__, "sched_setscheduler", errno);
01082 }
01083
01084 reportEvent( 5, "reverted to original scheduling");
01085 }
01086 #endif // HAVE_SCHED_GETSCHEDULER && HAVE_SCHED_GETPARAM
01087 }
01088
01089
01090
01091
01092
01093 bool
01094 DarkIce :: encode ( void ) throw ( Exception )
01095 {
01096 unsigned int len;
01097 unsigned long bytes;
01098
01099 if ( !encConnector->open() ) {
01100 throw Exception( __FILE__, __LINE__, "can't open connector");
01101 }
01102
01103 bytes = dsp->getSampleRate() *
01104 (dsp->getBitsPerSample() / 8UL) *
01105 dsp->getChannel() *
01106 duration;
01107
01108 len = encConnector->transfer( bytes, 4096, 1, 0 );
01109
01110 reportEvent( 1, len, "bytes transfered to the encoders");
01111
01112 encConnector->close();
01113
01114 return true;
01115 }
01116
01117
01118
01119
01120
01121 int
01122 DarkIce :: run ( void ) throw ( Exception )
01123 {
01124 reportEvent( 3, "encoding");
01125
01126 if (enableRealTime) {
01127 setRealTimeScheduling();
01128 }
01129 encode();
01130 if (enableRealTime) {
01131 setOriginalScheduling();
01132 }
01133 reportEvent( 3, "encoding ends");
01134
01135 return 0;
01136 }
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307