Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
soundserver.cpp
Go to the documentation of this file.
1 //#define HAVE_SDL
2 #if !defined (SDL_MIX_MAXVOLUME)
3 #define SDL_MIX_MAXVOLUME 128
4 #endif
5 #ifdef HAVE_SDL
6 #include <SDL/SDL.h>
7 #include <SDL/SDL_thread.h>
8 #include <SDL/SDL_mixer.h>
9 #else
10 typedef int Mix_Music;
11 #endif
12 
13 #include <signal.h>
14 #include <string>
15 #ifdef _WIN32
16 #ifndef NOMINMAX
17 #define NOMINMAX
18 #endif //tells VCC not to generate min/max macros
19 #include <direct.h>
20 #include <windows.h>
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <io.h>
24 #define sleep( sec ) Sleep( sec*1000 );
25 #else
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <pwd.h>
29 #endif
30 #include <stdarg.h>
31 
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <vector>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include "inet_file.h"
39 #include "inet.h"
40 #ifndef _WIN32
41 #include <sys/types.h>
42 #include <pwd.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <sys/file.h>
48 #endif
49 #include "softvolume.h"
50 
51 #ifndef MIX_CHANNEL_POST
52 #define MIX_CHANNEL_POST -2
53 #endif
54 
55 int fadeout = 0, fadein = 0;
57 float volume = 0;
58 float soft_volume = 1;
59 int bits = 0, done = 0;
60 static bool fnet = false;
61 int my_getchar( int socket )
62 {
63  if (fnet)
64  return fNET_fgetc( socket );
65 
66  else
67  return INET_fgetc( socket );
68 }
69 std::string my_getstring( int socket )
70 {
71  std::string str;
72  int arg;
73  do {
74  arg = my_getchar( socket );
75  if ( (arg != '\r') && (arg != '\n') && (arg != '\0') )
76  str += (char) arg;
77  } while ( (arg != '\n') && (arg != '\0') );
78  return str;
79 }
81 {
82  if (fnet)
83  return fNET_BytesToRead( socket );
84 
85  else
86  return INET_BytesToRead( socket );
87 }
88 #if defined (_WIN32) && defined (_WINDOWS)
89 FILE *mystdout = stdout;
90 #define STD_ERR mystdout
91 #define STD_OUT mystdout
92 #else
93 #define STD_ERR stderr
94 #define STD_OUT stdout
95 #endif
96 #ifdef __APPLE
97 #undef main
98 #endif
99 #include <iostream>
100 #include <fstream>
101 #define SONG_MUTEX 0
102 #if SONG_MUTEX
103 #include <SDL/SDL_mutex.h>
104 /*
105  *****************************************************************************
106  * some simple exit and error routines
107  */
108 char *songNames[5] = {0, 0, 0, 0, 0};
109 unsigned int counter = 0;
110 SDL_mutex *RestartSong = NULL;
111 #endif
112 void errorv( char *str, va_list ap )
113 {
114 #ifdef HAVE_SDL
115  vfprintf( STD_ERR, str, ap );
116 
117  fprintf( STD_ERR, ": %s.\n", SDL_GetError() );
118 #endif
119 }
120 std::string concat( const std::vector< std::string >& );
121 void cleanExit( char *str, ... )
122 {
123 #ifdef HAVE_SDL
124  va_list ap;
125  va_start( ap, str );
126  errorv( str, ap );
127  va_end( ap );
128  Mix_CloseAudio();
129  SDL_Quit();
130 #endif
131  exit( 1 );
132 }
133 std::string HOMESUBDIR = ".vegastrike";
134 /*
135  *****************************************************************************
136  * The main function
137  */
138 void changehome( bool to, bool linuxhome = true )
139 {
140  static std::vector< std::string >paths;
141  if (to) {
142  char mycurpath[8192];
143  getcwd( mycurpath, 8191 );
144  mycurpath[8191] = '\0';
145  paths.push_back( mycurpath );
146 #ifndef _WIN32
147  if (linuxhome) {
148  struct passwd *pwent;
149  pwent = getpwuid( getuid() );
150  chdir( pwent->pw_dir );
151  }
152 #endif
153  chdir( HOMESUBDIR.c_str() );
154  } else if ( !paths.empty() ) {
155  chdir( paths.back().c_str() );
156  paths.pop_back();
157  }
158 }
159 
160 std::string alphanum( std::string s )
161 {
162  std::string ret;
163  std::string::iterator i = s.begin();
164  unsigned int counter = 0;
165  for (; i != s.end(); ++i, ++counter)
166  if ( (*i >= 'A' && *i <= 'Z')
167  || (*i >= 'a' && *i <= 'z')
168  || (*i >= '0' && *i <= '9') || ( (*i) == '.' && counter == s.length()-4 ) )
169  ret += *i;
170  return ret;
171 }
172 void concat_ostream( std::ofstream &o, const std::vector< std::string > &files )
173 {
174  if ( o.is_open() ) {
175  for (unsigned int i = 0; i < files.size(); ++i) {
176  std::ifstream as;
177  as.open( files[i].c_str(), std::ios::binary );
178  if ( !as.is_open() ) {
179  changehome( true, false );
180  as.open( files[i].c_str(), std::ios::binary );
181  changehome( false );
182  }
183  if ( !as.is_open() ) {
184  changehome( true, true );
185  as.open( files[i].c_str(), std::ios::binary );
186  changehome( false );
187  }
188  if ( as.is_open() ) {
189  o<<as.rdbuf(); //read original file into target
190  as.close();
191  }
192  }
193  o.close();
194  }
195 }
196 std::string concat( const std::vector< std::string > &files )
197 {
198  std::string ret =
199 #ifdef _WIN32
200  "c:/temp/"
201 #else
202  "/tmp/"
203 #endif
204  ;
205  std::string alphan;
206  {
207  for (unsigned int i = 0; i < files.size(); ++i)
208  alphan += alphanum( files[i] );
209  }
210  ret += alphan;
211  FILE *checker = fopen( ret.c_str(), "rb" );
212  if (checker) {
213  fclose( checker );
214  return ret;
215  }
216  std::ofstream o( ret.c_str(), std::ios::binary );
217  if ( !o.is_open() ) {
218  ret = "music/"+alphan; //current dir
219  checker = fopen( ret.c_str(), "rb" );
220  if (checker) {
221  fclose( checker );
222  return ret;
223  }
224  std::ofstream o1( ret.c_str(), std::ios::binary );
225  if ( o1.is_open() ) {
226  concat_ostream( o1, files );
227  return ret;
228  } else {
229 #ifdef _WIN32
230  ret = tempnam( "c:\tmp", alphan.c_str() );
231  ret += ".ogg";
232  checker = fopen( ret.c_str(), "rb" );
233  if (checker) {
234  fclose( checker );
235  return ret;
236  }
237  std::ofstream of( ret.c_str(), std::ios::binary );
238  fprintf( STD_OUT, "\nTrying to Open %s\n", ret.c_str() );
239  if ( of.is_open() ) {
240  concat_ostream( of, files );
241  return ret;
242  }
243 #endif
244  }
245  } else {
246  concat_ostream( o, files );
247  return ret;
248  }
249  return "";
250 }
251 std::vector< std::string >split( std::string tmpstr, std::string splitter )
252 {
253  std::string::size_type where;
254  std::vector< std::string >ret;
255  while ( ( where = tmpstr.find( splitter ) ) != std::string::npos ) {
256  ret.push_back( tmpstr.substr( 0, where ) );
257  tmpstr = tmpstr.substr( where+1 );
258  }
259  if ( tmpstr.length() )
260  ret.push_back( tmpstr );
261  return ret;
262 }
263 
264 /*
265  * if (ret.size()==2) {
266  * std::string tmp = concat(ret[0],ret[1]);
267  * if (tmp.length()) {
268  * ret[0]=tmp;
269  * ret.pop_back();
270  * }
271  * }
272  */
273 
274 int mysocket = -1;
275 int mysocket_write = -1;
276 #if SONG_MUTEX
277 Mix_Music *music = NULL;
278 #endif
279 
280 #ifdef _WIN32
281 #undef main
282 #endif
283 volatile bool sende = true;
284 std::string curmus;
285 
286 #ifdef HAVE_SDL
287 static int numloops( std::string file )
288 {
289  int value = 1;
290  std::string::size_type where;
291  if ( ( where = file.find_last_of( "." ) ) != std::string::npos ) {
292  file = file.substr( 0, where );
293  if ( ( where = file.find_last_of( "-_" ) ) != std::string::npos ) {
294  file = file.substr( where+1 );
295  if ( file.length() ) {
296  if (file[0] == 'i')
297  return -1;
298  else
299  return atoi( file.c_str() );
300  }
301  }
302  }
303  return value;
304 }
305 #endif
306 
307 Mix_Music * PlayMusic( std::string file, Mix_Music *oldmusic )
308 {
309  std::vector< std::string >files = split( file, "|" );
310  if (files.size() > 1) {
311  std::string tmp = concat( files );
312  if ( tmp.length() )
313  file = tmp;
314  }
315 #ifdef HAVE_SDL
316  Mix_Music *music = NULL;
317  if ( !file.empty() ) {
318  music = Mix_LoadMUS( file.c_str() );
319  if (music == NULL) {
320  changehome( true, false );
321  music = Mix_LoadMUS( file.c_str() );
322  changehome( false );
323  if (music == NULL) {
324  changehome( true, true );
325  music = Mix_LoadMUS( file.c_str() );
326  changehome( false );
327  if (music == NULL)
328  return oldmusic;
329  }
330  }
331  }
332  sende = false;
333  if ( oldmusic && Mix_PlayingMusic() ) {
336  if (music == NULL) return NULL;
337  //while(!my_bytestoread(mysocket)&&Mix_SoftVolume_GetCurrentVolume(MIX_CHANNEL_POST)>0) SDL_Delay(100);
338  }
339  Mix_HaltMusic();
340  while ( Mix_PlayingMusic() )
341  SDL_Delay( 100 );
342  if (oldmusic) {
343  Mix_FreeMusic( oldmusic );
344  oldmusic = NULL;
345  }
346  if (music == NULL) {
347  //No music, so stop softvolume processing
349  return NULL;
350  }
351  sende = true;
352  int loops = numloops( file );
355  if (Mix_PlayMusic( music, loops ) == -1) {
356  fprintf( STD_OUT, "Mix_FadeInMusic: %s %d\n", Mix_GetError() );
357  return NULL;
358  } else {
359  fprintf( STD_OUT, "Playing %s with %d loops\n", file.c_str(), loops );
360  //well, there's no music, but most games don't break without music...
361  }
362  int newvolume = (int) (SDL_MIX_MAXVOLUME*volume);
363  Mix_VolumeMusic( newvolume );
364  return music;
365 
366 #else
367  return NULL;
368 #endif
369 }
371 {
372  if (sende) {
373  char data = 'e';
374 #if SONG_MUTEX
375  SDL_mutexP( RestartSong );
376  int tmp = counter;
377  char *newname = NULL;
378  if (tmp < 5) {
379  newname = songNames[tmp];
380  counter++;
381  }
382  if (newname) {
383  music = PlayMusic( newname, music );
384  SDL_mutexV( RestartSong );
385  } else {
386  SDL_mutexV( RestartSong );
387 #endif
388  if (fnet)
389  fNET_Write( mysocket_write, sizeof (char), &data );
390  else
391  INET_Write( mysocket_write, sizeof (char), &data );
392 #if SONG_MUTEX
393  }
394 #endif
395  fprintf( STD_OUT, "\ne\n[SONG DONE]\n" );
396  }
397 }
398 #if defined (_WIN32) && defined (_WINDOWS)
399 typedef char FileNameCharType[65535];
400 void getPipes( LPSTR cmd, int(*const pipes)[2] )
401 {
402  ptrdiff_t len = strlen( cmd );
403  ptrdiff_t i = len-1;
404  for (; i >= 0 && (isspace( cmd[i] ) || cmd[i] >= '0' && cmd[i] <= '9'); --i) {}
405  i += 1;
406  if (i < len)
407  sscanf( cmd+i, "%d %d", &(*pipes)[0], &(*pipes)[1] );
408 }
409 int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd )
410 {
411  FileNameCharType argvc;
412  FileNameCharType *argv = &argvc;
413  GetModuleFileName( NULL, argvc, 65534 );
414  mystdout = fopen( "soundserver_log.txt", "w" );
415  int pipes[2] = {-1, -1};
416  getPipes( lpCmdLine, &pipes );
417  if (mystdout)
418  setbuf( mystdout, NULL ); /* No buffering */
419  else
420  mystdout = stdout;
421 #else
422 int main( int argc, char **argv )
423 {
424  int pipes[2] = {-1, -1};
425  if (argc > 1) sscanf( argv[1], "%d", &pipes[0] );
426  if (argc > 2) sscanf( argv[2], "%d", &pipes[1] );
427 #endif
428  {
429  char origpath[65535];
430  getcwd( origpath, 65534 );
431  origpath[65534] = 0;
432  fprintf( STD_OUT, "Current Path %s\n", origpath );
433 #ifdef _WIN32
434  int i;
435  for (i = strlen( argv[0] ); argv[0][i] != '\\' && argv[0][i] != '/' && i >= 0; i--) {}
436  argv[0][i+1] = '\0';
437  chdir( argv[0] );
438 #endif
439  struct stat st;
440  if (stat( "vegastrike.config", &st ) != 0)
441  //vegastrike.config not found. Let's check ../
442  chdir( ".." ); //gotta check outside bin dir
443  getcwd( origpath, 65534 );
444  fprintf( STD_OUT, "Final Path %s\n", origpath );
445  }
446 
447  FILE *version = fopen( "Version.txt", "r" );
448  if (version) {
449  std::string hsd = "";
450  int c;
451  while ( ( c = fgetc( version ) ) != EOF ) {
452  if ( ( (c) == ' ' ) || ( (c) == '\t' ) || ( (c) == '\n' ) || ( (c) == '\r' ) || ( (c) == '\0' ) )
453  break;
454  hsd += (char) c;
455  }
456  fclose( version );
457  if ( hsd.length() ) {
458  HOMESUBDIR = hsd;
459  fprintf( STD_OUT, "Using %s as the home directory\n", hsd.c_str() );
460  }
461  }
462  int audio_rate, audio_channels,
463  //set this to any of 512,1024,2048,4096
464  //the higher it is, the more FPS shown and CPU needed
465  audio_buffers = 4096;
466 #ifdef HAVE_SDL
467  Uint16 audio_format;
468  //initialize SDL for audio and video
469  if (SDL_Init( SDL_INIT_AUDIO|SDL_INIT_TIMER ) < 0)
470  cleanExit( "SDL_Init\n" );
471  signal( SIGSEGV, SIG_DFL );
472 #if SONG_MUTEX
473  RestartSong = SDL_CreateMutex();
474  music = NULL;
475 #else
476  Mix_Music *music = NULL;
477 #endif
478  Mix_HookMusicFinished( &music_finished );
479 #else
480 #if SONG_MUTEX
481 #else
482  Mix_Music *music = NULL;
483 #endif
484 #endif
485 #ifndef _WIN32
486  fnet = (argc == 3 && pipes[1] == -1);
487 #endif
488  fnet = (fnet || pipes[1] != -1);
489  if (fnet)
490  fNET_startup();
491  else
492  INET_startup();
493  //initialize sdl mixer, open up the audio device
494 #ifdef HAVE_SDL
495  if (Mix_OpenAudio( 44100, MIX_DEFAULT_FORMAT, 2, audio_buffers ) < 0)
496  cleanExit( "Mix_OpenAudio\n" );
497  //print out some info on the audio device and stream
498  Mix_QuerySpec( &audio_rate, &audio_format, &audio_channels );
499  bits = audio_format&0xFF;
500 #endif
501  fprintf( STD_OUT, "Opened audio at %d Hz %d bit %s, %d bytes audio buffer\n", audio_rate,
502  bits, audio_channels > 1 ? "stereo" : "mono", audio_buffers );
503  //load the song
504  if (fnet) {
505  if (pipes[1] == -1 || pipes[0] == -1) {
506  mysocket_write = open( argv[2], O_WRONLY|O_CREAT, 0xffffffff );
507 #ifndef _WIN32
508  flock( mysocket_write, LOCK_SH );
509 #endif
510  mysocket = open( argv[1], O_RDONLY|O_CREAT, 0xffffffff );
511 #ifndef _WIN32
512  flock( mysocket, LOCK_SH );
513 #endif
514  } else {
515  mysocket_write = pipes[1];
516  mysocket = pipes[0];
517  }
518  } else {
519  for (int i = 0; i < 10 && mysocket == -1; i++) {
520  int port = (pipes[0] != -1 ? pipes[0] : 4364);
521  if (port == 0) port = 4364;
522  if (pipes[1] != -1 && pipes[0] != -1) {
523  mysocket = pipes[0];
524  mysocket_write = pipes[1];
525  } else {
526  mysocket = mysocket_write = INET_AcceptFrom( port, "localhost" );
527  }
528  }
529  }
530  if (mysocket == -1)
531  return 1;
532  fprintf( STD_OUT, "\n[CONNECTED]\n" );
533  fflush( STD_OUT );
534  char ministr[2] = {'\0', '\0'};
535  while (!done) {
536 //if ((Mix_PlayingMusic() || Mix_PausedMusic())&&(!done)) {
537  char arg = 't';
538  std::string str;
539  arg = my_getchar( mysocket );
540  fprintf( STD_OUT, "%c", arg );
541  fflush( STD_OUT );
542  switch (arg)
543  {
544  case 'p':
545  case 'P':
546  str = my_getstring( mysocket );
547  fprintf( STD_OUT, "%s", str.c_str() );
548  fflush( STD_OUT );
549  if ( (str != curmus)
550 #ifdef HAVE_SDL
551  || ( !Mix_PlayingMusic() )
552 #endif
553  ) {
554 #if SONG_MUTEX
555  std::vector< std::string >names = split( str, "&" );
556  char *tmpstrings[5] = {NULL, NULL, NULL, NULL, NULL};
557  for (unsigned int t = 0; t < 5 && t+1 < names.size(); ++t)
558  tmpstrings[t] = strdup( names[t+1].c_str() );
559  SDL_mutexP( RestartSong );
560  memcpy( songNames, tmpstrings, sizeof (char*)*5 );
561  if (names.size() > 0) str = names[0];
562  counter = 0;
563 #endif
564  music = PlayMusic( str, music );
565 #if SONG_MUTEX
566  SDL_mutexV( RestartSong );
567 #endif
568  if (music) {
569  fprintf( STD_OUT, "\n[PLAYING %s WITH %d FADEIN AND %d FADEOUT]\n", str.c_str(), fadein, fadeout );
570  curmus = str;
571  } else {
572  char mycurpath[8192];
573  getcwd( mycurpath, 8191 );
574  mycurpath[8191] = '\0';
575  fprintf( STD_OUT, "\n[UNABLE TO PLAY %s IN %s WITH %d FADEIN AND %d FADEOUT]\n",
576  str.c_str(), mycurpath, fadein, fadeout );
577  }
578  } else {
579  fprintf( STD_OUT, "\n[%s WITH %d FADEIN AND %d FADEOUT IS ALREADY PLAYING]\n", str.c_str(), fadein, fadeout );
580  }
581  fflush( STD_OUT );
582  break;
583  case 'i':
584  case 'I':
585  str = my_getstring( mysocket );
586  fprintf( STD_OUT, "%s", str.c_str() );
587  fadein = atoi( str.c_str() );
588  fprintf( STD_OUT, "\n[SETTING FADEIN TO %d]\n", fadein );
589  fflush( STD_OUT );
590  break;
591  case 'o':
592  case 'O':
593  str = my_getstring( mysocket );
594  fprintf( STD_OUT, "%s", str.c_str() );
595  fadeout = atoi( str.c_str() );
596  fprintf( STD_OUT, "\n[SETTING FADEOUT TO %d]\n", fadeout );
597  fflush( STD_OUT );
598  break;
599  case 'v':
600  case 'V':
601  {
602  int vtype = my_getchar( mysocket );
603  str = my_getstring( mysocket );
604  fprintf( STD_OUT, "%s", str.c_str() );
605  switch (vtype)
606  {
607  case 'h':
608  case 'H':
609  volume = (float) atof( str.c_str() );
610  break;
611  case 's':
612  case 'S':
613  soft_volume = (float) atof( str.c_str() );
614  str = my_getstring( mysocket );
615  fprintf( STD_OUT, "%s", str.c_str() );
617  break;
618  }
619  fprintf( STD_OUT, "\n[SETTING VOLUME TO %f]\n", volume );
620  fflush( STD_OUT );
621 #ifdef HAVE_SDL
622  int newvolume = (int) (SDL_MIX_MAXVOLUME*volume);
623  Mix_VolumeMusic( newvolume );
624 #endif
625  break;
626  }
627  case 's':
628  case 'S':
629  fprintf( STD_OUT, "\n[STOPPING ALL MUSIC - %d FADEOUT]\n", fadeout );
630  curmus = "";
631  music = PlayMusic( "", music );
632  break;
633  case 'h':
634  case 'H':
635  {
636  const char *shname = "UNRECOGNIZED";
637  int arg0, arg1;
638  arg0 = my_getchar( mysocket );
639  arg1 = my_getchar( mysocket );
640  switch (arg0)
641  {
642  case 'l':
643  case 'L':
644  switch (arg1)
645  {
646  case 'l':
647  case 'L':
649  shname = "LINEAR";
650  break;
651  case 'e':
652  case 'E':
654  shname = "LINEAR EASED";
655  break;
656  }
657  break;
658  case 'e':
659  case 'E':
660  switch (arg1)
661  {
662  case 'l':
663  case 'L':
665  shname = "EXPONENTIAL";
666  break;
667  case 'e':
668  case 'E':
670  shname = "EXPONENTIAL EASED";
671  break;
672  }
673  break;
674  }
675  fprintf( STD_OUT, "\n[SOFTVOLUME SHAPE: %s]\n", shname );
676  break;
677  }
678  case 't':
679  case 'T':
680  case '\0':
681  if (fnet) {
682  fNET_close( mysocket );
684  } else {
685  INET_close( mysocket );
687  }
688  done = true;
689  fprintf( STD_OUT, "\n[TERMINATING MUSIC SERVER]\n" );
690  fflush( STD_OUT );
691  break;
692  }
693  }
694  //free & close
695  if (fnet) {
696  fNET_cleanup();
697  if (pipes[0] == -1)
698  unlink( argv[1] );
699  if (pipes[1] == -1)
700  unlink( argv[2] );
701  } else {
702  INET_cleanup();
703  }
704 #ifdef HAVE_SDL
705  Mix_CloseAudio();
706 #if SONG_MUTEX
707  SDL_DestroyMutex( RestartSong );
708 #endif
709  SDL_Quit();
710 #endif
711 
712  return 0;
713 }
714