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