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