00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include <pthread.h>
00024 #include <stdio.h>
00025 #include <string.h>
00026 #include <signal.h>
00027 #include <unistd.h>
00028 #include <limits.h>
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 #include <sys/socket.h>
00032 #include <netinet/in.h>
00033 #include <arpa/inet.h>
00034
00035 #include "SoundSrvA.hh"
00036
00037
00038 static bool bDaemon = false;
00039 clSoundSrvA SoundSrvA;
00040
00041
00042 int main (int argc, char *argv[])
00043 {
00044 return SoundSrvA.Main(argc, argv);
00045 }
00046
00047
00048 void SigHandler (int iSigNum)
00049 {
00050 switch (iSigNum)
00051 {
00052 case SIGINT:
00053 SoundSrvA.Log.Add('#', "Received SIGINT, terminating...");
00054 SoundSrvA.Stop();
00055 break;
00056 case SIGHUP:
00057 SoundSrvA.Log.Add('#', "Received SIGHUP, terminating...");
00058 SoundSrvA.Stop();
00059 break;
00060 case SIGTERM:
00061 SoundSrvA.Log.Add('#', "Received SIGTERM, terminating...");
00062 SoundSrvA.Stop();
00063 break;
00064 default:
00065 SoundSrvA.Log.Add('!', "Received unknown signal, terminating...");
00066 SoundSrvA.Stop();
00067 }
00068 }
00069
00070
00071 void *WrapAudioInThread (void *vpParam)
00072 {
00073 return SoundSrvA.AudioInThread(vpParam);
00074 }
00075
00076
00077 void *WrapServeClientThread (void *vpParam)
00078 {
00079 return SoundSrvA.ServeClientThread(vpParam);
00080 }
00081
00082
00083 #ifdef USE_FLAC
00084
00085 FLAC__StreamEncoderWriteStatus WrapFLACWrite (
00086 const FLAC__StreamEncoder *spFLACEnc, const FLAC__byte cpBuffer[],
00087 unsigned uiBytes, unsigned uiSamples, unsigned uiCurrFrame,
00088 void *vpDataPtr)
00089 {
00090 clSoundSrvA *SoundSrvAInst = (clSoundSrvA *) vpDataPtr;
00091
00092 return SoundSrvAInst->FLACWrite(spFLACEnc, cpBuffer, uiBytes, uiSamples,
00093 uiCurrFrame);
00094 }
00095
00096
00097 void WrapFLACMetaData (
00098 const FLAC__StreamEncoder *spFLACEnc,
00099 const FLAC__StreamMetadata *spFLACMetaData,
00100 void *vpDataPtr)
00101 {
00102 clSoundSrvA *SoundSrvAInst = (clSoundSrvA *) vpDataPtr;
00103
00104 SoundSrvAInst->FLACMetaData(spFLACEnc, spFLACMetaData);
00105 }
00106
00107 #endif
00108
00109
00110 bool clSoundSrvA::GetAudioCfg (int *ipCard, int *ipDevice, int *ipSubDevice,
00111 int *ipChannels, int *ipSampleRate, int *ipBits,
00112 int *ipFragSize, int *ipFragCount)
00113 {
00114 if (!Cfg.GetInt("Card", ipCard))
00115 {
00116 Log.Add('!', "\"Card\" not found from configuration file");
00117 return false;
00118 }
00119 if (!Cfg.GetInt("Device", ipDevice))
00120 {
00121 Log.Add('!', "\"Device\" not found from configuration file");
00122 return false;
00123 }
00124 if (!Cfg.GetInt("SubDevice", ipDevice))
00125 {
00126 Log.Add('!', "\"SubDevice\" not found from configuration file");
00127 return false;
00128 }
00129 if (!Cfg.GetInt("Channels", ipChannels))
00130 {
00131 Log.Add('!', "\"Channels\" not found from configuration file");
00132 return false;
00133 }
00134 if (!Cfg.GetInt("SampleRate", ipSampleRate))
00135 {
00136 Log.Add('!', "\"SampleRate\" not found from configuration file");
00137 return false;
00138 }
00139 if (!Cfg.GetInt("Bits", ipBits))
00140 {
00141 Log.Add('!', "\"Bits\" not found from configuration file");
00142 return false;
00143 }
00144 if (!Cfg.GetInt("FragSize", ipFragSize))
00145 *ipFragSize = SSA_FRAG_SIZE_DEFAULT;
00146 if (!Cfg.GetInt("FragCount", ipFragCount))
00147 *ipFragCount = 2;
00148 return true;
00149 }
00150
00151
00152 bool clSoundSrvA::InitCompress (int iChannels, int iSampleRate, int iBits,
00153 int iFragSize, int iCompress)
00154 {
00155 if (iCompress == MSG_SOUND_COMPRESS_FLAC)
00156 {
00157 #ifdef USE_FLAC
00158 int iMaxLPCOrder;
00159 int iMinRiceOrder;
00160 int iMaxRiceOrder;
00161 FLAC__StreamEncoderState iEncState;
00162
00163 if (!Cfg.GetInt("FLACMaxLPCOrder", &iMaxLPCOrder))
00164 iMaxLPCOrder = 0;
00165 if (iMaxLPCOrder > (int) FLAC__MAX_LPC_ORDER)
00166 iMaxLPCOrder = FLAC__MAX_LPC_ORDER;
00167 if (!Cfg.GetInt("FLACMinRiceOrder", &iMinRiceOrder))
00168 iMinRiceOrder = 0;
00169 if (!Cfg.GetInt("FLACMaxRiceOrder", &iMaxRiceOrder))
00170 iMaxRiceOrder = 0;
00171 if (iMaxRiceOrder > (int) FLAC__MAX_RICE_PARTITION_ORDER)
00172 iMaxRiceOrder = FLAC__MAX_RICE_PARTITION_ORDER;
00173 FLACFrame.Size(iFragSize * sizeof(FLAC__int32));
00174
00175 spFLACEnc = FLAC__stream_encoder_new();
00176 if (spFLACEnc == NULL)
00177 {
00178 Log.Add('!', "FLAC constructor failed");
00179 return false;
00180 }
00181 FLAC__stream_encoder_set_streamable_subset(spFLACEnc,
00182 1);
00183 FLAC__stream_encoder_set_do_mid_side_stereo(spFLACEnc,
00184 0);
00185 FLAC__stream_encoder_set_loose_mid_side_stereo(spFLACEnc,
00186 0);
00187 FLAC__stream_encoder_set_channels(spFLACEnc,
00188 iChannels);
00189 FLAC__stream_encoder_set_bits_per_sample(spFLACEnc,
00190 iBits);
00191 FLAC__stream_encoder_set_sample_rate(spFLACEnc,
00192 iSampleRate);
00193 FLAC__stream_encoder_set_blocksize(spFLACEnc,
00194 iFragSize);
00195 FLAC__stream_encoder_set_max_lpc_order(spFLACEnc,
00196 iMaxLPCOrder);
00197 FLAC__stream_encoder_set_qlp_coeff_precision(spFLACEnc,
00198 0);
00199 FLAC__stream_encoder_set_do_qlp_coeff_prec_search(spFLACEnc,
00200 0);
00201 FLAC__stream_encoder_set_do_escape_coding(spFLACEnc,
00202 1);
00203 FLAC__stream_encoder_set_do_exhaustive_model_search(spFLACEnc,
00204 1);
00205 FLAC__stream_encoder_set_min_residual_partition_order(spFLACEnc,
00206 iMinRiceOrder);
00207 FLAC__stream_encoder_set_max_residual_partition_order(spFLACEnc,
00208 iMaxRiceOrder);
00209 FLAC__stream_encoder_set_rice_parameter_search_dist(spFLACEnc,
00210 0);
00211 FLAC__stream_encoder_set_total_samples_estimate(spFLACEnc,
00212 0);
00213 FLAC__stream_encoder_set_metadata(spFLACEnc,
00214 NULL, 0);
00215 FLAC__stream_encoder_set_write_callback(spFLACEnc,
00216 WrapFLACWrite);
00217 FLAC__stream_encoder_set_metadata_callback(spFLACEnc,
00218 WrapFLACMetaData);
00219 FLAC__stream_encoder_set_client_data(spFLACEnc,
00220 (void *) this);
00221
00222 iEncState = FLAC__stream_encoder_init(spFLACEnc);
00223 if (iEncState != FLAC__STREAM_ENCODER_OK)
00224 {
00225 Log.Add('!', FLAC__StreamEncoderStateString[iEncState]);
00226 return false;
00227 }
00228 #else
00229 return false;
00230 #endif
00231 }
00232 else return false;
00233
00234 return true;
00235 }
00236
00237
00238 #ifdef USE_FLAC
00239 void clSoundSrvA::Convert (FLAC__int32 *ipDest, const void *vpSrc,
00240 long lSamples, int iBits)
00241 {
00242 long lSampleCntr;
00243
00244 if (iBits == 8)
00245 {
00246 unsigned char *ipSrc = (unsigned char *) vpSrc;
00247
00248 for (lSampleCntr = 0; lSampleCntr < lSamples; lSampleCntr++)
00249 {
00250 ipDest[lSampleCntr] = (FLAC__int32) ipSrc[lSampleCntr] - 0x80;
00251 }
00252 }
00253 else if (iBits > 8 && iBits <= 16)
00254 {
00255 signed short *ipSrc = (signed short *) vpSrc;
00256
00257 for (lSampleCntr = 0; lSampleCntr < lSamples; lSampleCntr++)
00258 {
00259 ipDest[lSampleCntr] = (FLAC__int32) ipSrc[lSampleCntr];
00260 }
00261 }
00262 else if (iBits > 16)
00263 {
00264 signed int *ipSrc = (signed int *) vpSrc;
00265
00266 for (lSampleCntr = 0; lSampleCntr < lSamples; lSampleCntr++)
00267 {
00268 ipDest[lSampleCntr] =
00269 ((FLAC__int32) ipSrc[lSampleCntr] >> (32 - iBits));
00270 }
00271 }
00272 }
00273 #endif
00274
00275
00276 clSoundSrvA::clSoundSrvA ()
00277 {
00278 bRun = true;
00279 iAudioBufSize = 0;
00280 iBlockCntr = 0;
00281 #ifdef USE_FLAC
00282 spFLACEnc = NULL;
00283 #endif
00284 Log.Open(SSA_LOGFILE);
00285 Log.Add('*', "Starting");
00286 Cfg.SetFileName(SSA_CFGFILE);
00287 }
00288
00289
00290 clSoundSrvA::~clSoundSrvA ()
00291 {
00292 #ifdef USE_FLAC
00293 if (spFLACEnc != NULL)
00294 {
00295 FLAC__stream_encoder_finish(spFLACEnc);
00296 FLAC__stream_encoder_delete(spFLACEnc);
00297 }
00298 #endif
00299 Log.Add('*', "Ending");
00300 }
00301
00302
00303 int clSoundSrvA::Main (int iArgC, char **cpArgV)
00304 {
00305 int iPort;
00306 int iSockH;
00307 void *vpAudioInRes;
00308 pthread_t ptidAudioIn;
00309 pthread_t ptidServeClient;
00310 clSockServ SServ;
00311
00312 signal(SIGINT, SigHandler);
00313 signal(SIGHUP, SigHandler);
00314 signal(SIGTERM, SigHandler);
00315 signal(SIGPIPE, SIG_IGN);
00316 signal(SIGFPE, SIG_IGN);
00317 if (iArgC >= 2)
00318 {
00319 if (strcmp(cpArgV[1], "-D"))
00320 {
00321 bDaemon = true;
00322 }
00323 else if (strcmp(cpArgV[1], "--version"))
00324 {
00325 printf("%s v%i.%i.%i\n", cpArgV[0], GLOBAL_VERSMAJ,
00326 GLOBAL_VERSMIN, GLOBAL_VERSPL);
00327 printf("Copyright (C) 2000-2002 Jussi Laako\n");
00328 return 0;
00329 }
00330 else if (strcmp(cpArgV[1], "--help"))
00331 {
00332 printf("%s [-D|--version|--help]\n\n", cpArgV[0]);
00333 printf("-D start as daemon\n");
00334 printf("--version display version information\n");
00335 printf("--help display this help\n");
00336 return 0;
00337 }
00338 }
00339 if (bDaemon)
00340 {
00341 if (fork() != 0)
00342 {
00343 exit(0);
00344 }
00345 setsid();
00346 freopen("/dev/null", "r+", stderr);
00347 freopen("/dev/null", "r+", stdin);
00348 freopen("/dev/null", "r+", stdout);
00349 }
00350 if (!Cfg.GetInt("Port", &iPort))
00351 {
00352 Log.Add('!', "\"Port\" not found from configuration file");
00353 return 1;
00354 }
00355 SServ.Bind(iPort);
00356 pthread_create(&ptidAudioIn, NULL, WrapAudioInThread, NULL);
00357 while (bRun)
00358 {
00359 if (access(SSA_SHUTDOWNFILE, F_OK) == 0)
00360 {
00361 unlink(SSA_SHUTDOWNFILE);
00362 Stop();
00363 break;
00364 }
00365 iSockH = SServ.WaitForConnect(SSA_CONNECT_TIMEOUT);
00366 if (iSockH >= 0)
00367 {
00368 pthread_create(&ptidServeClient, NULL, WrapServeClientThread,
00369 (void *) iSockH);
00370 pthread_detach(ptidServeClient);
00371 }
00372 }
00373 pthread_join(ptidAudioIn, &vpAudioInRes);
00374 if ((int) vpAudioInRes != 0) return ((int) vpAudioInRes);
00375 return 0;
00376 }
00377
00378
00379 void *clSoundSrvA::AudioInThread (void *vpParam)
00380 {
00381 int iCard;
00382 int iDevice;
00383 int iSubDevice;
00384 int iChannels;
00385 int iSampleRate;
00386 int iBits;
00387 int iSampleSize;
00388 int iFragSize = SSA_FRAG_SIZE_DEFAULT;
00389 int iFragCount = 2;
00390 int iSampleCount;
00391 int iCompress;
00392 int iErrorCode;
00393 char cpLogEntry[SSA_LOGENTRY_SIZE];
00394 #ifndef USE_ALSA05
00395 char cpDeviceId[10];
00396 #endif
00397 sigset_t sigsetThis;
00398 #ifndef BSDSYS
00399 uid_t uidCurrent;
00400 struct sched_param sSchedParam;
00401 #endif
00402 clAlloc RawBuf;
00403 clAlloc ConvBuf;
00404 #ifdef USE_ALSA05
00405 clAudioA AudioA;
00406 #else
00407 clAudioA2 AudioA;
00408 #endif
00409 clDSPOp DSP;
00410 clSoundMsg Msg;
00411
00412 sigemptyset(&sigsetThis);
00413 sigaddset(&sigsetThis, SIGPIPE);
00414 sigaddset(&sigsetThis, SIGINT);
00415 sigaddset(&sigsetThis, SIGHUP);
00416 sigaddset(&sigsetThis, SIGFPE);
00417 pthread_sigmask(SIG_BLOCK, &sigsetThis, NULL);
00418
00419 GetAudioCfg(&iCard, &iDevice, &iSubDevice, &iChannels, &iSampleRate,
00420 &iBits, &iFragSize, &iFragCount);
00421 if (!Cfg.GetInt("Compress", &iCompress))
00422 iCompress = MSG_SOUND_COMPRESS_NONE;
00423 switch (iBits)
00424 {
00425 case 8:
00426 iSampleSize = 1;
00427 break;
00428 case 16:
00429 iSampleSize = 2;
00430 break;
00431 case 24:
00432 case 32:
00433 iSampleSize = 4;
00434 break;
00435 default:
00436 sprintf(cpLogEntry, "Unsupported word length %i\n", iBits);
00437 Log.Add('!', cpLogEntry);
00438 Stop();
00439 return ((void *) 1);
00440 }
00441 sprintf(cpLogEntry, "ALSA library version %s", SND_LIB_VERSION_STR);
00442 Log.Add(' ', cpLogEntry);
00443 if (!AudioA.CardOpen(iCard))
00444 {
00445 #ifdef USE_ALSA05
00446 sprintf(cpLogEntry, "Failed to open card %i/%i", iCard,
00447 AudioA.CardGetCount());
00448 #else
00449 sprintf(cpLogEntry, "Failed to open card %i", iCard);
00450 #endif
00451 Log.Add('!', cpLogEntry);
00452 Stop();
00453 return ((void *) 1);
00454 }
00455 #ifdef USE_ALSA05
00456 sprintf(cpLogEntry, "Card %i/%i (%s) open, provides %i channels",
00457 iCard + 1, AudioA.CardGetCount(),
00458 AudioA.CardGetName(),
00459 AudioA.CardGetChannelCount());
00460 #else
00461 sprintf(cpLogEntry, "Card %i (%s) open",
00462 iCard + 1, AudioA.CardGetName(iCard));
00463 #endif
00464 Log.Add(' ', cpLogEntry);
00465 #ifdef USE_ALSA05
00466 if (!AudioA.PcmOpen(iDevice, iSubDevice, AA_MODE_RECORD))
00467 #else
00468 sprintf(cpDeviceId, "plughw:%i,%i", iCard, iDevice);
00469 if (!AudioA.PcmOpen(cpDeviceId, AA_MODE_RECORD))
00470 #endif
00471 {
00472 Log.Add('!', "Unable to open PCM device");
00473 Stop();
00474 return ((void *) 2);
00475 }
00476 sprintf(cpLogEntry, "Device: %s", AudioA.PcmGetName());
00477 Log.Add(' ', cpLogEntry);
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 #ifdef USE_ALSA05
00489 sprintf(cpLogEntry, "Request ch %i fs %i wl %i frag %i bytes",
00490 iChannels, iSampleRate, iBits, iFragSize);
00491 Log.Add(' ', cpLogEntry);
00492 if (!AudioA.PcmSetSetup(iChannels, iSampleRate, iBits, iFragSize, false))
00493 #else
00494 sprintf(cpLogEntry, "Request ch %i fs %i wl %i, %i frags of %i bytes",
00495 iChannels, iSampleRate, iBits, iFragCount, iFragSize);
00496 Log.Add(' ', cpLogEntry);
00497 if (!AudioA.PcmSetSetup(iChannels, iSampleRate, iBits,
00498 iFragSize, iFragCount))
00499 #endif
00500 {
00501 Log.Add('!', "PCM setup failed");
00502 Stop();
00503 return ((void *) 3);
00504 }
00505 iChannels = AudioA.PcmGetChannels();
00506 iSampleRate = AudioA.PcmGetSampleRate();
00507 iBits = AudioA.PcmGetBits();
00508 iFragSize = AudioA.PcmGetFragmentSize();
00509 #ifdef USE_ALSA05
00510 sprintf(cpLogEntry, "Open ch %i fs %i wl %i frag %i bytes (%s)",
00511 iChannels, iSampleRate, iBits, iFragSize,
00512 AudioA.PcmGetFormatName());
00513 #else
00514 sprintf(cpLogEntry, "Open ch %i fs %i wl %i, %i frags of %i bytes (%i)",
00515 iChannels, iSampleRate, iBits, AudioA.PcmGetFragmentCount(), iFragSize,
00516 AudioA.PcmGetBufferSize());
00517 #endif
00518 Log.Add(' ', cpLogEntry);
00519 iSampleCount = iFragSize / iSampleSize;
00520 if (iCompress == MSG_SOUND_COMPRESS_FLAC)
00521 {
00522 #ifdef USE_FLAC
00523 iAudioBufSize = iSampleCount * sizeof(FLAC__int32);
00524 #else
00525 iAudioBufSize = 0;
00526 #endif
00527 }
00528 else
00529 {
00530 iAudioBufSize = iSampleCount * sizeof(GDT);
00531 }
00532 sHdr.iChannels = iChannels;
00533 sHdr.dSampleRate = iSampleRate;
00534 sHdr.iFragmentSize = iSampleCount;
00535 sHdr.iCompress = iCompress;
00536
00537 RawBuf.Size(iFragSize);
00538 RawBuf.Lock();
00539 ConvBuf.Size(iAudioBufSize);
00540 ConvBuf.Lock();
00541 AudioBuf.Size(iAudioBufSize);
00542 AudioBuf.Lock();
00543
00544 if (iCompress)
00545 {
00546 if (!InitCompress(iChannels, iSampleRate, iBits, iSampleCount,
00547 iCompress))
00548 Stop();
00549 }
00550
00551 #ifndef BSDSYS
00552 uidCurrent = getuid();
00553 setuid(0);
00554 sSchedParam.sched_priority = sched_get_priority_min(SCHED_FIFO) +
00555 SSA_INTHREAD_PRIORITY;
00556 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sSchedParam) != 0)
00557 Log.Add('#', "Warning: Unable to set scheduling parameters");
00558 setuid(uidCurrent);
00559 #endif
00560 if (!AudioA.PcmPrepare())
00561 {
00562 Log.Add('!', "Unable to prepare PCM");
00563 Stop();
00564 return ((void *) 4);
00565 }
00566
00567
00568
00569 Log.Add(' ', "AudioIn thread running");
00570 #ifdef USE_ALSA05
00571 if (!AudioA.PcmGo())
00572 #else
00573 if (!AudioA.PcmStart())
00574 #endif
00575 {
00576 Log.Add('!', "Unable to start PCM");
00577 Stop();
00578 return ((void *) 5);
00579 }
00580 while (bRun)
00581 {
00582 #ifndef USE_ALSA05
00583 if (AudioA.PcmGetStatus() == SND_PCM_STATE_XRUN)
00584 {
00585 Log.Add('#', "Xrun detected");
00586
00587
00588
00589
00590 }
00591 #endif
00592 iErrorCode = AudioA.PcmRead(RawBuf, iFragSize);
00593 if (iErrorCode < iFragSize)
00594 {
00595 sprintf(cpLogEntry, "Error reading device: %s",
00596 snd_strerror(iErrorCode));
00597 Log.Add('!', cpLogEntry);
00598 sprintf(cpLogEntry, "Status: %s",
00599 AudioA.PcmGetStatusStr(AudioA.PcmGetStatus()));
00600 Log.Add('!', cpLogEntry);
00601
00602 Stop();
00603 return ((void *) 6);
00604 }
00605 if (iCompress == MSG_SOUND_COMPRESS_FLAC)
00606 {
00607 #ifdef USE_FLAC
00608 Convert(FLACFrame, RawBuf, iSampleCount, iBits);
00609 if (!FLAC__stream_encoder_process_interleaved(spFLACEnc,
00610 FLACFrame, iSampleCount / iChannels))
00611 {
00612 Log.Add('!', "Compression error");
00613 Stop();
00614 return ((void *) 2);
00615 }
00616 #endif
00617 }
00618 else
00619 {
00620 switch (iBits)
00621 {
00622 case 8:
00623 DSP.Convert((GDT *) ConvBuf, (unsigned char *) RawBuf,
00624 iSampleCount);
00625 break;
00626 case 16:
00627 DSP.Convert((GDT *) ConvBuf, (signed short *) RawBuf,
00628 iSampleCount, false);
00629 break;
00630 case 24:
00631 DSP.Convert((GDT *) ConvBuf, (signed int *) RawBuf,
00632 iSampleCount, true);
00633 break;
00634 case 32:
00635 DSP.Convert((GDT *) ConvBuf, (signed int *) RawBuf,
00636 iSampleCount, false);
00637 break;
00638 default:
00639 sprintf(cpLogEntry, "Fatal error @%s~%i", __FILE__, __LINE__);
00640 Log.Add('!', cpLogEntry);
00641 Stop();
00642 return ((void *) 2);
00643 }
00644 #ifndef USE_RWLOCK
00645 MtxAudio.Wait();
00646 #else
00647 RWLAudio.WaitWrite();
00648 #endif
00649 Msg.SetData(AudioBuf, (GDT *) ConvBuf, iSampleCount);
00650 iBlockCntr++;
00651 CndAudio.NotifyAll();
00652 #ifndef USE_RWLOCK
00653 MtxAudio.Release();
00654 #else
00655 RWLAudio.Release();
00656 #endif
00657 }
00658 }
00659 Log.Add(' ', "AudioIn thread ending");
00660 return ((void *) 0);
00661 }
00662
00663
00664 void *clSoundSrvA::ServeClientThread (void *vpParam)
00665 {
00666 bool bConnected = true;
00667 int iFragBufCount;
00668 int iLocalBlockCntr;
00669 char cpLogEntry[SSA_LOGENTRY_SIZE];
00670 char cpHdrMsg[GLOBAL_HEADER_LEN];
00671 socklen_t iAddrLen;
00672 struct sockaddr_in sPeerAddr;
00673 sigset_t sigsetThis;
00674 #ifndef BSDSYS
00675 uid_t uidCurrent;
00676 struct sched_param sSchedParam;
00677 #endif
00678 clAlloc OutBuf(iAudioBufSize);
00679 clSoundMsg Msg;
00680 clSockOp SOp((int) vpParam);
00681
00682 sigemptyset(&sigsetThis);
00683 sigaddset(&sigsetThis, SIGPIPE);
00684 sigaddset(&sigsetThis, SIGINT);
00685 sigaddset(&sigsetThis, SIGHUP);
00686 pthread_sigmask(SIG_BLOCK, &sigsetThis, NULL);
00687
00688 if (!Cfg.GetInt("BufferFrags", &iFragBufCount))
00689 iFragBufCount = SSA_SOCKET_BUF_FRAGS;
00690 SOp.SetSendBufSize(iFragBufCount * iAudioBufSize);
00691 SOp.DisableNagle();
00692 SOp.SetTypeOfService(IPTOS_LOWDELAY);
00693 iAddrLen = sizeof(sPeerAddr);
00694 SOp.GetPeerName((struct sockaddr *) &sPeerAddr, &iAddrLen);
00695 sprintf(cpLogEntry, "Client connected from %s:%i",
00696 inet_ntoa(sPeerAddr.sin_addr), ntohs(sPeerAddr.sin_port));
00697 Log.Add('+', cpLogEntry);
00698 Msg.SetStart(cpHdrMsg, &sHdr);
00699 if (SOp.WriteN(cpHdrMsg, GLOBAL_HEADER_LEN) < GLOBAL_HEADER_LEN)
00700 bConnected = false;
00701 OutBuf.Lock();
00702 if (sHdr.iCompress)
00703 {
00704 if (SOp.WriteN(CompHead, CompHead.GetSize()) < CompHead.GetSize())
00705 bConnected = false;
00706 }
00707
00708 #ifndef BSDSYS
00709 uidCurrent = getuid();
00710 setuid(0);
00711 sSchedParam.sched_priority = sched_get_priority_min(SCHED_FIFO) +
00712 SSA_OUTTHREAD_PRIORITY;
00713 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &sSchedParam) != 0)
00714 Log.Add('#', "Warning: Unable to set scheduling parameters");
00715 setuid(uidCurrent);
00716 #endif
00717
00718 iLocalBlockCntr = iBlockCntr;
00719 while (bRun && bConnected)
00720 {
00721 MtxAudio.Wait();
00722 CndAudio.Wait(MtxAudio.GetPtr());
00723 #ifdef USE_RWLOCK
00724 MtxAudio.Release();
00725 RWLAudio.WaitRead();
00726 #endif
00727 if (iAudioBufSize > OutBuf.GetSize())
00728 {
00729 OutBuf.UnLock();
00730 OutBuf.Size(iAudioBufSize);
00731 OutBuf.Lock();
00732 }
00733 memcpy(OutBuf, AudioBuf, iAudioBufSize);
00734 iLocalBlockCntr++;
00735 if (iLocalBlockCntr != iBlockCntr)
00736 {
00737 printf("soundsrva: %i blocks lost\n",
00738 iBlockCntr - iLocalBlockCntr);
00739 iLocalBlockCntr = iBlockCntr;
00740 }
00741 #ifndef USE_RWLOCK
00742 MtxAudio.Release();
00743 #else
00744 RWLAudio.Release();
00745 #endif
00746 if (SOp.WriteN(OutBuf, iAudioBufSize) < iAudioBufSize)
00747 bConnected = false;
00748 }
00749 sprintf(cpLogEntry, "Client from %s:%i disconnected",
00750 inet_ntoa(sPeerAddr.sin_addr), ntohs(sPeerAddr.sin_port));
00751 Log.Add('-', cpLogEntry);
00752 return NULL;
00753 }
00754
00755
00756 #ifdef USE_FLAC
00757
00758 FLAC__StreamEncoderWriteStatus clSoundSrvA::FLACWrite (
00759 const FLAC__StreamEncoder *spFLACEnc, const FLAC__byte *cpBuffer,
00760 unsigned uiBytes, unsigned uiSamples, unsigned uiCurrFrame)
00761 {
00762 static bool bFirst = true;
00763 FLAC__StreamEncoderWriteStatus iEncStatus =
00764 FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
00765
00766 #ifndef USE_RWLOCK
00767 MtxAudio.Wait();
00768 #else
00769 RWLAudio.WaitWrite();
00770 #endif
00771 if (bFirst)
00772 {
00773 CompHead.Size(uiBytes);
00774 memcpy(CompHead, cpBuffer, uiBytes);
00775 bFirst = false;
00776 }
00777 else
00778 {
00779 iAudioBufSize = uiBytes;
00780 if (iAudioBufSize > AudioBuf.GetSize())
00781 {
00782 AudioBuf.UnLock();
00783 AudioBuf.Size(iAudioBufSize);
00784 AudioBuf.Lock();
00785 }
00786 memcpy(AudioBuf, cpBuffer, iAudioBufSize);
00787 iBlockCntr++;
00788 CndAudio.NotifyAll();
00789 }
00790 #ifndef USE_RWLOCK
00791 MtxAudio.Release();
00792 #else
00793 RWLAudio.Release();
00794 #endif
00795 return iEncStatus;
00796 }
00797
00798
00799 void clSoundSrvA::FLACMetaData (
00800 const FLAC__StreamEncoder *spFLACEnc,
00801 const FLAC__StreamMetadata *spFLACMetaData)
00802 {
00803 }
00804
00805 #endif