Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

SoundSrv2.cc

Go to the documentation of this file.
00001 /*
00002 
00003     SoundServer2
00004     Copyright (C) 2000-2002 Jussi Laako
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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);  // non-default
00195         FLAC__stream_encoder_set_do_exhaustive_model_search(spFLACEnc,
00196             1);  // non-default
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

Generated on Sun Oct 26 19:11:22 2003 for HASAS by doxygen 1.3.3