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

FileSrv.cc

Go to the documentation of this file.
00001 /*
00002 
00003     File replay server
00004     Copyright (C) 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 <stdlib.h>
00024 #include <string.h>
00025 #include <signal.h>
00026 #include <unistd.h>
00027 #include <errno.h>
00028 #include <math.h>
00029 #include <float.h>
00030 #include <time.h>
00031 #include <sys/time.h>
00032 
00033 #include <gtk/gtk.h>
00034 
00035 #include <DynThreads.hh>
00036 
00037 #include "FileSrv.hh"
00038 
00039 
00040 static const char *cpWindowTxt = "File server";
00041 static const char *cpFileSelectTxt = "Select file";
00042 // Table1
00043 static const char *cpFileTxt = "Filename";
00044 static const char *cpBrowseTxt = "Browse...";
00045 // Table2
00046 static const char *cpPlayStopTxt[] = { "Play", "Stop" };
00047 static const char *cpPositionTxt = "Position";
00048 
00049 
00050 clFileSrv FileSrv;
00051 clDynThreads<clFileSrv> FileSrvThreads(FileSrv);
00052 
00053 
00054 int main (int argc, char *argv[])
00055 {
00056     signal(SIGPIPE, SIG_IGN);
00057     signal(SIGFPE, SIG_IGN);
00058     return FileSrv.Main(&argc, &argv);
00059 }
00060 
00061 
00062 gboolean WrapOnDelete (GtkWidget *gwSender, GdkEvent *geEvent, gpointer gpData)
00063 {
00064     return FileSrv.OnDelete(gwSender, geEvent, gpData);
00065 }
00066 
00067 
00068 void WrapOnFileSelectOkClick (GtkButton *gbSender, gpointer gpData)
00069 {
00070     FileSrv.OnFileSelectOkClick(gbSender, gpData);
00071 }
00072 
00073 
00074 void WrapOnFileSelectCancelClick (GtkButton *gbSender, gpointer gpData)
00075 {
00076     FileSrv.OnFileSelectCancelClick(gbSender, gpData);
00077 }
00078 
00079 
00080 void WrapOnBrowseClick (GtkButton *gbSender, gpointer gpData)
00081 {
00082     FileSrv.OnBrowseClick(gbSender, gpData);
00083 }
00084 
00085 
00086 void WrapOnPlayStopToggle (GtkToggleButton *gtbSender, gpointer gpData)
00087 {
00088     FileSrv.OnPlayStopToggle(gtbSender, gpData);
00089 }
00090 
00091 
00092 void WrapOnPositionChange (GtkAdjustment *gaSender, gpointer gpData)
00093 {
00094     FileSrv.OnPositionChange(gaSender, gpData);
00095 }
00096 
00097 
00098 #ifdef USE_FLAC
00099 
00100 FLAC__StreamDecoderWriteStatus WrapFLACWriteCB (
00101     const FLAC__FileDecoder *flacDecoderInst, const FLAC__Frame *flacFrame,
00102     const FLAC__int32 * const flacBuffer[], void *vpUserData)
00103 {
00104     clFileSrv *FileSrvInst = (clFileSrv *) vpUserData;
00105     
00106     return FileSrvInst->FLACWriteCB(flacDecoderInst, flacFrame, flacBuffer);
00107 }
00108 
00109 
00110 void WrapFLACMetadataCB (const FLAC__FileDecoder *flacDecoderInst,
00111     const FLAC__StreamMetadata *flacMetadata, void *vpUserData)
00112 {
00113     clFileSrv *FileSrvInst = (clFileSrv *) vpUserData;
00114     
00115     FileSrvInst->FLACMetadataCB(flacDecoderInst, flacMetadata);
00116 }
00117 
00118 
00119 void WrapFLACErrorCB (const FLAC__FileDecoder *flacDecoderInst,
00120     FLAC__StreamDecoderErrorStatus flacError, void *vpUserData)
00121 {
00122     clFileSrv *FileSrvInst = (clFileSrv *) vpUserData;
00123 
00124     FileSrvInst->FLACErrorCB(flacDecoderInst, flacError);
00125 }
00126 
00127 #endif
00128 
00129 
00130 bool clFileSrv::Build ()
00131 {
00132     gwWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00133     gtk_window_set_title(GTK_WINDOW(gwWindow), cpWindowTxt);
00134     // shrink, grow, auto-shrink
00135     gtk_window_set_policy(GTK_WINDOW(gwWindow), TRUE, TRUE, FALSE);
00136     // homogenous, spacing
00137     gwVBox = gtk_vbox_new(FALSE, FS_WSPACING);
00138     gtk_container_add(GTK_CONTAINER(gwWindow), gwVBox);
00139     gtk_widget_show(gwVBox);
00140 
00141     gwFileSelect = gtk_file_selection_new(cpFileSelectTxt);
00142 
00143     if (!BuildTable1()) return false;
00144     if (!BuildTable2()) return false;
00145 
00146     if (!ConnectSignals()) return false;
00147 
00148     gtk_widget_show(gwWindow);
00149 
00150     return true;
00151 }
00152 
00153 
00154 bool clFileSrv::BuildTable1 ()
00155 {
00156     gwTable1 = gtk_table_new(2, 2, FALSE);
00157     gtk_box_pack_start(GTK_BOX(gwVBox), gwTable1, FALSE, FALSE, 0);
00158     gtk_widget_show(gwTable1);
00159 
00160     // Label & Entry: filename
00161     gwLFile = gtk_label_new(cpFileTxt);
00162     gtk_table_attach(GTK_TABLE(gwTable1), gwLFile,
00163         0, 1,
00164         0, 1,
00165         (GtkAttachOptions) (GTK_EXPAND|GTK_SHRINK|GTK_FILL),
00166         (GtkAttachOptions) 0,
00167         FS_WSPACING / 2, FS_WSPACING / 2);
00168     gtk_label_set_justify(GTK_LABEL(gwLFile), GTK_JUSTIFY_LEFT);
00169     gtk_widget_show(gwLFile);
00170     gwEFile = gtk_entry_new();
00171     gtk_table_attach(GTK_TABLE(gwTable1), gwEFile,
00172         0, 1,
00173         1, 2,
00174         (GtkAttachOptions) (GTK_EXPAND|GTK_SHRINK|GTK_FILL),
00175         (GtkAttachOptions) 0,
00176         FS_WSPACING / 2, FS_WSPACING / 2);
00177     gtk_widget_show(gwEFile);
00178 
00179     // Button: browse
00180     gwBBrowse = gtk_button_new_with_label(cpBrowseTxt);
00181     gtk_table_attach(GTK_TABLE(gwTable1), gwBBrowse,
00182         1, 2,
00183         1, 2,
00184         (GtkAttachOptions) 0,
00185         (GtkAttachOptions) 0,
00186         FS_WSPACING / 2, FS_WSPACING / 2);
00187     gtk_widget_show(gwBBrowse);
00188 
00189     return true;
00190 }
00191 
00192 
00193 bool clFileSrv::BuildTable2 ()
00194 {
00195     gwTable2 = gtk_table_new(2, 2, FALSE);
00196     gtk_box_pack_start(GTK_BOX(gwVBox), gwTable2, FALSE, FALSE, 0);
00197     gtk_widget_show(gwTable2);
00198 
00199     // ToggleButton: play / stop
00200     gwTBPlayStop = gtk_toggle_button_new_with_label(cpPlayStopTxt[0]);
00201     gtk_table_attach(GTK_TABLE(gwTable2), gwTBPlayStop,
00202         0, 1,
00203         1, 2,
00204         (GtkAttachOptions) 0,
00205         (GtkAttachOptions) 0,
00206         FS_WSPACING / 2, FS_WSPACING / 2);
00207     gtk_widget_show(gwTBPlayStop);
00208     
00209     // Label & Adjustment & HScale: position
00210     gwLPosition = gtk_label_new(cpPositionTxt);
00211     gtk_table_attach(GTK_TABLE(gwTable2), gwLPosition,
00212         1, 2,
00213         0, 1,
00214         (GtkAttachOptions) (GTK_EXPAND|GTK_SHRINK|GTK_FILL),
00215         (GtkAttachOptions) 0,
00216         FS_WSPACING / 2, FS_WSPACING / 2);
00217     gtk_label_set_justify(GTK_LABEL(gwLPosition), GTK_JUSTIFY_LEFT);
00218     gtk_widget_show(gwLPosition);
00219     gaPosition = gtk_adjustment_new(0, 0, 1, 
00220         1.0 / 60.0, 1.0 / 60.0, 1.0 / 60.0);
00221     gwHSPosition = gtk_hscale_new(GTK_ADJUSTMENT(gaPosition));
00222     gtk_table_attach(GTK_TABLE(gwTable2), gwHSPosition,
00223         1, 2,
00224         1, 2,
00225         (GtkAttachOptions) (GTK_EXPAND|GTK_SHRINK|GTK_FILL),
00226         (GtkAttachOptions) 0,
00227         FS_WSPACING / 2, FS_WSPACING / 2);
00228     gtk_scale_set_digits(GTK_SCALE(gwHSPosition), 2);
00229     gtk_scale_set_draw_value(GTK_SCALE(gwHSPosition), TRUE);
00230     gtk_widget_show(gwHSPosition);
00231 
00232     return true;
00233 }
00234 
00235 
00236 bool clFileSrv::ConnectSignals ()
00237 {
00238     //int iWidgetCntr;
00239 
00240     gtk_signal_connect(GTK_OBJECT(gwWindow), "delete-event",
00241         GTK_SIGNAL_FUNC(WrapOnDelete), NULL);
00242 
00243     gtk_signal_connect(
00244         GTK_OBJECT(GTK_FILE_SELECTION(gwFileSelect)->ok_button),
00245         "clicked",
00246         GTK_SIGNAL_FUNC(WrapOnFileSelectOkClick), NULL);
00247     gtk_signal_connect(
00248         GTK_OBJECT(GTK_FILE_SELECTION(gwFileSelect)->cancel_button),
00249         "clicked",
00250         GTK_SIGNAL_FUNC(WrapOnFileSelectCancelClick), NULL);
00251     gtk_signal_connect(GTK_OBJECT(gwBBrowse), "clicked",
00252         GTK_SIGNAL_FUNC(WrapOnBrowseClick), NULL);
00253     gtk_signal_connect(GTK_OBJECT(gwTBPlayStop), "toggled",
00254         GTK_SIGNAL_FUNC(WrapOnPlayStopToggle), NULL);
00255 
00256     /*gtk_signal_connect(gaPosition, "value-changed",
00257         GTK_SIGNAL_FUNC(WrapOnPositionChange), NULL);*/
00258 
00259     return true;
00260 }
00261 
00262 
00263 double clFileSrv::GetTime ()
00264 {
00265     double dTime;
00266 #   if (defined(linux) || defined(BSDSYS))
00267     struct timespec sTimeSpec;
00268     
00269     clock_gettime(CLOCK_REALTIME, &sTimeSpec);
00270     dTime = (double) (sTimeSpec.tv_sec - lEpoch);
00271     dTime += (double) sTimeSpec.tv_nsec / 1000000000.0;
00272 #   else
00273     struct timeval sTimeVal;
00274     
00275     gettimeofday(&sTimeVal, NULL);
00276     dTime = (double) (sTimeVal.tv_sec - lEpoch);
00277     dTime += (double) sTimeVal.tv_usec / 1000000.0;
00278 #   endif
00279     return dTime;
00280 }
00281 
00282 
00283 void clFileSrv::ShortSleep (long lSleepTime)
00284 {
00285     if (lSleepTime <= 0) return;
00286 #   if (defined(linux) || defined(BSDSYS))
00287     struct timeval sTimeout;
00288     
00289     sTimeout.tv_sec = lSleepTime / 1000000;
00290     sTimeout.tv_usec = lSleepTime % 1000000;
00291     select(0, NULL, NULL, NULL, &sTimeout);
00292 #   else
00293     int iEC = 0;
00294     struct timespec sTimeSpec;
00295 
00296     sTimeSpec.tv_sec = lSleepTime / 1000000;
00297     sTiemSpec.tv_nsec = lSleepTime % 1000000 * 1000;
00298     do
00299     {
00300         if (nanosleep(&sTimeSpec, &sTimeSpec) < 0)
00301             iEC = errno;
00302     } while (iEC == EINTR);
00303 #   endif
00304 }
00305 
00306 
00307 #ifdef USE_FLAC
00308 
00309 bool clFileSrv::OpenFLAC (const char *cpFilename)
00310 {
00311     flacDecoder = FLAC__file_decoder_new();
00312 
00313     FLAC__file_decoder_set_filename(flacDecoder, cpFilename);
00314     FLAC__file_decoder_set_write_callback(flacDecoder, WrapFLACWriteCB);
00315     FLAC__file_decoder_set_metadata_callback(flacDecoder, WrapFLACMetadataCB);
00316     FLAC__file_decoder_set_error_callback(flacDecoder, WrapFLACErrorCB);
00317     FLAC__file_decoder_set_client_data(flacDecoder, (void *) this);
00318     
00319     if (FLAC__file_decoder_init(flacDecoder) != FLAC__FILE_DECODER_OK)
00320     {
00321         CloseFLAC();
00322         return false;
00323     }
00324 
00325     if (!FLAC__file_decoder_process_until_end_of_metadata(flacDecoder))
00326     {
00327         g_print("FLAC: warning, unable to process metadata!\n");
00328     }
00329 
00330     return true;
00331 }
00332 
00333 
00334 void clFileSrv::CloseFLAC ()
00335 {
00336     if (flacDecoder != NULL)
00337     {
00338         if (FLAC__file_decoder_get_state(flacDecoder) !=
00339             FLAC__FILE_DECODER_UNINITIALIZED)
00340             FLAC__file_decoder_finish(flacDecoder);
00341         FLAC__file_decoder_delete(flacDecoder);
00342         flacDecoder = NULL;
00343     }
00344 }
00345 
00346 #endif
00347 
00348 
00349 clFileSrv::clFileSrv ()
00350 {
00351     bRun = true;
00352     sndfileFile = NULL;
00353     lEpoch = time(NULL);
00354 #   ifdef USE_FLAC
00355     flacDecoder = NULL;
00356 #   endif
00357 }
00358 
00359 
00360 clFileSrv::~clFileSrv ()
00361 {
00362 }
00363 
00364 
00365 int clFileSrv::Main (int *ipArgC, char ***cppaArgV)
00366 {
00367     int iReaderH;
00368     int iServerH;
00369     int iFragSize;
00370     int iServerPort;
00371 
00372     g_print("%s v%i.%i.%i\n", cpWindowTxt,
00373         FS_VER_MAJ, FS_VER_MIN, FS_VER_PL);
00374     g_print("Copyright (C) 2002 Jussi Laako\n\n");
00375     g_print("Gtk+ version %i.%i.%i\n", gtk_major_version, gtk_minor_version,
00376         gtk_micro_version);
00377     g_print("Locale set to %s\n", gtk_set_locale());
00378     gtk_init(ipArgC, cppaArgV);
00379 
00380     Cfg.SetFileName(FS_CFGFILE);
00381     if (!Cfg.GetInt("FragSize", &iFragSize))
00382         iFragSize = FS_FRAG_SIZE_DEFAULT;
00383     if (!Cfg.GetInt("Port", &iServerPort))
00384         iServerPort = FS_DEFAULT_PORT;
00385 
00386     if (!Build()) return 1;
00387 
00388     AudioBlock.Size(iFragSize);
00389     AudioBlock.Lock();
00390     iFragSize /= sizeof(GDT);
00391 
00392     iReaderH = FileSrvThreads.Create(&clFileSrv::ReaderThread, 
00393         (void *) iFragSize);
00394     iServerH = FileSrvThreads.Create(&clFileSrv::ServerThread, 
00395         (void *) iServerPort);
00396 
00397     gtk_main();
00398 
00399     FileSrvThreads.Wait(iServerH);
00400     FileSrvThreads.Wait(iReaderH);
00401 
00402     return 0;
00403 }
00404 
00405 
00406 gboolean clFileSrv::OnDelete (GtkWidget *gwSender, GdkEvent *geEvent,
00407     gpointer gpData)
00408 {
00409     bRun = false;
00410     gtk_main_quit();
00411     return TRUE;
00412 }
00413 
00414 
00415 void clFileSrv::OnFileSelectOkClick (GtkButton *gbSender, gpointer gpData)
00416 {
00417     const gchar *cpFilename;
00418 
00419     cpFilename = 
00420         gtk_file_selection_get_filename(GTK_FILE_SELECTION(gwFileSelect));
00421     if (access(cpFilename, F_OK) != 0)
00422     {
00423         gtk_file_selection_complete(GTK_FILE_SELECTION(gwFileSelect), 
00424             cpFilename);
00425         return;
00426     }
00427     gtk_entry_set_text(GTK_ENTRY(gwEFile), cpFilename);
00428     gtk_widget_hide(gwFileSelect);
00429 }
00430 
00431 
00432 void clFileSrv::OnFileSelectCancelClick (GtkButton *gbSender, gpointer gpData)
00433 {
00434     gtk_widget_hide(gwFileSelect);
00435 }
00436 
00437 
00438 void clFileSrv::OnBrowseClick (GtkButton *gbSender, gpointer gpData)
00439 {
00440     gtk_widget_show(gwFileSelect);
00441 }
00442 
00443 
00444 void clFileSrv::OnPlayStopToggle (GtkToggleButton *gtbSender, gpointer gpData)
00445 {
00446     if (gtk_toggle_button_get_active(gtbSender))
00447     {
00448         const gchar *cpFilename = gtk_entry_get_text(GTK_ENTRY(gwEFile));
00449 
00450         MtxAudio.Wait();
00451         if (sndfileFile != NULL)
00452             sf_close(sndfileFile);
00453         if (strlen(cpFilename) > 4)
00454         {
00455             if (strcmp(&cpFilename[strlen(cpFilename) - 4], "flac") == 0)
00456             {
00457 #               ifdef USE_FLAC
00458                 CloseFLAC();
00459                 if (!OpenFLAC(cpFilename))
00460                     g_print("FLAC: open failed\n");
00461 #               else
00462                 g_print("FLAC files are not supported by this compile!\n");
00463 #               endif                
00464             }
00465             else
00466             {
00467                 sndfileFile = sf_open(cpFilename, SFM_READ, &sFileInfo);
00468                 if (sndfileFile != NULL)
00469                 {
00470                     long lSamples = sf_seek(sndfileFile, 0, SEEK_END);
00471                     sf_seek(sndfileFile, 0, SEEK_SET);
00472                     double dLength = (double) lSamples /
00473                         (double) sFileInfo.samplerate;
00474                     dLength /= 60.0;
00475                     g_print("File length %.2f minutes\n", dLength);
00476                     GTK_ADJUSTMENT(gaPosition)->upper = dLength;
00477                     gtk_adjustment_changed(GTK_ADJUSTMENT(gaPosition));
00478                     gtk_adjustment_set_value(GTK_ADJUSTMENT(gaPosition), 0);
00479                 }
00480                 else g_print("sf_open_read() failed\n");
00481                 if (!sf_command(sndfileFile, SFC_SET_NORM_DOUBLE, NULL, 
00482                     SF_TRUE))
00483                 {
00484                     g_print("sf_command(SFC_SET_NORM_DOUBLE) failed\n");
00485                 }
00486             }
00487         }
00488         MtxAudio.Release();
00489     }
00490     else
00491     {
00492         MtxAudio.Wait();
00493         if (sndfileFile != NULL)
00494             sf_close(sndfileFile);
00495         sndfileFile = NULL;
00496 #       ifdef USE_FLAC
00497         CloseFLAC();
00498 #       endif
00499         MtxAudio.Release();
00500     }
00501 }
00502 
00503 
00504 void clFileSrv::OnPositionChange (GtkAdjustment *gaSender, gpointer gpData)
00505 {
00506 }
00507 
00508 
00509 void *clFileSrv::ReaderThread (void *vpParam)
00510 {
00511     int iFragSize = (int) vpParam;
00512     int iBlockCntr;
00513     int iSampleCntr;
00514     long lSleepTime;
00515     double dStartTime;
00516     double dFrameTime;
00517     double *dpFileBlock;
00518     GDT *fpAudioBlock;
00519     clAlloc FileBlock;
00520 
00521     g_print("Reader running\n");
00522     dpFileBlock = (double *) FileBlock.Size(iFragSize * sizeof(double));
00523     FileBlock.Lock();
00524     fpAudioBlock = AudioBlock;
00525 
00526     #ifndef BSDSYS
00527     FileSrvThreads.SetSched(FileSrvThreads.Self(), 
00528         SCHED_FIFO, FS_INTHREAD_PRIORITY);
00529     #endif
00530 
00531     iBlockCntr = 0;
00532     dStartTime = GetTime();
00533     while (bRun)
00534     {
00535         MtxAudio.Wait();
00536 #       ifdef USE_FLAC
00537         if (sndfileFile == NULL && flacDecoder == NULL)
00538 #       else
00539         if (sndfileFile == NULL)
00540 #       endif
00541         {
00542             MtxAudio.Release();
00543             ShortSleep(100);
00544             iBlockCntr = 0;
00545             dStartTime = GetTime();
00546             continue;
00547         }
00548         if (sndfileFile != NULL)
00549         {
00550             if (sf_read_double(sndfileFile, dpFileBlock, 
00551                 (sf_count_t) iFragSize) < (sf_count_t) iFragSize)
00552             {
00553                 g_print("At EOF, starting over\n");
00554                 sf_seek(sndfileFile, 0, SEEK_SET);
00555                 iBlockCntr = 0;
00556                 dStartTime = GetTime();
00557                 MtxAudio.Release();
00558                 continue;
00559             }
00560         }
00561 #       ifdef USE_FLAC
00562         if (flacDecoder != NULL)
00563         {
00564             while (!StreamBuf.Get(dpFileBlock, iFragSize))
00565             {
00566                 if (!FLAC__file_decoder_process_single(flacDecoder))
00567                 {
00568                     g_print("FLAC: process single failed, EOF?\n");
00569                     CloseFLAC();
00570                     MtxAudio.Release();
00571                     continue;
00572                 }
00573             }
00574         }
00575 #       endif
00576         dFrameTime = dStartTime + (double) iBlockCntr * 
00577             ((double) (iFragSize / sFileInfo.channels) / 
00578             (double) sFileInfo.samplerate);
00579         MtxAudio.Release();
00580         // we truncate here, because system sleeps this time _minimum_
00581         lSleepTime = (long) ((dFrameTime - GetTime()) * 1000000.0);
00582         /*printf("sleep time %li  time delta %f us (%f - %f)\n", 
00583             lSleepTime, (dFrameTime - GetTime()) * 1000000.0,
00584             dFrameTime, dStartTime);*/
00585         ShortSleep(lSleepTime);
00586         MtxAudio.Wait();
00587         gettimeofday(&sTimeStamp, NULL);
00588         for (iSampleCntr = 0; iSampleCntr < iFragSize; iSampleCntr++)
00589             fpAudioBlock[iSampleCntr] = (GDT) dpFileBlock[iSampleCntr];
00590         CndReady.NotifyAll();
00591         MtxAudio.Release();
00592         iBlockCntr++;
00593 
00594         if (iBlockCntr % 100 == 0)
00595         {
00596             gtk_adjustment_set_value(GTK_ADJUSTMENT(gaPosition), 
00597                 (dFrameTime - dStartTime) / 60.0);
00598         }
00599     }
00600     // wake up all serveclients
00601     CndReady.NotifyAll();
00602     g_print("Reader stopping\n");
00603     
00604     return NULL;
00605 }
00606 
00607 
00608 void *clFileSrv::ServerThread (void *vpParam)
00609 {
00610     int iPort;
00611     int iSockH;
00612     clSockServ SServ;
00613 
00614     g_print("Server running\n");
00615     iPort = (int) vpParam;
00616     SServ.Bind((unsigned short) iPort);
00617     while (bRun)
00618     {
00619         iSockH = SServ.WaitForConnect(FS_ACCEPT_TIMEOUT);
00620         if (iSockH >= 0)
00621         {
00622             FileSrvThreads.Create(&clFileSrv::ServeClientThread,
00623                 (void *) iSockH);
00624         }
00625     }
00626     g_print("Server stopping\n");
00627     
00628     return NULL;
00629 }
00630 
00631 
00632 void *clFileSrv::ServeClientThread (void *vpParam)
00633 {
00634     long lBlockSize;
00635     struct timeval sLTimeStamp;
00636     stSoundStart sHdr;
00637     clAlloc LAudioBlock;
00638     clAlloc MsgBuf;
00639     clSockOp SOp((int) vpParam);
00640     clSoundMsg Msg;
00641 
00642     g_print("Client connected\n");
00643 
00644     MtxAudio.Wait();
00645     LAudioBlock.Size(AudioBlock.GetSize());
00646     lBlockSize = AudioBlock.GetSize() / sizeof(GDT);
00647     sHdr.iChannels = sFileInfo.channels;
00648     sHdr.dSampleRate = sFileInfo.samplerate;
00649     sHdr.iFragmentSize = lBlockSize;
00650     sHdr.iCompress = MSG_SOUND_COMPRESS_NONE;
00651     MtxAudio.Release();
00652     
00653     MsgBuf.Size(GLOBAL_HEADER_LEN + LAudioBlock.GetSize());
00654     Msg.SetStart(MsgBuf, &sHdr);
00655     if (SOp.WriteN(MsgBuf, GLOBAL_HEADER_LEN) <= 0)
00656     {
00657         g_print("Error sending header!\n");
00658         return NULL;
00659     }
00660 
00661     if (!SOp.DisableNagle())
00662     {
00663         g_warning("Failed to disable TCP Nagle algorithm.");
00664     }
00665     if (!SOp.SetTypeOfService(IPTOS_LOWDELAY))
00666     {
00667         g_warning("Unable to set type-of-service flag.");
00668     }
00669 
00670     #ifndef BSDSYS
00671     FileSrvThreads.SetSched(FileSrvThreads.Self(), 
00672         SCHED_FIFO, FS_OUTTHREAD_PRIORITY);
00673     #endif
00674 
00675     while (bRun)
00676     {
00677         MtxAudio.Wait();
00678         CndReady.Wait(MtxAudio.GetPtr());
00679 
00680         memcpy(&sLTimeStamp, &sTimeStamp, sizeof(sTimeStamp));
00681         memcpy(LAudioBlock, AudioBlock, AudioBlock.GetSize());
00682 
00683         MtxAudio.Release();
00684 
00685         //Msg.SetData(MsgBuf, &sLTimeStamp, (GDT *) LAudioBlock, lBlockSize);
00686         Msg.SetData(MsgBuf, (GDT *) LAudioBlock, lBlockSize);
00687         //if (SOp.WriteN(MsgBuf, MsgBuf.GetSize()) <= 0) break;
00688         if (SOp.WriteN(MsgBuf, lBlockSize * sizeof(GDT)) <= 0) break;
00689     }
00690     g_print("Client disconnected\n");
00691     
00692     return NULL;
00693 }
00694 
00695 
00696 #ifdef USE_FLAC
00697 
00698 FLAC__StreamDecoderWriteStatus clFileSrv::FLACWriteCB (
00699     const FLAC__FileDecoder *flacDecoderInst, const FLAC__Frame *flacFrame,
00700     const FLAC__int32 * const flacBuffer[])
00701 {
00702     int iBits;
00703     int iSamples;
00704     int iSampleCntr;
00705     int iChannels;
00706     int iChannelCntr;
00707     double dScale;
00708     double *dpConvBuf;
00709 
00710     iBits = flacFrame->header.bits_per_sample;
00711     iSamples = flacFrame->header.blocksize;
00712     iChannels = flacFrame->header.channels;
00713     sFileInfo.samplerate = flacFrame->header.sample_rate;
00714     sFileInfo.channels = flacFrame->header.channels;
00715 
00716     /*printf("FLAC: process %i samples for %i channels\n",
00717         iSamples, iChannels);*/
00718 
00719     dScale = 1.0 / pow(2.0, iBits - 1);
00720     dpConvBuf = (double *) ConvBuf.Size(iSamples * iChannels * sizeof(double));
00721     for (iChannelCntr = 0; iChannelCntr < iChannels; iChannelCntr++)
00722     {
00723         for (iSampleCntr = 0; iSampleCntr < iSamples; iSampleCntr++)
00724         {
00725             dpConvBuf[iSampleCntr * iChannels + iChannelCntr] = (double)
00726                 flacBuffer[iChannelCntr][iSampleCntr] * dScale;
00727         }
00728     }
00729     StreamBuf.Put(dpConvBuf, iSamples * iChannels);
00730 
00731     // FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
00732     return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
00733 }
00734 
00735 
00736 void clFileSrv::FLACMetadataCB (const FLAC__FileDecoder *flacDecoderInst,
00737     const FLAC__StreamMetadata *flacMetadata)
00738 {
00739     g_print("FLAC: metadata\n");
00740 }
00741 
00742 
00743 void clFileSrv::FLACErrorCB (const FLAC__FileDecoder *flacDecoderInst,
00744     FLAC__StreamDecoderErrorStatus flacError)
00745 {
00746     switch (flacError)
00747     {
00748         case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
00749             g_print("FLAC: synchronization lost\n");
00750             break;
00751         case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
00752             g_print("FLAC: bad header\n");
00753             break;
00754         case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
00755             g_print("FLAC: frame CRC error\n");
00756             break;
00757         default:
00758             g_print("FLAC: unknown error\n");
00759     }
00760 }
00761 
00762 #endif

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