Fix various compiler warnings (bug #322)
[asterisk/asterisk.git] / res / res_musiconhold.c
index 0d540ae..5ca4f5f 100755 (executable)
@@ -27,6 +27,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <sys/time.h>
@@ -39,7 +40,6 @@
 #endif
 #include <unistd.h>
 #include <sys/ioctl.h>
-#include <sys/wait.h>
 
 #include <pthread.h>
 
@@ -84,7 +84,6 @@ struct mohclass {
 
 struct mohdata {
        int pipe[2];
-       int origrfmt;
        int origwfmt;
        struct mohclass *parent;
        struct mohdata *next;
@@ -92,19 +91,12 @@ struct mohdata {
 
 static struct mohclass *mohclasses;
 
-static pthread_mutex_t moh_lock = AST_MUTEX_INITIALIZER;
+static ast_mutex_t moh_lock = AST_MUTEX_INITIALIZER;
 
+#define LOCAL_MPG_123 "/usr/local/bin/mpg123"
 #define MPG_123 "/usr/bin/mpg123"
 #define MAX_MP3S 256
 
-static void child_handler(int sig)
-{
-       int status;
-       if (wait4(-1,&status, WNOHANG, NULL)<1) 
-               if (option_debug)       
-                       ast_log(LOG_DEBUG, "Huh?  Child handler, but nobody there?\n");
-}
-
 static int spawn_mp3(struct mohclass *class)
 {
        int fds[2];
@@ -121,7 +113,7 @@ static int spawn_mp3(struct mohclass *class)
                ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
                return -1;
        }
-       argv[0] = MPG_123;
+       argv[0] = "mpg123";
        argv[1] = "-q";
        argv[2] = "-s";
        argv[3] = "--mono";
@@ -190,7 +182,12 @@ static int spawn_mp3(struct mohclass *class)
                        close(x);
                /* Child */
                chdir(class->dir);
+               /* Default install is /usr/local/bin */
+               execv(LOCAL_MPG_123, argv);
+               /* Many places have it in /usr/bin */
                execv(MPG_123, argv);
+               /* Check PATH as a last-ditch effort */
+               execvp("mpg123", argv);
                ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
                exit(1);
        } else {
@@ -202,12 +199,24 @@ static int spawn_mp3(struct mohclass *class)
 
 static void *monmp3thread(void *data)
 {
+#define        MOH_MS_INTERVAL         100
+
        struct mohclass *class = data;
        struct mohdata *moh;
        char buf[8192];
        short sbuf[8192];
        int res, res2;
-       signal(SIGCHLD, child_handler);
+       struct timeval tv;
+       struct timeval tv_tmp;
+       long error_sec, error_usec;
+       long delay;
+
+       tv_tmp.tv_sec = 0;
+       tv_tmp.tv_usec = 0;
+       tv.tv_sec = 0;
+       tv.tv_usec = 0;
+       error_sec = 0;
+       error_usec = 0;
        for(;/* ever */;) {
                /* Spawn mp3 player if it's not there */
                if (class->srcfd < 0)  {
@@ -221,9 +230,40 @@ static void *monmp3thread(void *data)
                        /* Pause some amount of time */
                        res = read(class->pseudofd, buf, sizeof(buf));
                } else {
-                       /* otherwise just sleep (unreliable) */
-                       usleep(250000);
-                       res = 2000;
+                       /* Reliable sleep */
+                       if (gettimeofday(&tv_tmp, NULL) < 0) {
+                               ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
+                               return NULL;
+                       }
+                       if (((unsigned long)(tv.tv_sec) > 0)&&((unsigned long)(tv.tv_usec) > 0)) {
+                               if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv.tv_usec)) {
+                                       tv_tmp.tv_usec += 1000000;
+                                       tv_tmp.tv_sec -= 1;
+                               }
+                               error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv.tv_sec);
+                               error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv.tv_usec);
+                       } else {
+                               error_sec = 0;
+                               error_usec = 0;
+                       }
+                       if (error_sec * 1000 + error_usec / 1000 < MOH_MS_INTERVAL) {
+                               tv.tv_sec = tv_tmp.tv_sec + (MOH_MS_INTERVAL/1000 - error_sec);
+                               tv.tv_usec = tv_tmp.tv_usec + ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec);
+                               delay = (MOH_MS_INTERVAL/1000 - error_sec) * 1000 +
+                                                       ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec) / 1000;
+                       } else {
+                               ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
+                               tv.tv_sec = tv_tmp.tv_sec;
+                               tv.tv_usec = tv_tmp.tv_usec;
+                               delay = 0;
+                       }
+                       if (tv.tv_usec > 1000000) {
+                               tv.tv_sec++;
+                               tv.tv_usec-= 1000000;
+                       }
+                       if (delay > 0)
+                               usleep(delay * 1000);
+                       res = 800;              /* 800 samples */
                }
                if (!class->members)
                        continue;
@@ -240,7 +280,7 @@ static void *monmp3thread(void *data)
                                ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2);
                        continue;
                }
-               ast_pthread_mutex_lock(&moh_lock);
+               ast_mutex_lock(&moh_lock);
                moh = class->members;
                while(moh) {
                        /* Write data */
@@ -249,7 +289,7 @@ static void *monmp3thread(void *data)
                                    ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
                        moh = moh->next;
                }
-               pthread_mutex_unlock(&moh_lock);
+               ast_mutex_unlock(&moh_lock);
        }
        return NULL;
 }
@@ -329,8 +369,8 @@ static struct mohdata *mohalloc(struct mohclass *cl)
 static void moh_release(struct ast_channel *chan, void *data)
 {
        struct mohdata *moh = data, *prev, *cur;
-       int oldrfmt, oldwfmt;
-       ast_pthread_mutex_lock(&moh_lock);
+       int oldwfmt;
+       ast_mutex_lock(&moh_lock);
        /* Unlink */
        prev = NULL;
        cur = moh->parent->members;
@@ -345,16 +385,14 @@ static void moh_release(struct ast_channel *chan, void *data)
                prev = cur;
                cur = cur->next;
        }
-       ast_pthread_mutex_unlock(&moh_lock);
+       ast_mutex_unlock(&moh_lock);
        close(moh->pipe[0]);
        close(moh->pipe[1]);
-       oldrfmt = moh->origrfmt;
        oldwfmt = moh->origwfmt;
        free(moh);
        if (chan) {
-               if (ast_set_write_format(chan, oldwfmt) ||
-                   ast_set_read_format(chan, oldrfmt)) 
-                       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %d/%d\n", chan->name, oldwfmt, oldrfmt);
+               if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
+                       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
        }
@@ -364,7 +402,7 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
 {
        struct mohdata *res;
        struct mohclass *class;
-       ast_pthread_mutex_lock(&moh_lock);
+       ast_mutex_lock(&moh_lock);
        class = get_mohbyname(params);
        if (class)
                res = mohalloc(class);
@@ -373,21 +411,18 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
                        ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
                res = NULL;
        }
-       ast_pthread_mutex_unlock(&moh_lock);
+       ast_mutex_unlock(&moh_lock);
        if (res) {
-               res->origrfmt = chan->readformat;
                res->origwfmt = chan->writeformat;
                if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
                        ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
                        moh_release(NULL, res);
                        res = NULL;
-               } else if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
-                       ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
-                       moh_release(NULL, res);
-                       res = NULL;
                }
+#if 0
                /* Allow writes to interrupt */
                chan->writeinterrupt = 1;
+#endif         
                if (option_verbose > 2)
                        ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
        }
@@ -398,11 +433,13 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
 {
        struct ast_frame f;
        struct mohdata *moh = data;
-       short buf[640 + AST_FRIENDLY_OFFSET / 2];
+       short buf[1280 + AST_FRIENDLY_OFFSET / 2];
        int res;
-       if (len > sizeof(buf)) {
+
+       len = samples * 2;
+       if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
                ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", sizeof(buf), len, chan->name);
-               len = sizeof(buf);
+               len = sizeof(buf) - AST_FRIENDLY_OFFSET;
        }
        res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
 #if 0
@@ -437,10 +474,12 @@ static struct ast_generator mohgen =
 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
 {
        struct mohclass *moh;
+#ifdef ZAPATA_MOH
        int x;
-       ast_pthread_mutex_lock(&moh_lock);
+#endif
+       ast_mutex_lock(&moh_lock);
        moh = get_mohbyname(classname);
-       ast_pthread_mutex_unlock(&moh_lock);
+       ast_mutex_unlock(&moh_lock);
        if (moh) {
                ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
                return -1;
@@ -456,7 +495,7 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
        if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "httpmp3")) {
                if (!strcasecmp(mode, "quietmp3"))
                        moh->quiet = 1;
-               strncpy(moh->dir, param, sizeof(moh->dir));
+               strncpy(moh->dir, param, sizeof(moh->dir) - 1);
                moh->srcfd = -1;
 #ifdef ZAPATA_MOH
                /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
@@ -483,10 +522,10 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
                free(moh);
                return -1;
        }
-       ast_pthread_mutex_lock(&moh_lock);
+       ast_mutex_lock(&moh_lock);
        moh->next = mohclasses;
        mohclasses = moh;
-       ast_pthread_mutex_unlock(&moh_lock);
+       ast_mutex_unlock(&moh_lock);
        return 0;
 }
 
@@ -531,19 +570,30 @@ static void load_moh_classes(void)
        }
 }
 
-void ast_moh_destroy(void)
+static void ast_moh_destroy(void)
 {
        struct mohclass *moh;
-       ast_pthread_mutex_lock(&moh_lock);
+       char buff[8192];
+       int bytes, tbytes=0, stime = 0;
+       if (option_verbose > 1)
+               ast_verbose(VERBOSE_PREFIX_2 "Destroying any remaining musiconhold processes\n");
+       ast_mutex_lock(&moh_lock);
        moh = mohclasses;
        while(moh) {
                if (moh->pid) {
-                       kill(moh->pid, SIGKILL);
+                       ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
+                       stime = time(NULL);
+                       kill(moh->pid, SIGABRT);
+                       while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
+                               tbytes = tbytes + bytes;
+                       }
+                       ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", moh->pid, tbytes);
+                       close(moh->srcfd);
                        moh->pid = 0;
                        }
                moh = moh->next;
        }
-       ast_pthread_mutex_unlock(&moh_lock);
+       ast_mutex_unlock(&moh_lock);
 }
 
 int load_module(void)
@@ -551,7 +601,7 @@ int load_module(void)
        int res;
        load_moh_classes();
        res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
-       atexit(ast_moh_destroy);
+       ast_register_atexit(ast_moh_destroy);
        if (!res)
                res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
        if (!res)