FreeWRL/FreeX3D  3.0.0
SoundEngineClient.c
1 /*
2 
3 
4 This is the SoundEngine client code for FreeWRL.
5 
6 Some of this stuff came from files from "wavplay" - see information below
7 
8 */
9 
10 
11 /****************************************************************************
12  This file is part of the FreeWRL/FreeX3D Distribution.
13 
14  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
15 
16  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
17  it under the terms of the GNU Lesser Public License as published by
18  the Free Software Foundation, either version 3 of the License, or
19  (at your option) any later version.
20 
21  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
22  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  GNU General Public License for more details.
25 
26  You should have received a copy of the GNU General Public License
27  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
28 ****************************************************************************/
29 
30 
31 #include <config.h>
32 #include <system.h>
33 #include <system_net.h>
34 #include <internal.h>
35 #include <errno.h>
36 #include <libFreeWRL.h>
37 #include <signal.h>
38 
39 #include "../scenegraph/sounds.h"
40 
41 #define SOUNDVERBOSE
42 
43 // OLD_IPHONE_AQUA #if defined(_MSC_VER) || defined (IPHONE) || defined(_ANDROID) || defined(GLES2) || defined (AQUA)
44 #if defined(_MSC_VER) || defined(_ANDROID) || defined(GLES2)
45 
46 void
47 Sound_toserver(char *message)
48 {}
49 
50 int SoundEngineInit(void){ return 0;}
51 
52 void
53 waitformessage(void)
54 {}
55 
56 void
57 SoundEngineDestroy(void)
58 {}
59 
60 int
61 SoundSourceRegistered(int num)
62 { return FALSE;}
63 
64 float
65 SoundSourceInit(int num,
66  int loop,
67  double pitch,
68  double start_time,
69  double stop_time,
70  char *url)
71 {return 0.0f;}
72 
73 void
74 SetAudioActive(int num, int stat)
75 {}
76 
77 #else /*ifdef win32 or IPHONE */
78 
79 
80 int SReg[MAXSOUNDS];
81 
82 int my_ipc_key;
83 
84 FWSNDMSG msg; /* message buffer */
85 
86 /* TODO: integrate this variable into configure:
87  define there a SOUNDSERVERBINARY ...
88  */
89 #ifdef __APPLE__
90 const char SSPATH[] = "/usr/local/bin/FreeWRL_SoundServer";
91 #else
92 const char SSPATH[] = "freewrl_snd";
93 #endif
94 char *sspath = NULL;
95 
96 static int initialized = SOUND_NEEDS_STARTING; /* are we able to run? */
97 
98 
99 /* IPC stuff */
100 #ifndef __APPLE__
101 int msq_toserver = -1;
102 int msq_fromserver = -1;
103 #else
104 char* serverpipe = "/tmp/soundserver";
105 char* clientpipe = "/tmp/soundclient";
106 int server_pipe_fd, client_pipe_fd;
107 time_t last_time, current_time;
108 #endif
109 
110 pid_t S_Server_PID;
111 
112 void Sound_toserver (char *message) {
113  int xx;
114 
115  if (initialized != SOUND_STARTED) return;
116 
117  strcpy (msg.msg,message);
118  #ifdef SOUNDVERBOSE
119  printf ("Client:Sending to server %s\n",msg.msg);
120  #endif
121 
122 #ifndef __APPLE__
123  while((xx = msgsnd(msq_toserver, &msg,strlen(msg.msg)+1,IPC_NOWAIT)));
124 #else
125  xx = (int) write(server_pipe_fd, &msg, sizeof(msg));
126  if (xx > 0)
127  xx = 0;
128 #endif
129  /* printf ("Client:Sent to server\n"); */
130  if (xx) { /* Send to server */
131  perror("server error");
132  printf ("SoundEngineServer - error sending ready msg\n");
133 #ifndef __APPLE__
134  initialized = SOUND_FAILED;
135 #endif
136  }
137 }
138 
139 void SoundEngineInit () {
140  int x;
141  char buf[200];
142 
143  struct stat enginestat;
144 
145  /* have we done this before (can happen if more than 1 sound source) */
146  if (initialized != SOUND_NEEDS_STARTING) return;
147 
148 #if defined(SOUNDSERVERBINARY)
149  sspath = (char *) malloc( strlen(SOUNDSERVERBINARY) + 1 );
150  sprintf(sspath, "%s", SOUNDSERVERBINARY);
151 #else
152  sspath = (char *) malloc( strlen(SSPATH) + 1 );
153  strcpy(sspath, SSPATH);
154 #endif
155 
156  /* is the sound engine installed on this system? */
157  if (stat(sspath,&enginestat)) {
158  printf ("FreeWRL: SoundEngine not installed on system\n");
159  initialized = SOUND_FAILED;
160  return;
161  }
162 
163  my_ipc_key = getpid();
164  /* my_ipc_key = 1234; */
165 
166  msg.mtype=1;
167 
168  /* initialize SoundRegistered "database" */
169  for (x=0; x<MAXSOUNDS; x++) SReg[x]=FALSE;
170 
171  /* printf ("Client, thus queue key is %d\n",my_ipc_key); */
172 
173  /* message queue for client/server comms */
174 #ifndef __APPLE__
175  if ( (msq_toserver = msgget(my_ipc_key,IPC_CREAT|0666)) < 0 ) {
176  ConsoleMessage ("FreeWRL:SoundServer error creating toserver message queue\n");
177  initialized = SOUND_FAILED;
178  return;
179  }
180  if ( (msq_fromserver = msgget(my_ipc_key+1,IPC_CREAT|0666)) < 0 ) {
181  ConsoleMessage ("FreeWRL:SoundServer error creating fromserver message queue\n");
182  initialized = SOUND_FAILED;
183  return;
184  }
185 #else
186 
187  if ((client_pipe_fd = open (clientpipe, O_RDONLY | O_NONBLOCK)) < 0) {
188  if ((mkfifo(clientpipe, S_IRUSR | S_IWUSR | S_IXUSR)) < 0) {
189  ConsoleMessage ("FreeWRL:SoundServer error creating client pipe\n");
190  initialized = SOUND_FAILED;
191  return;
192  }
193  if ((client_pipe_fd = open (clientpipe, O_RDONLY | O_NONBLOCK)) < 0) {
194  ConsoleMessage ("FreeWRL:SoundServer error opening client pipe\n");
195  initialized = SOUND_FAILED;
196  return;
197  }
198  }
199 #endif
200  #ifdef XSOUNDVERBOSE
201  printf ("SoundClient - msq_toserver=%x, msq_fromserver=%x.\n", msq_toserver,msq_fromserver);
202  #endif
203 
204  sprintf(buf,"INIT %d",my_ipc_key);
205  #ifdef SOUNDVERBOSE
206  printf("buf='%s' sspath='%s'.\n",buf,sspath);
207  #endif
208 
209 
210  if ( (S_Server_PID = fork()) == (pid_t)0L ) {
211  /* is this path ok? */
212  execl((const char *)sspath,(const char *)buf,"",NULL);
213 
214  /* if we got here, we have an error... */
215  printf("FreeWRL:SoundServer:%s: exec of %s\n",strerror(errno),sspath);
216 #ifndef __APPLE__
217  msgctl(msq_toserver,IPC_RMID,NULL);
218  msgctl(msq_fromserver,IPC_RMID,NULL);
219 #else
220  close(client_pipe_fd);
221 #endif
222  initialized = SOUND_FAILED;
223  return;
224 
225  } else if ( S_Server_PID < 0 ) {
226  ConsoleMessage ("FreeWRL:SoundServer %s: error starting server process",
227  strerror);
228 #ifndef __APPLE__
229  msgctl(msq_toserver,IPC_RMID,NULL);
230  msgctl(msq_fromserver,IPC_RMID,NULL);
231 #else
232  close(client_pipe_fd);
233 #endif
234  initialized = SOUND_FAILED;
235  return;
236  }
237 
238 
239  #ifdef SOUNDVERBOSE
240  printf ("Client: - server pid %d\n",S_Server_PID);
241  #endif
242 
243 
244  /* if FreeWRL actually gets to the exit stage... :-) */
245  atexit(SoundEngineDestroy);
246 
247  /* wait for the message queue to initialize. */
248  waitformessage();
249 
250 #ifdef __APPLE__
251  if ((server_pipe_fd = open (serverpipe, O_WRONLY | O_NONBLOCK)) < 0) {
252  perror("Open error\n");
253  printf("FreeWRL:SoundServer error opening server pipe\n");
254  initialized = SOUND_FAILED;
255  return;
256  }
257 #endif
258  if (initialized == SOUND_FAILED) {
259  printf("FreeWRL:SoundServer: Timeout: starting server.");
260  SoundEngineDestroy();
261  }
262 }
263 
264 /* Wait for SoundServer to return a response. Note: Not all commands wait for this return. */
265 void waitformessage () {
266  int xx;
267  time_t t0, t;
268  pid_t PID;
269  int proc_status;
270 
271  time(&t0);
272 
273  while ( 1 ) {
274 
275  /* wait for a response - is the server telling us it is ok? */
276  /* printf ("Client: waiting for response on %d\n",msq_toserver); */
277  /* printf("Client: waiting for response\n"); */
278 
279  do {
280 #ifndef __APPLE__
281  xx = msgrcv(msq_fromserver,&msg,128,1,0);
282 #else
283  xx = (int) read (client_pipe_fd, &msg, sizeof(msg));
284  if (xx <= 1)
285  xx = 0;
286 #endif
287  /* printf ("Client waiting... xx is %d\n",xx); */
288 
289  usleep(1000);
290  } while (!xx);
291 
292  #ifdef SOUNDVERBOSE
293  printf ("message received was %s type %ld\n", msg.msg,msg.mtype);
294  #endif
295 
296  if (xx>0) {
297  /* We have a message from the server */
298  if ( msg.mtype == 1 ) {
299  initialized = SOUND_STARTED;
300  return; /* connect OK */
301  }
302  } else {
303  while ((PID=waitpid(-1,&proc_status,WNOHANG)) == -1
304  && errno==EINTR );
305  if ( PID > 0 ) {
306  ConsoleMessage ("FreeWRL:SoundServer process ID %ld terminated: %d",
307  PID,proc_status);
308  initialized = SOUND_FAILED;
309  return;
310 
311  } else sleep(1);
312  }
313 
314  time(&t);
315  if ( t - t0 > 5 )
316  break;
317  }
318 
319 }
320 
321 /* close socket, destroy the server */
322 void SoundEngineDestroy() {
323  /* printf("reached DESTROY\n"); */
324  if (initialized == SOUND_STARTED) {
325 #ifndef __APPLE__
326  msgctl(msq_toserver,IPC_RMID,NULL);
327  msgctl(msq_fromserver,IPC_RMID,NULL);
328 #else
329  /* fclose((FILE*)serverpipe); */
330  /* fclose((FILE*)clientpipe); */
331  /* unlink(serverpipe); */
332  /* unlink(clientpipe); */
333 #endif
334  printf ("SoundEngineDestroy, sound was started successfully\n");
335  kill(S_Server_PID,SIGTERM);
336  }
337  initialized = SOUND_NEEDS_STARTING;
338 }
339 
340 int SoundSourceRegistered (int num) {
341  if (num >= MAXSOUNDS) {
342  printf ("Too many sounds in VRML file - max %d",num);
343  return FALSE;
344  }
345  return SReg[num];
346 }
347 
348 float SoundSourceInit (int num, int loop, double pitch, double start_time, double stop_time,
349  char *url) {
350 
351  char mystring[512];
352  float duration;
353  int returnednum;
354 
355 
356  SReg[num] = TRUE;
357 
358  #ifdef SOUNDVERBOSE
359  printf ("start of SoundSourceInit)\n");
360  printf ("num %d\n",num);
361  printf ("loop %d\n",loop);
362  printf ("pitch %f\n",pitch);
363  printf ("start_time %f\n",start_time);
364  printf ("stop_time %f\n",stop_time);
365  printf ("SoundSourceInit - url is %s\n",url);
366  #endif
367 
368 
369  if (url == NULL) {
370  printf ("SoundSourceInit - no file to source \n");
371  return 0.0f;
372  }
373 
374  if (strlen(url) > 192) {
375  printf ("SoundSourceInit - url %s is too long\n",url);
376  return 0.0f;
377  }
378 
379  #ifdef __APPLE__
380  /* possible problems with spaces in file name, so quote file name */
381  sprintf (mystring,"REGS:\"%s\" %2d %2d %4.3f %4.3f %4.3f",url,num,loop,pitch,start_time, stop_time);
382  #else
383  sprintf (mystring,"REGS:%s %2d %2d %4.3f %4.3f %4.3f",url,num,loop,pitch,start_time, stop_time);
384  #endif
385  Sound_toserver(mystring);
386 
387  #ifdef SOUNDVERBOSE
388  printf ("SoundSourceInit, waiting for response\n");
389  #endif
390 
391  waitformessage();
392 
393  #ifdef SOUNDVERBOSE
394  printf ("SoundSourceInit, got message %s\n",msg.msg);
395  #endif
396 
397  if (sscanf (msg.msg,"REGS %d %f",&returnednum,&duration) != 2) {
398  /* something funny happened here */
399  return 1.0f;
400  } else {
401  return duration;
402  }
403 }
404 
405 /* send new active state to the soundengine. */
406 void SetAudioActive (int num, int stat) {
407  char mystring[512];
408 
409  #ifdef SOUNDVERBOSE
410  printf ("SoundSource - got SetAudioActive for %d state %d\n",num,stat);
411  #endif
412 
413  sprintf (mystring,"ACTV %2d %2d",num,stat);
414  Sound_toserver(mystring);
415 }
416 
417 void SoundServer_finish()
418 {
419  FREE_IF_NZ(sspath);
420 }
421 
422 #endif /*ifdef win32 */