00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00043 static const char *cpFileTxt = "Filename";
00044 static const char *cpBrowseTxt = "Browse...";
00045
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
00135 gtk_window_set_policy(GTK_WINDOW(gwWindow), TRUE, TRUE, FALSE);
00136
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
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
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
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
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
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
00257
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
00581 lSleepTime = (long) ((dFrameTime - GetTime()) * 1000000.0);
00582
00583
00584
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
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
00686 Msg.SetData(MsgBuf, (GDT *) LAudioBlock, lBlockSize);
00687
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
00717
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
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