Update Fluidsynth to v2.0.4
[ardour.git] / libs / fluidsynth / src / fluid_sys.c
1 /* FluidSynth - A Software Synthesizer
2  *
3  * Copyright (C) 2003  Peter Hanappe and others.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public License
7  * as published by the Free Software Foundation; either version 2.1 of
8  * the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  */
20
21 #include "fluid_sys.h"
22
23
24 #if WITH_READLINE
25 #include <readline/readline.h>
26 #include <readline/history.h>
27 #endif
28
29 #ifdef DBUS_SUPPORT
30 #include "fluid_rtkit.h"
31 #endif
32
33 #if HAVE_PTHREAD_H && !defined(WIN32)
34 // Do not include pthread on windows. It includes winsock.h, which collides with ws2tcpip.h from fluid_sys.h
35 // It isn't need on Windows anyway.
36 #include <pthread.h>
37 #endif
38
39 /* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
40  * Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
41 #ifdef _WIN32
42 #define FLUID_SOCKET_FLAG      0x40000000
43 #else
44 #define FLUID_SOCKET_FLAG      0x00000000
45 #define SOCKET_ERROR           -1
46 #define INVALID_SOCKET         -1
47 #endif
48
49 /* SCHED_FIFO priority for high priority timer threads */
50 #define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL         10
51
52
53 typedef struct
54 {
55     fluid_thread_func_t func;
56     void *data;
57     int prio_level;
58 } fluid_thread_info_t;
59
60 struct _fluid_timer_t
61 {
62     long msec;
63     fluid_timer_callback_t callback;
64     void *data;
65     fluid_thread_t *thread;
66     int cont;
67     int auto_destroy;
68 };
69
70 struct _fluid_server_socket_t
71 {
72     fluid_socket_t socket;
73     fluid_thread_t *thread;
74     int cont;
75     fluid_server_func_t func;
76     void *data;
77 };
78
79
80 static int fluid_istream_gets(fluid_istream_t in, char *buf, int len);
81
82 static fluid_log_function_t fluid_log_function[LAST_LOG_LEVEL] =
83 {
84     fluid_default_log_function,
85     fluid_default_log_function,
86     fluid_default_log_function,
87     fluid_default_log_function,
88     fluid_default_log_function
89 };
90 static void *fluid_log_user_data[LAST_LOG_LEVEL] = { NULL };
91
92 static const char fluid_libname[] = "fluidsynth";
93
94 /**
95  * Installs a new log function for a specified log level.
96  * @param level Log level to install handler for.
97  * @param fun Callback function handler to call for logged messages
98  * @param data User supplied data pointer to pass to log function
99  * @return The previously installed function.
100  */
101 fluid_log_function_t
102 fluid_set_log_function(int level, fluid_log_function_t fun, void *data)
103 {
104     fluid_log_function_t old = NULL;
105
106     if((level >= 0) && (level < LAST_LOG_LEVEL))
107     {
108         old = fluid_log_function[level];
109         fluid_log_function[level] = fun;
110         fluid_log_user_data[level] = data;
111     }
112
113     return old;
114 }
115
116 /**
117  * Default log function which prints to the stderr.
118  * @param level Log level
119  * @param message Log message
120  * @param data User supplied data (not used)
121  */
122 void
123 fluid_default_log_function(int level, const char *message, void *data)
124 {
125     FILE *out;
126
127 #if defined(WIN32)
128     out = stdout;
129 #else
130     out = stderr;
131 #endif
132
133     switch(level)
134     {
135     case FLUID_PANIC:
136         FLUID_FPRINTF(out, "%s: panic: %s\n", fluid_libname, message);
137         break;
138
139     case FLUID_ERR:
140         FLUID_FPRINTF(out, "%s: error: %s\n", fluid_libname, message);
141         break;
142
143     case FLUID_WARN:
144         FLUID_FPRINTF(out, "%s: warning: %s\n", fluid_libname, message);
145         break;
146
147     case FLUID_INFO:
148         FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
149         break;
150
151     case FLUID_DBG:
152 #if DEBUG
153         FLUID_FPRINTF(out, "%s: debug: %s\n", fluid_libname, message);
154 #endif
155         break;
156
157     default:
158         FLUID_FPRINTF(out, "%s: %s\n", fluid_libname, message);
159         break;
160     }
161
162     fflush(out);
163 }
164
165 /**
166  * Print a message to the log.
167  * @param level Log level (#fluid_log_level).
168  * @param fmt Printf style format string for log message
169  * @param ... Arguments for printf 'fmt' message string
170  * @return Always returns #FLUID_FAILED
171  */
172 int
173 fluid_log(int level, const char *fmt, ...)
174 {
175     if((level >= 0) && (level < LAST_LOG_LEVEL))
176     {
177         fluid_log_function_t fun = fluid_log_function[level];
178
179         if(fun != NULL)
180         {
181             char errbuf[1024];
182             
183             va_list args;
184             va_start(args, fmt);
185             FLUID_VSNPRINTF(errbuf, sizeof(errbuf), fmt, args);
186             va_end(args);
187         
188             (*fun)(level, errbuf, fluid_log_user_data[level]);
189         }
190     }
191
192     return FLUID_FAILED;
193 }
194
195 /**
196  * An improved strtok, still trashes the input string, but is portable and
197  * thread safe.  Also skips token chars at beginning of token string and never
198  * returns an empty token (will return NULL if source ends in token chars though).
199  * NOTE: NOT part of public API
200  * @internal
201  * @param str Pointer to a string pointer of source to tokenize.  Pointer gets
202  *   updated on each invocation to point to beginning of next token.  Note that
203  *   token char get's overwritten with a 0 byte.  String pointer is set to NULL
204  *   when final token is returned.
205  * @param delim String of delimiter chars.
206  * @return Pointer to the next token or NULL if no more tokens.
207  */
208 char *fluid_strtok(char **str, const char *delim)
209 {
210     char *s,  *token;
211                 const char *d;
212     char c;
213
214     if(str == NULL || delim == NULL || !*delim)
215     {
216         FLUID_LOG(FLUID_ERR, "Null pointer");
217         return NULL;
218     }
219
220     s = *str;
221
222     if(!s)
223     {
224         return NULL;    /* str points to a NULL pointer? (tokenize already ended) */
225     }
226
227     /* skip delimiter chars at beginning of token */
228     do
229     {
230         c = *s;
231
232         if(!c)  /* end of source string? */
233         {
234             *str = NULL;
235             return NULL;
236         }
237
238         for(d = delim; *d; d++) /* is source char a token char? */
239         {
240             if(c == *d) /* token char match? */
241             {
242                 s++;            /* advance to next source char */
243                 break;
244             }
245         }
246     }
247     while(*d);          /* while token char match */
248
249     token = s;          /* start of token found */
250
251     /* search for next token char or end of source string */
252     for(s = s + 1; *s; s++)
253     {
254         c = *s;
255
256         for(d = delim; *d; d++) /* is source char a token char? */
257         {
258             if(c == *d) /* token char match? */
259             {
260                 *s = '\0';      /* overwrite token char with zero byte to terminate token */
261                 *str = s + 1;   /* update str to point to beginning of next token */
262                 return token;
263             }
264         }
265     }
266
267     /* we get here only if source string ended */
268     *str = NULL;
269     return token;
270 }
271
272 /**
273  * Suspend the execution of the current thread for the specified amount of time.
274  * @param milliseconds to wait.
275  */
276 void fluid_msleep(unsigned int msecs)
277 {
278     g_usleep(msecs * 1000);
279 }
280
281 /**
282  * Get time in milliseconds to be used in relative timing operations.
283  * @return Unix time in milliseconds.
284  */
285 unsigned int fluid_curtime(void)
286 {
287     static glong initial_seconds = 0;
288     GTimeVal timeval;
289
290     if(initial_seconds == 0)
291     {
292         g_get_current_time(&timeval);
293         initial_seconds = timeval.tv_sec;
294     }
295
296     g_get_current_time(&timeval);
297
298     return (unsigned int)((timeval.tv_sec - initial_seconds) * 1000.0 + timeval.tv_usec / 1000.0);
299 }
300
301 /**
302  * Get time in microseconds to be used in relative timing operations.
303  * @return time in microseconds.
304  * Note: When used for profiling we need high precision clock given
305  * by g_get_monotonic_time()if available (glib version >= 2.53.3).
306  * If glib version is too old and in the case of Windows the function
307  * uses high precision performance counter instead of g_getmonotic_time().
308  */
309 double
310 fluid_utime(void)
311 {
312     double utime;
313
314 #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 28
315     /* use high precision monotonic clock if available (g_monotonic_time().
316      * For Winfdows, if this clock is actually implemented as low prec. clock
317      * (i.e. in case glib is too old), high precision performance counter are
318      * used instead.
319      * see: https://bugzilla.gnome.org/show_bug.cgi?id=783340
320      */
321 #if defined(WITH_PROFILING) &&  defined(WIN32) &&\
322         /* glib < 2.53.3 */\
323         (GLIB_MINOR_VERSION <= 53 && (GLIB_MINOR_VERSION < 53 || GLIB_MICRO_VERSION < 3))
324     /* use high precision performance counter. */
325     static LARGE_INTEGER freq_cache = {0, 0};   /* Performance Frequency */
326     LARGE_INTEGER perf_cpt;
327
328     if(! freq_cache.QuadPart)
329     {
330         QueryPerformanceFrequency(&freq_cache);  /* Frequency value */
331     }
332
333     QueryPerformanceCounter(&perf_cpt); /* Counter value */
334     utime = perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
335 #else
336     utime = g_get_monotonic_time();
337 #endif
338 #else
339     /* fallback to less precise clock */
340     GTimeVal timeval;
341     g_get_current_time(&timeval);
342     utime = (timeval.tv_sec * 1000000.0 + timeval.tv_usec);
343 #endif
344
345     return utime;
346 }
347
348
349
350 #if defined(WIN32)      /* Windoze specific stuff */
351
352 void
353 fluid_thread_self_set_prio(int prio_level)
354 {
355     if(prio_level > 0)
356     {
357         SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
358     }
359 }
360
361
362 #elif defined(__OS2__)  /* OS/2 specific stuff */
363
364 void
365 fluid_thread_self_set_prio(int prio_level)
366 {
367     if(prio_level > 0)
368     {
369         DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, PRTYD_MAXIMUM, 0);
370     }
371 }
372
373 #else   /* POSIX stuff..  Nice POSIX..  Good POSIX. */
374
375 void
376 fluid_thread_self_set_prio(int prio_level)
377 {
378     struct sched_param priority;
379
380     if(prio_level > 0)
381     {
382
383         memset(&priority, 0, sizeof(priority));
384         priority.sched_priority = prio_level;
385
386         if(pthread_setschedparam(pthread_self(), SCHED_FIFO, &priority) == 0)
387         {
388             return;
389         }
390
391 #ifdef DBUS_SUPPORT
392         /* Try to gain high priority via rtkit */
393
394         if(fluid_rtkit_make_realtime(0, prio_level) == 0)
395         {
396             return;
397         }
398
399 #endif
400         FLUID_LOG(FLUID_WARN, "Failed to set thread to high priority");
401     }
402 }
403
404 #ifdef FPE_CHECK
405
406 /***************************************************************
407  *
408  *               Floating point exceptions
409  *
410  *  The floating point exception functions were taken from Ircam's
411  *  jMax source code. http://www.ircam.fr/jmax
412  *
413  *  FIXME: check in config for i386 machine
414  *
415  *  Currently not used. I leave the code here in case we want to pick
416  *  this up again some time later.
417  */
418
419 /* Exception flags */
420 #define _FPU_STATUS_IE    0x001  /* Invalid Operation */
421 #define _FPU_STATUS_DE    0x002  /* Denormalized Operand */
422 #define _FPU_STATUS_ZE    0x004  /* Zero Divide */
423 #define _FPU_STATUS_OE    0x008  /* Overflow */
424 #define _FPU_STATUS_UE    0x010  /* Underflow */
425 #define _FPU_STATUS_PE    0x020  /* Precision */
426 #define _FPU_STATUS_SF    0x040  /* Stack Fault */
427 #define _FPU_STATUS_ES    0x080  /* Error Summary Status */
428
429 /* Macros for accessing the FPU status word.  */
430
431 /* get the FPU status */
432 #define _FPU_GET_SW(sw) __asm__ ("fnstsw %0" : "=m" (*&sw))
433
434 /* clear the FPU status */
435 #define _FPU_CLR_SW() __asm__ ("fnclex" : : )
436
437 /* Purpose:
438  * Checks, if the floating point unit has produced an exception, print a message
439  * if so and clear the exception.
440  */
441 unsigned int fluid_check_fpe_i386(char *explanation)
442 {
443     unsigned int s;
444
445     _FPU_GET_SW(s);
446     _FPU_CLR_SW();
447
448     s &= _FPU_STATUS_IE | _FPU_STATUS_DE | _FPU_STATUS_ZE | _FPU_STATUS_OE | _FPU_STATUS_UE;
449
450     if(s)
451     {
452         FLUID_LOG(FLUID_WARN, "FPE exception (before or in %s): %s%s%s%s%s", explanation,
453                   (s & _FPU_STATUS_IE) ? "Invalid operation " : "",
454                   (s & _FPU_STATUS_DE) ? "Denormal number " : "",
455                   (s & _FPU_STATUS_ZE) ? "Zero divide " : "",
456                   (s & _FPU_STATUS_OE) ? "Overflow " : "",
457                   (s & _FPU_STATUS_UE) ? "Underflow " : "");
458     }
459
460     return s;
461 }
462
463 /* Purpose:
464  * Clear floating point exception.
465  */
466 void fluid_clear_fpe_i386(void)
467 {
468     _FPU_CLR_SW();
469 }
470
471 #endif  // ifdef FPE_CHECK
472
473
474 #endif  // #else    (its POSIX)
475
476
477 /***************************************************************
478  *
479  *               Profiling (Linux, i586 only)
480  *
481  */
482
483 #if WITH_PROFILING
484 /* Profiling interface beetween profiling command shell and audio rendering API
485   (FluidProfile_0004.pdf- 3.2.2).
486   Macros are in defined in fluid_sys.h.
487 */
488
489 /*
490   -----------------------------------------------------------------------------
491   Shell task side |    Profiling interface              |  Audio task side
492   -----------------------------------------------------------------------------
493   profiling       |    Internal    |      |             |      Audio
494   command   <---> |<-- profling -->| Data |<--macros -->| <--> rendering
495   shell           |    API         |      |             |      API
496
497 */
498 /* default parameters for shell command "prof_start" in fluid_sys.c */
499 unsigned short fluid_profile_notes = 0; /* number of generated notes */
500 /* preset bank:0 prog:16 (organ) */
501 unsigned char fluid_profile_bank = FLUID_PROFILE_DEFAULT_BANK;
502 unsigned char fluid_profile_prog = FLUID_PROFILE_DEFAULT_PROG;
503
504 /* print mode */
505 unsigned char fluid_profile_print = FLUID_PROFILE_DEFAULT_PRINT;
506 /* number of measures */
507 unsigned short fluid_profile_n_prof = FLUID_PROFILE_DEFAULT_N_PROF;
508 /* measure duration in ms */
509 unsigned short fluid_profile_dur = FLUID_PROFILE_DEFAULT_DURATION;
510 /* lock between multiple-shell */
511 fluid_atomic_int_t fluid_profile_lock = 0;
512 /**/
513
514 /*----------------------------------------------
515   Profiling Data
516 -----------------------------------------------*/
517 unsigned char fluid_profile_status = PROFILE_STOP; /* command and status */
518 unsigned int fluid_profile_end_ticks = 0;          /* ending position (in ticks) */
519 fluid_profile_data_t fluid_profile_data[] =        /* Data duration */
520 {
521     {"synth_write_* ------------>", 1e10, 0.0, 0.0, 0, 0, 0},
522     {"synth_one_block ---------->", 1e10, 0.0, 0.0, 0, 0, 0},
523     {"synth_one_block:clear ---->", 1e10, 0.0, 0.0, 0, 0, 0},
524     {"synth_one_block:one voice->", 1e10, 0.0, 0.0, 0, 0, 0},
525     {"synth_one_block:all voices>", 1e10, 0.0, 0.0, 0, 0, 0},
526     {"synth_one_block:reverb --->", 1e10, 0.0, 0.0, 0, 0, 0},
527     {"synth_one_block:chorus --->", 1e10, 0.0, 0.0, 0, 0, 0},
528     {"voice:note --------------->", 1e10, 0.0, 0.0, 0, 0, 0},
529     {"voice:release ------------>", 1e10, 0.0, 0.0, 0, 0, 0}
530 };
531
532
533 /*----------------------------------------------
534   Internal profiling API
535 -----------------------------------------------*/
536 /* logging profiling data (used on synthesizer instance deletion) */
537 void fluid_profiling_print(void)
538 {
539     int i;
540
541     printf("fluid_profiling_print\n");
542
543     FLUID_LOG(FLUID_INFO, "Estimated times: min/avg/max (micro seconds)");
544
545     for(i = 0; i < FLUID_PROFILE_NBR; i++)
546     {
547         if(fluid_profile_data[i].count > 0)
548         {
549             FLUID_LOG(FLUID_INFO, "%s: %.3f/%.3f/%.3f",
550                       fluid_profile_data[i].description,
551                       fluid_profile_data[i].min,
552                       fluid_profile_data[i].total / fluid_profile_data[i].count,
553                       fluid_profile_data[i].max);
554         }
555         else
556         {
557             FLUID_LOG(FLUID_DBG, "%s: no profiling available",
558                       fluid_profile_data[i].description);
559         }
560     }
561 }
562
563 /* Macro that returns cpu load in percent (%)
564  * @dur: duration (micro second).
565  * @sample_rate: sample_rate used in audio driver (Hz).
566  * @n_amples: number of samples collected during 'dur' duration.
567 */
568 #define fluid_profile_load(dur,sample_rate,n_samples) \
569         (dur * sample_rate / n_samples / 10000.0)
570
571
572 /* prints cpu loads only
573 *
574 * @param sample_rate the sample rate of audio output.
575 * @param out output stream device.
576 *
577 * ------------------------------------------------------------------------------
578 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
579 * ------------------------------------------------------------------------------
580 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
581 * -------|---------|---------|----------|---------|---------|-------------------
582 *     250|   41.544|   41.544|     0.000|    0.000|    0.163|              612
583 */
584 static void fluid_profiling_print_load(double sample_rate, fluid_ostream_t out)
585 {
586     unsigned int n_voices; /* voices number */
587     static const char max_voices_not_available[] = "      not available";
588     const char *pmax_voices;
589     char max_voices_available[20];
590
591     /* First computes data to be printed */
592     double  total, voices, reverb, chorus, all_voices, voice;
593     /* voices number */
594     n_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
595                fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_voices /
596                fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count : 0;
597
598     /* total load (%) */
599     total =  fluid_profile_data[FLUID_PROF_WRITE].count ?
600              fluid_profile_load(fluid_profile_data[FLUID_PROF_WRITE].total, sample_rate,
601                                 fluid_profile_data[FLUID_PROF_WRITE].n_samples) : 0;
602
603     /* reverb load (%) */
604     reverb = fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].count ?
605              fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].total,
606                                 sample_rate,
607                                 fluid_profile_data[FLUID_PROF_ONE_BLOCK_REVERB].n_samples) : 0;
608
609     /* chorus load (%) */
610     chorus = fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].count ?
611              fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].total,
612                                 sample_rate,
613                                 fluid_profile_data[FLUID_PROF_ONE_BLOCK_CHORUS].n_samples) : 0;
614
615     /* total voices load: total - reverb - chorus (%) */
616     voices = total - reverb - chorus;
617
618     /* One voice load (%): all_voices / n_voices. */
619     all_voices = fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].count ?
620                  fluid_profile_load(fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].total,
621                                     sample_rate,
622                                     fluid_profile_data[FLUID_PROF_ONE_BLOCK_VOICES].n_samples) : 0;
623
624     voice = n_voices ?  all_voices / n_voices : 0;
625
626     /* estimated maximum voices number */
627     if(voice > 0)
628     {
629         FLUID_SNPRINTF(max_voices_available, sizeof(max_voices_available),
630                        "%17d", (unsigned int)((100.0 - reverb - chorus) / voice));
631         pmax_voices = max_voices_available;
632     }
633     else
634     {
635         pmax_voices = max_voices_not_available;
636     }
637
638     /* Now prints data */
639     fluid_ostream_printf(out,
640                          " ------------------------------------------------------------------------------\n");
641     fluid_ostream_printf(out,
642                          " Cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond) and maximum voices\n",
643                          sample_rate, 1000000.0 / sample_rate);
644     fluid_ostream_printf(out,
645                          " ------------------------------------------------------------------------------\n");
646     fluid_ostream_printf(out,
647                          " nVoices| total(%%)|voices(%%)| reverb(%%)|chorus(%%)| voice(%%)|estimated maxVoices\n");
648     fluid_ostream_printf(out,
649                          " -------|---------|---------|----------|---------|---------|-------------------\n");
650     fluid_ostream_printf(out,
651                          "%8d|%9.3f|%9.3f|%10.3f|%9.3f|%9.3f|%s\n", n_voices, total, voices,
652                          reverb, chorus, voice, pmax_voices);
653 }
654
655 /*
656 * prints profiling data (used by profile shell command: prof_start).
657 * The function is an internal profiling API between the "profile" command
658 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
659 *
660 * @param sample_rate the sample rate of audio output.
661 * @param out output stream device.
662 *
663 * When print mode is 1, the function prints all the informations (see below).
664 * When print mode is 0, the fonction prints only the cpu loads.
665 *
666 * ------------------------------------------------------------------------------
667 * Duration(microsecond) and cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond)
668 * ------------------------------------------------------------------------------
669 * Code under profiling       |Voices|       Duration (microsecond)   |  Load(%)
670 *                            |   nbr|       min|       avg|       max|
671 * ---------------------------|------|--------------------------------|----------
672 * synth_write_* ------------>|   250|      3.91|   2188.82|   3275.00|  41.544
673 * synth_one_block ---------->|   250|   1150.70|   2273.56|   3241.47|  41.100
674 * synth_one_block:clear ---->|   250|      3.07|      4.62|     61.18|   0.084
675 * synth_one_block:one voice->|     1|      4.19|      9.02|   1044.27|   0.163
676 * synth_one_block:all voices>|   250|   1138.41|   2259.11|   3217.73|  40.839
677 * synth_one_block:reverb --->| no profiling available
678 * synth_one_block:chorus --->| no profiling available
679 * voice:note --------------->| no profiling available
680 * voice:release ------------>| no profiling available
681 * ------------------------------------------------------------------------------
682 * Cpu loads(%) (sr: 44100 Hz, sp: 22.68 microsecond) and maximum voices
683 * ------------------------------------------------------------------------------
684 * nVoices| total(%)|voices(%)| reverb(%)|chorus(%)| voice(%)|estimated maxVoices
685 * -------|---------|---------|----------|---------|---------|-------------------
686 *     250|   41.544|   41.544|     0.000|    0.000|    0.163|              612
687 */
688 void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out)
689 {
690     int i;
691
692     if(fluid_profile_print)
693     {
694         /* print all details: Duration(microsecond) and cpu loads(%) */
695         fluid_ostream_printf(out,
696                              " ------------------------------------------------------------------------------\n");
697         fluid_ostream_printf(out,
698                              " Duration(microsecond) and cpu loads(%%) (sr:%6.0f Hz, sp:%6.2f microsecond)\n",
699                              sample_rate, 1000000.0 / sample_rate);
700         fluid_ostream_printf(out,
701                              " ------------------------------------------------------------------------------\n");
702         fluid_ostream_printf(out,
703                              " Code under profiling       |Voices|       Duration (microsecond)   |  Load(%%)\n");
704         fluid_ostream_printf(out,
705                              "                            |   nbr|       min|       avg|       max|\n");
706         fluid_ostream_printf(out,
707                              " ---------------------------|------|--------------------------------|----------\n");
708
709         for(i = 0; i < FLUID_PROFILE_NBR; i++)
710         {
711             unsigned int count = fluid_profile_data[i].count;
712
713             if(count > 0)
714             {
715                 /* data are available */
716
717                 if(FLUID_PROF_WRITE <= i && i <= FLUID_PROF_ONE_BLOCK_CHORUS)
718                 {
719                     double load = fluid_profile_load(fluid_profile_data[i].total, sample_rate,
720                                                      fluid_profile_data[i].n_samples);
721                     fluid_ostream_printf(out, " %s|%6d|%10.2f|%10.2f|%10.2f|%8.3f\n",
722                                          fluid_profile_data[i].description, /* code under profiling */
723                                          fluid_profile_data[i].n_voices / count, /* voices number */
724                                          fluid_profile_data[i].min,              /* minimum duration */
725                                          fluid_profile_data[i].total / count,    /* average duration */
726                                          fluid_profile_data[i].max,              /* maximum duration */
727                                          load);                                  /* cpu load */
728                 }
729                 else
730                 {
731                     /* note and release duration */
732                     fluid_ostream_printf(out, " %s|%6d|%10.0f|%10.0f|%10.0f|\n",
733                                          fluid_profile_data[i].description, /* code under profiling */
734                                          fluid_profile_data[i].n_voices / count,
735                                          fluid_profile_data[i].min,              /* minimum duration */
736                                          fluid_profile_data[i].total / count,    /* average duration */
737                                          fluid_profile_data[i].max);             /* maximum duration */
738                 }
739             }
740             else
741             {
742                 /* data aren't available */
743                 fluid_ostream_printf(out,
744                                      " %s| no profiling available\n", fluid_profile_data[i].description);
745             }
746         }
747     }
748
749     /* prints cpu loads only */
750     fluid_profiling_print_load(sample_rate, out);/* prints cpu loads */
751 }
752
753 /*
754  Returns true if the user cancels the current profiling measurement.
755  Actually this is implemented using the <ENTER> key. To add this functionality:
756  1) Adds #define FLUID_PROFILE_CANCEL in fluid_sys.h.
757  2) Adds the necessary code inside fluid_profile_is_cancel().
758
759  When FLUID_PROFILE_CANCEL is not defined, the function return FALSE.
760 */
761 int fluid_profile_is_cancel_req(void)
762 {
763 #ifdef FLUID_PROFILE_CANCEL
764
765 #if defined(WIN32)      /* Windows specific stuff */
766     /* Profile cancellation is supported for Windows */
767     /* returns TRUE if key <ENTER> is depressed */
768     return(GetAsyncKeyState(VK_RETURN) & 0x1);
769
770 #elif defined(__OS2__)  /* OS/2 specific stuff */
771     /* Profile cancellation isn't yet supported for OS2 */
772     /* For OS2, replaces the following  line with the function that returns
773     true when the keyboard key <ENTER> is depressed */
774     return FALSE; /* default value */
775
776 #else   /* POSIX stuff */
777     /* Profile cancellation is supported for Linux */
778     /* returns true is <ENTER> is depressed */
779     {
780         /* Here select() is used to poll the standard input to see if an input
781          is ready. As the standard input is usually buffered, the user
782          needs to depress <ENTER> to set the input to a "ready" state.
783         */
784         struct timeval tv;
785         fd_set fds;    /* just one fds need to be polled */
786         tv.tv_sec = 0; /* Setting both values to 0, means a 0 timeout */
787         tv.tv_usec = 0;
788         FD_ZERO(&fds); /* reset fds */
789         FD_SET(STDIN_FILENO, &fds); /* sets fds to poll standard input only */
790         select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); /* polling */
791         return (FD_ISSET(0, &fds)); /* returns true if standard input is ready */
792     }
793 #endif /* OS stuff */
794
795 #else /* FLUID_PROFILE_CANCEL not defined */
796     return FALSE; /* default value */
797 #endif /* FLUID_PROFILE_CANCEL */
798 }
799
800 /**
801 * Returns status used in shell command "prof_start".
802 * The function is an internal profiling API between the "profile" command
803 * prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
804 *
805 * @return status
806 * - PROFILE_READY profiling data are ready.
807 * - PROFILE_RUNNING, profiling data are still under acquisition.
808 * - PROFILE_CANCELED, acquisition has been cancelled by the user.
809 * - PROFILE_STOP, no acquisition in progress.
810 *
811 * When status is PROFILE_RUNNING, the caller can do passive waiting, or other
812 * work before recalling the function later.
813 */
814 int fluid_profile_get_status(void)
815 {
816     /* Checks if user has requested to cancel the current measurement */
817     /* Cancellation must have precedence over other status */
818     if(fluid_profile_is_cancel_req())
819     {
820         fluid_profile_start_stop(0, 0); /* stops the measurement */
821         return PROFILE_CANCELED;
822     }
823
824     switch(fluid_profile_status)
825     {
826     case PROFILE_READY:
827         return PROFILE_READY; /* profiling data are ready */
828
829     case PROFILE_START:
830         return PROFILE_RUNNING;/* profiling data are under acquisition */
831
832     default:
833         return PROFILE_STOP;
834     }
835 }
836
837 /**
838 *  Starts or stops profiling measurement.
839 *  The function is an internal profiling API between the "profile" command
840 *  prof_start and audio rendering API (see FluidProfile_0004.pdf - 3.2.2).
841 *
842 *  @param end_tick end position of the measure (in ticks).
843 *  - If end_tick is greater then 0, the function starts a measure if a measure
844 *    isn't running. If a measure is already running, the function does nothing
845 *    and returns.
846 *  - If end_tick is 0, the function stops a measure.
847 *  @param clear_data,
848 *  - If clear_data is 0, the function clears fluid_profile_data before starting
849 *    a measure, otherwise, the data from the started measure will be accumulated
850 *    within fluid_profile_data.
851 */
852 void fluid_profile_start_stop(unsigned int end_ticks, short clear_data)
853 {
854     if(end_ticks)    /* This is a "start" request */
855     {
856         /* Checks if a measure is already running */
857         if(fluid_profile_status != PROFILE_START)
858         {
859             short i;
860             fluid_profile_end_ticks = end_ticks;
861
862             /* Clears profile data */
863             if(clear_data == 0)
864                 for(i = 0; i < FLUID_PROFILE_NBR; i++)
865                 {
866                     fluid_profile_data[i].min = 1e10;/* min sets to max value */
867                     fluid_profile_data[i].max = 0;   /* maximum sets to min value */
868                     fluid_profile_data[i].total = 0; /* total duration microsecond */
869                     fluid_profile_data[i].count = 0;    /* data count */
870                     fluid_profile_data[i].n_voices = 0; /* voices number */
871                     fluid_profile_data[i].n_samples = 0;/* audio samples number */
872                 }
873
874             fluid_profile_status = PROFILE_START;       /* starts profiling */
875         }
876
877         /* else do nothing when profiling is already started */
878     }
879     else /* This is a "stop" request */
880     {
881         /* forces the current running profile (if any) to stop */
882         fluid_profile_status = PROFILE_STOP;    /* stops profiling */
883     }
884 }
885
886 #endif /* WITH_PROFILING */
887
888 /***************************************************************
889  *
890  *               Threads
891  *
892  */
893
894 #if OLD_GLIB_THREAD_API
895
896 /* Rather than inline this one, we just declare it as a function, to prevent
897  * GCC warning about inline failure. */
898 fluid_cond_t *
899 new_fluid_cond(void)
900 {
901     if(!g_thread_supported())
902     {
903         g_thread_init(NULL);
904     }
905
906     return g_cond_new();
907 }
908
909 #endif
910
911 static gpointer
912 fluid_thread_high_prio(gpointer data)
913 {
914     fluid_thread_info_t *info = data;
915
916     fluid_thread_self_set_prio(info->prio_level);
917
918     info->func(info->data);
919     FLUID_FREE(info);
920
921     return NULL;
922 }
923
924 /**
925  * Create a new thread.
926  * @param func Function to execute in new thread context
927  * @param data User defined data to pass to func
928  * @param prio_level Priority level.  If greater than 0 then high priority scheduling will
929  *   be used, with the given priority level (used by pthreads only).  0 uses normal scheduling.
930  * @param detach If TRUE, 'join' does not work and the thread destroys itself when finished.
931  * @return New thread pointer or NULL on error
932  */
933 fluid_thread_t *
934 new_fluid_thread(const char *name, fluid_thread_func_t func, void *data, int prio_level, int detach)
935 {
936     GThread *thread;
937     fluid_thread_info_t *info;
938     GError *err = NULL;
939
940     g_return_val_if_fail(func != NULL, NULL);
941
942 #if OLD_GLIB_THREAD_API
943
944     /* Make sure g_thread_init has been called.
945      * FIXME - Probably not a good idea in a shared library,
946      * but what can we do *and* remain backwards compatible? */
947     if(!g_thread_supported())
948     {
949         g_thread_init(NULL);
950     }
951
952 #endif
953
954     if(prio_level > 0)
955     {
956         info = FLUID_NEW(fluid_thread_info_t);
957
958         if(!info)
959         {
960             FLUID_LOG(FLUID_ERR, "Out of memory");
961             return NULL;
962         }
963
964         info->func = func;
965         info->data = data;
966         info->prio_level = prio_level;
967 #if NEW_GLIB_THREAD_API
968         thread = g_thread_try_new(name, fluid_thread_high_prio, info, &err);
969 #else
970         thread = g_thread_create(fluid_thread_high_prio, info, detach == FALSE, &err);
971 #endif
972     }
973
974 #if NEW_GLIB_THREAD_API
975     else
976     {
977         thread = g_thread_try_new(name, (GThreadFunc)func, data, &err);
978     }
979
980 #else
981     else
982     {
983         thread = g_thread_create((GThreadFunc)func, data, detach == FALSE, &err);
984     }
985
986 #endif
987
988     if(!thread)
989     {
990         FLUID_LOG(FLUID_ERR, "Failed to create the thread: %s",
991                   fluid_gerror_message(err));
992         g_clear_error(&err);
993         return NULL;
994     }
995
996 #if NEW_GLIB_THREAD_API
997
998     if(detach)
999     {
1000         g_thread_unref(thread);    // Release thread reference, if caller wants to detach
1001     }
1002
1003 #endif
1004
1005     return thread;
1006 }
1007
1008 /**
1009  * Frees data associated with a thread (does not actually stop thread).
1010  * @param thread Thread to free
1011  */
1012 void
1013 delete_fluid_thread(fluid_thread_t *thread)
1014 {
1015     /* Threads free themselves when they quit, nothing to do */
1016 }
1017
1018 /**
1019  * Join a thread (wait for it to terminate).
1020  * @param thread Thread to join
1021  * @return FLUID_OK
1022  */
1023 int
1024 fluid_thread_join(fluid_thread_t *thread)
1025 {
1026     g_thread_join(thread);
1027
1028     return FLUID_OK;
1029 }
1030
1031
1032 static fluid_thread_return_t
1033 fluid_timer_run(void *data)
1034 {
1035     fluid_timer_t *timer;
1036     int count = 0;
1037     int cont;
1038     long start;
1039     long delay;
1040
1041     timer = (fluid_timer_t *)data;
1042
1043     /* keep track of the start time for absolute positioning */
1044     start = fluid_curtime();
1045
1046     while(timer->cont)
1047     {
1048         cont = (*timer->callback)(timer->data, fluid_curtime() - start);
1049
1050         count++;
1051
1052         if(!cont)
1053         {
1054             break;
1055         }
1056
1057         /* to avoid incremental time errors, calculate the delay between
1058            two callbacks bringing in the "absolute" time (count *
1059            timer->msec) */
1060         delay = (count * timer->msec) - (fluid_curtime() - start);
1061
1062         if(delay > 0)
1063         {
1064             fluid_msleep(delay);
1065         }
1066     }
1067
1068     FLUID_LOG(FLUID_DBG, "Timer thread finished");
1069
1070     if(timer->auto_destroy)
1071     {
1072         FLUID_FREE(timer);
1073     }
1074
1075     return FLUID_THREAD_RETURN_VALUE;
1076 }
1077
1078 fluid_timer_t *
1079 new_fluid_timer(int msec, fluid_timer_callback_t callback, void *data,
1080                 int new_thread, int auto_destroy, int high_priority)
1081 {
1082     fluid_timer_t *timer;
1083
1084     timer = FLUID_NEW(fluid_timer_t);
1085
1086     if(timer == NULL)
1087     {
1088         FLUID_LOG(FLUID_ERR, "Out of memory");
1089         return NULL;
1090     }
1091
1092     timer->msec = msec;
1093     timer->callback = callback;
1094     timer->data = data;
1095     timer->cont = TRUE ;
1096     timer->thread = NULL;
1097     timer->auto_destroy = auto_destroy;
1098
1099     if(new_thread)
1100     {
1101         timer->thread = new_fluid_thread("timer", fluid_timer_run, timer, high_priority
1102                                          ? FLUID_SYS_TIMER_HIGH_PRIO_LEVEL : 0, FALSE);
1103
1104         if(!timer->thread)
1105         {
1106             FLUID_FREE(timer);
1107             return NULL;
1108         }
1109     }
1110     else
1111     {
1112         fluid_timer_run(timer);   /* Run directly, instead of as a separate thread */
1113
1114         if(auto_destroy)
1115         {
1116             /* do NOT return freed memory */
1117             return NULL;
1118         }
1119     }
1120
1121     return timer;
1122 }
1123
1124 void
1125 delete_fluid_timer(fluid_timer_t *timer)
1126 {
1127     int auto_destroy;
1128     fluid_return_if_fail(timer != NULL);
1129
1130     auto_destroy = timer->auto_destroy;
1131
1132     timer->cont = 0;
1133     fluid_timer_join(timer);
1134
1135     /* Shouldn't access timer now if auto_destroy enabled, since it has been destroyed */
1136
1137     if(!auto_destroy)
1138     {
1139         FLUID_FREE(timer);
1140     }
1141 }
1142
1143 int
1144 fluid_timer_join(fluid_timer_t *timer)
1145 {
1146     int auto_destroy;
1147
1148     if(timer->thread)
1149     {
1150         auto_destroy = timer->auto_destroy;
1151         fluid_thread_join(timer->thread);
1152
1153         if(!auto_destroy)
1154         {
1155             timer->thread = NULL;
1156         }
1157     }
1158
1159     return FLUID_OK;
1160 }
1161
1162
1163 /***************************************************************
1164  *
1165  *               Sockets and I/O
1166  *
1167  */
1168
1169 /**
1170  * Get standard in stream handle.
1171  * @return Standard in stream.
1172  */
1173 fluid_istream_t
1174 fluid_get_stdin(void)
1175 {
1176     return STDIN_FILENO;
1177 }
1178
1179 /**
1180  * Get standard output stream handle.
1181  * @return Standard out stream.
1182  */
1183 fluid_ostream_t
1184 fluid_get_stdout(void)
1185 {
1186     return STDOUT_FILENO;
1187 }
1188
1189 /**
1190  * Read a line from an input stream.
1191  * @return 0 if end-of-stream, -1 if error, non zero otherwise
1192  */
1193 int
1194 fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt,
1195                        char *buf, int len)
1196 {
1197 #if WITH_READLINE
1198
1199     if(in == fluid_get_stdin())
1200     {
1201         char *line;
1202
1203         line = readline(prompt);
1204
1205         if(line == NULL)
1206         {
1207             return -1;
1208         }
1209
1210         FLUID_SNPRINTF(buf, len, "%s", line);
1211         buf[len - 1] = 0;
1212
1213         if(buf[0] != '\0')
1214         {
1215             add_history(buf);
1216         }
1217
1218         free(line);
1219         return 1;
1220     }
1221     else
1222 #endif
1223     {
1224         fluid_ostream_printf(out, "%s", prompt);
1225         return fluid_istream_gets(in, buf, len);
1226     }
1227 }
1228
1229 /**
1230  * Reads a line from an input stream (socket).
1231  * @param in The input socket
1232  * @param buf Buffer to store data to
1233  * @param len Maximum length to store to buf
1234  * @return 1 if a line was read, 0 on end of stream, -1 on error
1235  */
1236 static int
1237 fluid_istream_gets(fluid_istream_t in, char *buf, int len)
1238 {
1239     char c;
1240     int n;
1241
1242     buf[len - 1] = 0;
1243
1244     while(--len > 0)
1245     {
1246 #ifndef WIN32
1247         n = read(in, &c, 1);
1248
1249         if(n == -1)
1250         {
1251             return -1;
1252         }
1253
1254 #else
1255
1256         /* Handle read differently depending on if its a socket or file descriptor */
1257         if(!(in & FLUID_SOCKET_FLAG))
1258         {
1259             n = read(in, &c, 1);
1260
1261             if(n == -1)
1262             {
1263                 return -1;
1264             }
1265         }
1266         else
1267         {
1268 #ifdef NETWORK_SUPPORT
1269             n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
1270             if(n == SOCKET_ERROR)
1271 #endif
1272             {
1273                 return -1;
1274             }
1275         }
1276
1277 #endif
1278
1279         if(n == 0)
1280         {
1281             *buf = 0;
1282             return 0;
1283         }
1284
1285         if(c == '\n')
1286         {
1287             *buf = 0;
1288             return 1;
1289         }
1290
1291         /* Store all characters excluding CR */
1292         if(c != '\r')
1293         {
1294             *buf++ = c;
1295         }
1296     }
1297
1298     return -1;
1299 }
1300
1301 /**
1302  * Send a printf style string with arguments to an output stream (socket).
1303  * @param out Output stream
1304  * @param format printf style format string
1305  * @param ... Arguments for the printf format string
1306  * @return Number of bytes written or -1 on error
1307  */
1308 int
1309 fluid_ostream_printf(fluid_ostream_t out, const char *format, ...)
1310 {
1311     char buf[4096];
1312     va_list args;
1313     int len;
1314
1315     va_start(args, format);
1316     len = FLUID_VSNPRINTF(buf, 4095, format, args);
1317     va_end(args);
1318
1319     if(len == 0)
1320     {
1321         return 0;
1322     }
1323
1324     if(len < 0)
1325     {
1326         printf("fluid_ostream_printf: buffer overflow");
1327         return -1;
1328     }
1329
1330     buf[4095] = 0;
1331
1332 #ifndef WIN32
1333     return write(out, buf, FLUID_STRLEN(buf));
1334 #else
1335     {
1336         int retval;
1337
1338         /* Handle write differently depending on if its a socket or file descriptor */
1339         if(!(out & FLUID_SOCKET_FLAG))
1340         {
1341             return write(out, buf, (unsigned int)FLUID_STRLEN(buf));
1342         }
1343
1344 #ifdef NETWORK_SUPPORT
1345         /* Socket */
1346         retval = send(out & ~FLUID_SOCKET_FLAG, buf, (int)FLUID_STRLEN(buf), 0);
1347         return retval != SOCKET_ERROR ? retval : -1;
1348 #else
1349         return -1;
1350 #endif
1351     }
1352 #endif
1353 }
1354
1355 #ifdef NETWORK_SUPPORT
1356
1357 int fluid_server_socket_join(fluid_server_socket_t *server_socket)
1358 {
1359     return fluid_thread_join(server_socket->thread);
1360 }
1361
1362 static int fluid_socket_init(void)
1363 {
1364 #ifdef _WIN32
1365     WSADATA wsaData;
1366     int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
1367
1368     if(res != 0)
1369     {
1370         FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
1371         return FLUID_FAILED;
1372     }
1373
1374 #endif
1375
1376     return FLUID_OK;
1377 }
1378
1379 static void fluid_socket_cleanup(void)
1380 {
1381 #ifdef _WIN32
1382     WSACleanup();
1383 #endif
1384 }
1385
1386 static int fluid_socket_get_error(void)
1387 {
1388 #ifdef _WIN32
1389     return (int)WSAGetLastError();
1390 #else
1391     return errno;
1392 #endif
1393 }
1394
1395 fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock)
1396 {
1397     return sock | FLUID_SOCKET_FLAG;
1398 }
1399
1400 fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock)
1401 {
1402     return sock | FLUID_SOCKET_FLAG;
1403 }
1404
1405 void fluid_socket_close(fluid_socket_t sock)
1406 {
1407     if(sock != INVALID_SOCKET)
1408     {
1409 #ifdef _WIN32
1410         closesocket(sock);
1411
1412 #else
1413         close(sock);
1414 #endif
1415     }
1416 }
1417
1418 static fluid_thread_return_t fluid_server_socket_run(void *data)
1419 {
1420     fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
1421     fluid_socket_t client_socket;
1422 #ifdef IPV6_SUPPORT
1423     struct sockaddr_in6 addr;
1424 #else
1425     struct sockaddr_in addr;
1426 #endif
1427
1428 #ifdef HAVE_INETNTOP
1429 #ifdef IPV6_SUPPORT
1430     char straddr[INET6_ADDRSTRLEN];
1431 #else
1432     char straddr[INET_ADDRSTRLEN];
1433 #endif /* IPV6_SUPPORT */
1434 #endif /* HAVE_INETNTOP */
1435
1436     socklen_t addrlen = sizeof(addr);
1437     int r;
1438     FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
1439
1440     FLUID_LOG(FLUID_DBG, "Server listening for connections");
1441
1442     while(server_socket->cont)
1443     {
1444         client_socket = accept(server_socket->socket, (struct sockaddr *)&addr, &addrlen);
1445
1446         FLUID_LOG(FLUID_DBG, "New client connection");
1447
1448         if(client_socket == INVALID_SOCKET)
1449         {
1450             if(server_socket->cont)
1451             {
1452                 FLUID_LOG(FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
1453             }
1454
1455             server_socket->cont = 0;
1456             return FLUID_THREAD_RETURN_VALUE;
1457         }
1458         else
1459         {
1460 #ifdef HAVE_INETNTOP
1461
1462 #ifdef IPV6_SUPPORT
1463             inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
1464 #else
1465             inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
1466 #endif
1467
1468             r = server_socket->func(server_socket->data, client_socket,
1469                                     straddr);
1470 #else
1471             r = server_socket->func(server_socket->data, client_socket,
1472                                     inet_ntoa(addr.sin_addr));
1473 #endif
1474
1475             if(r != 0)
1476             {
1477                 fluid_socket_close(client_socket);
1478             }
1479         }
1480     }
1481
1482     FLUID_LOG(FLUID_DBG, "Server closing");
1483
1484     return FLUID_THREAD_RETURN_VALUE;
1485 }
1486
1487 fluid_server_socket_t *
1488 new_fluid_server_socket(int port, fluid_server_func_t func, void *data)
1489 {
1490     fluid_server_socket_t *server_socket;
1491 #ifdef IPV6_SUPPORT
1492     struct sockaddr_in6 addr;
1493 #else
1494     struct sockaddr_in addr;
1495 #endif
1496
1497     fluid_socket_t sock;
1498
1499     fluid_return_val_if_fail(func != NULL, NULL);
1500
1501     if(fluid_socket_init() != FLUID_OK)
1502     {
1503         return NULL;
1504     }
1505
1506 #ifdef IPV6_SUPPORT
1507     sock = socket(AF_INET6, SOCK_STREAM, 0);
1508
1509     if(sock == INVALID_SOCKET)
1510     {
1511         FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1512         fluid_socket_cleanup();
1513         return NULL;
1514     }
1515
1516     FLUID_MEMSET(&addr, 0, sizeof(addr));
1517     addr.sin6_family = AF_INET6;
1518     addr.sin6_port = htons((uint16_t)port);
1519     addr.sin6_addr = in6addr_any;
1520 #else
1521
1522     sock = socket(AF_INET, SOCK_STREAM, 0);
1523
1524     if(sock == INVALID_SOCKET)
1525     {
1526         FLUID_LOG(FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
1527         fluid_socket_cleanup();
1528         return NULL;
1529     }
1530
1531     FLUID_MEMSET(&addr, 0, sizeof(addr));
1532     addr.sin_family = AF_INET;
1533     addr.sin_port = htons((uint16_t)port);
1534     addr.sin_addr.s_addr = htonl(INADDR_ANY);
1535 #endif
1536
1537     if(bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
1538     {
1539         FLUID_LOG(FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
1540         fluid_socket_close(sock);
1541         fluid_socket_cleanup();
1542         return NULL;
1543     }
1544
1545     if(listen(sock, SOMAXCONN) == SOCKET_ERROR)
1546     {
1547         FLUID_LOG(FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
1548         fluid_socket_close(sock);
1549         fluid_socket_cleanup();
1550         return NULL;
1551     }
1552
1553     server_socket = FLUID_NEW(fluid_server_socket_t);
1554
1555     if(server_socket == NULL)
1556     {
1557         FLUID_LOG(FLUID_ERR, "Out of memory");
1558         fluid_socket_close(sock);
1559         fluid_socket_cleanup();
1560         return NULL;
1561     }
1562
1563     server_socket->socket = sock;
1564     server_socket->func = func;
1565     server_socket->data = data;
1566     server_socket->cont = 1;
1567
1568     server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
1569                             0, FALSE);
1570
1571     if(server_socket->thread == NULL)
1572     {
1573         FLUID_FREE(server_socket);
1574         fluid_socket_close(sock);
1575         fluid_socket_cleanup();
1576         return NULL;
1577     }
1578
1579     return server_socket;
1580 }
1581
1582 void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
1583 {
1584     fluid_return_if_fail(server_socket != NULL);
1585
1586     server_socket->cont = 0;
1587
1588     if(server_socket->socket != INVALID_SOCKET)
1589     {
1590         fluid_socket_close(server_socket->socket);
1591     }
1592
1593     if(server_socket->thread)
1594     {
1595         fluid_thread_join(server_socket->thread);
1596         delete_fluid_thread(server_socket->thread);
1597     }
1598
1599     FLUID_FREE(server_socket);
1600
1601     // Should be called the same number of times as fluid_socket_init()
1602     fluid_socket_cleanup();
1603 }
1604
1605 #endif // NETWORK_SUPPORT