FreeWRL / FreeX3D 4.3.0
SoundEngineClient.c
1/*
2
3
4This is the SoundEngine client code for FreeWRL.
5
6Some 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) || defined (AQUA)
45
46void
47Sound_toserver(char *message)
48{}
49
50int SoundEngineInit(void){ return 0;}
51
52void
53waitformessage(void)
54{}
55
56void
57SoundEngineDestroy(void)
58{}
59
60int
61SoundSourceRegistered(int num)
62{ return FALSE;}
63
64float
65SoundSourceInit(int num,
66 int loop,
67 double pitch,
68 double start_time,
69 double stop_time,
70 char *url)
71{return 0.0f;}
72
73void
74SetAudioActive(int num, int stat)
75{}
76
77#else /*ifdef win32 or IPHONE */
78
79
80int SReg[MAXSOUNDS];
81
82int my_ipc_key;
83
84FWSNDMSG msg; /* message buffer */
85
86/* TODO: integrate this variable into configure:
87 define there a SOUNDSERVERBINARY ...
88 */
89#ifdef __APPLE__
90const char SSPATH[] = "/usr/local/bin/FreeWRL_SoundServer";
91#else
92const char SSPATH[] = "freewrl_snd";
93#endif
94char *sspath = NULL;
95
96static int initialized = SOUND_NEEDS_STARTING; /* are we able to run? */
97
98
99/* IPC stuff */
100#ifndef __APPLE__
101int msq_toserver = -1;
102int msq_fromserver = -1;
103#else
104char* serverpipe = "/tmp/soundserver";
105char* clientpipe = "/tmp/soundclient";
106int server_pipe_fd, client_pipe_fd;
107time_t last_time, current_time;
108#endif
109
110pid_t S_Server_PID;
111
112void 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
139void 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. */
265void 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 */
322void 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
340int 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
348float 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. */
406void 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
417void SoundServer_finish()
418{
419 FREE_IF_NZ(sspath);
420}
421
422#endif /*ifdef win32 */