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
00092
00093
00094
00095
00096
00097
00098
00099
00100 static const char fileid[] = "$Id: DarkIce.cpp,v 1.43 2005/04/11 19:27:43 darkeye Exp $";
00101
00102
00103
00104
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
00116
00117
00118
00119
00120
00121
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
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
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
00176
00177 void
00178 DarkIce :: configIceCast ( const Config & config,
00179 unsigned int bufferSecs )
00180 throw ( Exception )
00181 {
00182
00183
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
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
00295
00296
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
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
00349
00350 void
00351 DarkIce :: configIceCast2 ( const Config & config,
00352 unsigned int bufferSecs )
00353 throw ( Exception )
00354 {
00355
00356
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
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
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
00464
00465
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
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
00551
00552 void
00553 DarkIce :: configShoutCast ( const Config & config,
00554 unsigned int bufferSecs )
00555 throw ( Exception )
00556 {
00557
00558
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
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
00668
00669
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
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
00723
00724 void
00725 DarkIce :: configFileCast ( const Config & config )
00726 throw ( Exception )
00727 {
00728
00729
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
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
00813
00814
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
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
00875
00876 void
00877 DarkIce :: setRealTimeScheduling ( void ) throw ( Exception )
00878 {
00879
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
00890 if ( (origSchedPolicy = sched_getscheduler(0)) == -1 ) {
00891 throw Exception( __FILE__, __LINE__, "sched_getscheduler", errno);
00892 }
00893
00894 if ( sched_getparam( 0, ¶m) == -1 ) {
00895 throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
00896 }
00897 origSchedPriority = param.sched_priority;
00898
00899
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, ¶m) == -1 ) {
00908 throw Exception( __FILE__, __LINE__, "sched_setscheduler", errno);
00909 }
00910
00911
00912 if ( sched_getparam( 0, ¶m) == -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
00934
00935
00936
00937 void
00938 DarkIce :: setOriginalScheduling ( void ) throw ( Exception )
00939 {
00940
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, ¶m) == -1 ) {
00950 throw Exception( __FILE__, __LINE__, "sched_getparam", errno);
00951 }
00952
00953 param.sched_priority = origSchedPriority;
00954
00955 if ( sched_setscheduler( 0, origSchedPolicy, ¶m) == -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
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
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
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
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