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

SoundSrvA.cc

Go to the documentation of this file.
00001 /*
00002 
00003     SoundServer for ALSA
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 <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);  // non-default
00203         FLAC__stream_encoder_set_do_exhaustive_model_search(spFLACEnc,
00204             1);  // non-default
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     /*snd_pcm_channel_info_t *spChInfo;
00480     spChInfo = (snd_pcm_channel_info_t *) AudioA.PcmGetChannelInfo();
00481     fprintf(stderr, 
00482         "fs %i-%i, voices %i-%i, maxbuf %i, frag %i-%i\n",
00483         spChInfo->min_rate, spChInfo->max_rate,
00484         spChInfo->min_voices, spChInfo->max_voices,
00485         spChInfo->buffer_size,
00486         spChInfo->min_fragment_size, spChInfo->max_fragment_size);*/
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     //fprintf(stderr, "ts: %i\n", AudioA.PcmGetTransferSize());
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)  // or _DRAINING?
00584         {
00585             Log.Add('#', "Xrun detected");
00586             /*if (!AudioA.PcmStart())
00587             {
00588                 Log.Add('!', "Failed to restart device after Xrun!");
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             //Log.Add('!', "Error reading device");
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

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