- convert lists to use linked list macros

- instead of allocating a frame on the stack every time the music on hold
  generator is called, put a frame in the mohdata structure.  Also, initialize
  the parts of the frame that will never change when the mohdata struct is
  allocatted and only change the necessary parts in the generator function.


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@23334 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Russell Bryant 20 years ago
parent 379e426b25
commit 00f9884604

@ -70,6 +70,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/utils.h" #include "asterisk/utils.h"
#include "asterisk/cli.h" #include "asterisk/cli.h"
#include "asterisk/stringfields.h" #include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#define MAX_MOHFILES 512 #define MAX_MOHFILES 512
#define MAX_MOHFILE_LEN 128 #define MAX_MOHFILE_LEN 128
@ -139,24 +140,23 @@ struct mohclass {
int pid; /* PID of mpg123 */ int pid; /* PID of mpg123 */
time_t start; time_t start;
pthread_t thread; pthread_t thread;
struct mohdata *members;
/* Source of audio */ /* Source of audio */
int srcfd; int srcfd;
/* FD for timing source */ /* FD for timing source */
int pseudofd; int pseudofd;
struct mohclass *next; AST_LIST_HEAD_NOLOCK(, mohdata) members;
AST_LIST_ENTRY(mohclass) list;
}; };
struct mohdata { struct mohdata {
int pipe[2]; int pipe[2];
int origwfmt; int origwfmt;
struct mohclass *parent; struct mohclass *parent;
struct mohdata *next; struct ast_frame f;
AST_LIST_ENTRY(mohdata) list;
}; };
static struct mohclass *mohclasses; AST_LIST_HEAD_STATIC(mohclasses, mohclass);
AST_MUTEX_DEFINE_STATIC(moh_lock);
#define LOCAL_MPG_123 "/usr/local/bin/mpg123" #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
#define MPG_123 "/usr/bin/mpg123" #define MPG_123 "/usr/bin/mpg123"
@ -165,18 +165,16 @@ AST_MUTEX_DEFINE_STATIC(moh_lock);
static void ast_moh_free_class(struct mohclass **class) static void ast_moh_free_class(struct mohclass **class)
{ {
struct mohdata *members, *mtmp; struct mohdata *member;
while ((member = AST_LIST_REMOVE_HEAD(&((*class)->members), list)))
free(member);
members = (*class)->members;
while(members) {
mtmp = members;
members = members->next;
free(mtmp);
}
if ((*class)->thread) { if ((*class)->thread) {
pthread_cancel((*class)->thread); pthread_cancel((*class)->thread);
(*class)->thread = 0; (*class)->thread = 0;
} }
free(*class); free(*class);
*class = NULL; *class = NULL;
} }
@ -515,7 +513,7 @@ static void *monmp3thread(void *data)
} }
res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
} }
if (!class->members) if (AST_LIST_EMPTY(&class->members))
continue; continue;
/* Read mp3 audio */ /* Read mp3 audio */
len = ast_codec_get_len(class->format, res); len = ast_codec_get_len(class->format, res);
@ -538,16 +536,15 @@ static void *monmp3thread(void *data)
continue; continue;
} }
pthread_testcancel(); pthread_testcancel();
ast_mutex_lock(&moh_lock); AST_LIST_LOCK(&mohclasses);
moh = class->members; AST_LIST_TRAVERSE(&class->members, moh, list) {
while (moh) {
/* Write data */ /* Write data */
if ((res = write(moh->pipe[1], sbuf, res2)) != res2) if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
if (option_debug) if (option_debug)
ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2); ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
moh = moh->next; }
} }
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
} }
return NULL; return NULL;
} }
@ -607,60 +604,58 @@ static int moh4_exec(struct ast_channel *chan, void *data)
return 0; return 0;
} }
/*! \note This function should be called with the mohclasses list locked */
static struct mohclass *get_mohbyname(const char *name) static struct mohclass *get_mohbyname(const char *name)
{ {
struct mohclass *moh; struct mohclass *moh = NULL;
moh = mohclasses;
while (moh) { AST_LIST_TRAVERSE(&mohclasses, moh, list) {
if (!strcasecmp(name, moh->name)) if (!strcasecmp(name, moh->name))
return moh; break;
moh = moh->next;
} }
return NULL;
return moh;
} }
static struct mohdata *mohalloc(struct mohclass *cl) static struct mohdata *mohalloc(struct mohclass *cl)
{ {
struct mohdata *moh; struct mohdata *moh;
long flags; long flags;
if (!(moh = ast_calloc(1, sizeof(*moh)))) if (!(moh = ast_calloc(1, sizeof(*moh))))
return NULL; return NULL;
if (pipe(moh->pipe)) { if (pipe(moh->pipe)) {
ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
free(moh); free(moh);
return NULL; return NULL;
} }
/* Make entirely non-blocking */ /* Make entirely non-blocking */
flags = fcntl(moh->pipe[0], F_GETFL); flags = fcntl(moh->pipe[0], F_GETFL);
fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
flags = fcntl(moh->pipe[1], F_GETFL); flags = fcntl(moh->pipe[1], F_GETFL);
fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
moh->f.frametype = AST_FRAME_VOICE;
moh->f.subclass = cl->format;
moh->f.offset = AST_FRIENDLY_OFFSET;
moh->parent = cl; moh->parent = cl;
moh->next = cl->members; AST_LIST_INSERT_HEAD(&cl->members, moh, list);
cl->members = moh;
return moh; return moh;
} }
static void moh_release(struct ast_channel *chan, void *data) static void moh_release(struct ast_channel *chan, void *data)
{ {
struct mohdata *moh = data, *prev, *cur; struct mohdata *moh = data;
int oldwfmt; int oldwfmt;
ast_mutex_lock(&moh_lock);
/* Unlink */ AST_LIST_LOCK(&mohclasses);
prev = NULL; AST_LIST_REMOVE(&moh->parent->members, moh, list);
cur = moh->parent->members; AST_LIST_UNLOCK(&mohclasses);
while (cur) {
if (cur == moh) {
if (prev)
prev->next = cur->next;
else
moh->parent->members = cur->next;
break;
}
prev = cur;
cur = cur->next;
}
ast_mutex_unlock(&moh_lock);
close(moh->pipe[0]); close(moh->pipe[0]);
close(moh->pipe[1]); close(moh->pipe[1]);
oldwfmt = moh->origwfmt; oldwfmt = moh->origwfmt;
@ -693,7 +688,6 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
static int moh_generate(struct ast_channel *chan, void *data, int len, int samples) static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
{ {
struct ast_frame f;
struct mohdata *moh = data; struct mohdata *moh = data;
short buf[1280 + AST_FRIENDLY_OFFSET / 2]; short buf[1280 + AST_FRIENDLY_OFFSET / 2];
int res; int res;
@ -708,25 +702,14 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
len = sizeof(buf) - AST_FRIENDLY_OFFSET; len = sizeof(buf) - AST_FRIENDLY_OFFSET;
} }
res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
#if 0
if (res != len) {
ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
}
#endif
if (res <= 0) if (res <= 0)
return 0; return 0;
memset(&f, 0, sizeof(f)); moh->f.datalen = res;
moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
f.frametype = AST_FRAME_VOICE; moh->f.samples = ast_codec_get_samples(&moh->f);
f.subclass = moh->parent->format;
f.mallocd = 0; if (ast_write(chan, &moh->f) < 0) {
f.datalen = res;
f.data = buf + AST_FRIENDLY_OFFSET / 2;
f.offset = AST_FRIENDLY_OFFSET;
f.samples = ast_codec_get_samples(&f);
if (ast_write(chan, &f) < 0) {
ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
return -1; return -1;
} }
@ -804,7 +787,7 @@ static int moh_register(struct mohclass *moh, int reload)
#ifdef HAVE_ZAPTEL #ifdef HAVE_ZAPTEL
int x; int x;
#endif #endif
ast_mutex_lock(&moh_lock); AST_LIST_LOCK(&mohclasses);
if (get_mohbyname(moh->name)) { if (get_mohbyname(moh->name)) {
if (reload) { if (reload) {
ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name); ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
@ -812,10 +795,10 @@ static int moh_register(struct mohclass *moh, int reload)
ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
} }
free(moh); free(moh);
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
return -1; return -1;
} }
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
time(&moh->start); time(&moh->start);
moh->start -= respawn_time; moh->start -= respawn_time;
@ -864,10 +847,11 @@ static int moh_register(struct mohclass *moh, int reload)
ast_moh_free_class(&moh); ast_moh_free_class(&moh);
return -1; return -1;
} }
ast_mutex_lock(&moh_lock);
moh->next = mohclasses; AST_LIST_LOCK(&mohclasses);
mohclasses = moh; AST_LIST_INSERT_HEAD(&mohclasses, moh, list);
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
return 0; return 0;
} }
@ -887,9 +871,9 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *class)
class = chan->musicclass; class = chan->musicclass;
if (ast_strlen_zero(class)) if (ast_strlen_zero(class))
class = "default"; class = "default";
ast_mutex_lock(&moh_lock); AST_LIST_LOCK(&mohclasses);
mohclass = get_mohbyname(class); mohclass = get_mohbyname(class);
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
if (!mohclass) { if (!mohclass) {
ast_log(LOG_WARNING, "No class: %s\n", (char *)class); ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
@ -1060,16 +1044,15 @@ static int load_moh_classes(int reload)
static void ast_moh_destroy(void) static void ast_moh_destroy(void)
{ {
struct mohclass *moh, *tmp; struct mohclass *moh;
char buff[8192]; char buff[8192];
int bytes, tbytes=0, stime = 0, pid = 0; int bytes, tbytes = 0, stime = 0, pid = 0;
if (option_verbose > 1) if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
ast_mutex_lock(&moh_lock);
moh = mohclasses;
while (moh) { AST_LIST_LOCK(&mohclasses);
while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
if (moh->pid) { if (moh->pid) {
ast_log(LOG_DEBUG, "killing %d!\n", moh->pid); ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
stime = time(NULL) + 2; stime = time(NULL) + 2;
@ -1083,18 +1066,14 @@ static void ast_moh_destroy(void)
kill(pid, SIGTERM); kill(pid, SIGTERM);
usleep(100000); usleep(100000);
kill(pid, SIGKILL); kill(pid, SIGKILL);
while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) { while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
tbytes = tbytes + bytes; tbytes = tbytes + bytes;
}
ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
close(moh->srcfd); close(moh->srcfd);
} }
tmp = moh; ast_moh_free_class(&moh);
moh = moh->next;
ast_moh_free_class(&tmp);
} }
mohclasses = NULL; AST_LIST_UNLOCK(&mohclasses);
ast_mutex_unlock(&moh_lock);
} }
static void moh_on_off(int on) static void moh_on_off(int on)
@ -1108,7 +1087,7 @@ static void moh_on_off(int on)
else else
ast_deactivate_generator(chan); ast_deactivate_generator(chan);
} }
ast_mutex_unlock(&chan->lock); ast_channel_unlock(chan);
} }
} }
@ -1129,8 +1108,8 @@ static int cli_files_show(int fd, int argc, char *argv[])
int i; int i;
struct mohclass *class; struct mohclass *class;
ast_mutex_lock(&moh_lock); AST_LIST_LOCK(&mohclasses);
for (class = mohclasses; class; class = class->next) { AST_LIST_TRAVERSE(&mohclasses, class, list) {
if (!class->total_files) if (!class->total_files)
continue; continue;
@ -1138,7 +1117,7 @@ static int cli_files_show(int fd, int argc, char *argv[])
for (i = 0; i < class->total_files; i++) for (i = 0; i < class->total_files; i++)
ast_cli(fd, "\tFile: %s\n", class->filearray[i]); ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
} }
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
return 0; return 0;
} }
@ -1147,8 +1126,8 @@ static int moh_classes_show(int fd, int argc, char *argv[])
{ {
struct mohclass *class; struct mohclass *class;
ast_mutex_lock(&moh_lock); AST_LIST_LOCK(&mohclasses);
for (class = mohclasses; class; class = class->next) { AST_LIST_TRAVERSE(&mohclasses, class, list) {
ast_cli(fd, "Class: %s\n", class->name); ast_cli(fd, "Class: %s\n", class->name);
ast_cli(fd, "\tMode: %s\n", S_OR(class->mode,"<none>")); ast_cli(fd, "\tMode: %s\n", S_OR(class->mode,"<none>"));
ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
@ -1156,7 +1135,7 @@ static int moh_classes_show(int fd, int argc, char *argv[])
ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
} }
ast_mutex_unlock(&moh_lock); AST_LIST_UNLOCK(&mohclasses);
return 0; return 0;
} }
@ -1173,12 +1152,14 @@ static int init_classes(int reload)
if (!load_moh_classes(reload)) /* Load classes from config */ if (!load_moh_classes(reload)) /* Load classes from config */
return 0; /* Return if nothing is found */ return 0; /* Return if nothing is found */
moh = mohclasses;
while (moh) { AST_LIST_LOCK(&mohclasses);
AST_LIST_TRAVERSE(&mohclasses, moh, list) {
if (moh->total_files) if (moh->total_files)
moh_scan_files(moh); moh_scan_files(moh);
moh = moh->next;
} }
AST_LIST_UNLOCK(&mohclasses);
return 1; return 1;
} }

Loading…
Cancel
Save