Merge "res_musiconhold: Use a vector instead of custom array allocation"

This commit is contained in:
Friendly Automation 2019-08-06 10:27:16 -05:00 committed by Gerrit Code Review
commit e5ee1b04c9
1 changed files with 55 additions and 87 deletions

View File

@ -171,12 +171,8 @@ struct mohclass {
char announcement[256];
char mode[80];
char digit;
/*! A dynamically sized array to hold the list of filenames in "files" mode */
char **filearray;
/*! The current size of the filearray */
int allowed_files;
/*! The current number of files loaded into the filearray */
int total_files;
/*! A vector of filenames in "files" mode */
struct ast_vector_string files;
unsigned int flags;
/*! The format from the MOH source, not applicable to "files" mode */
struct ast_format *format;
@ -318,6 +314,7 @@ static int ast_moh_files_next(struct ast_channel *chan)
{
struct moh_files_state *state = ast_channel_music_state(chan);
int tries;
size_t file_count;
/* Discontinue a stream if it is running already */
if (ast_channel_stream(chan)) {
@ -335,7 +332,8 @@ static int ast_moh_files_next(struct ast_channel *chan)
state->announcement = 0;
}
if (!state->class->total_files) {
file_count = AST_VECTOR_SIZE(&state->class->files);
if (!file_count) {
ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
return -1;
}
@ -343,15 +341,15 @@ static int ast_moh_files_next(struct ast_channel *chan)
if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) {
/* First time so lets play the file. */
state->save_pos = -1;
} else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && !strcmp(state->class->filearray[state->save_pos], state->save_pos_filename)) {
} else if (state->save_pos >= 0 && state->save_pos < file_count && !strcmp(AST_VECTOR_GET(&state->class->files, state->save_pos), state->save_pos_filename)) {
/* If a specific file has been saved confirm it still exists and that it is still valid */
state->pos = state->save_pos;
state->save_pos = -1;
} else if (ast_test_flag(state->class, MOH_SORTMODE) == MOH_RANDOMIZE) {
/* Get a random file and ensure we can open it */
for (tries = 0; tries < 20; tries++) {
state->pos = ast_random() % state->class->total_files;
if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) {
state->pos = ast_random() % file_count;
if (ast_fileexists(AST_VECTOR_GET(&state->class->files, state->pos), NULL, NULL) > 0) {
break;
}
}
@ -360,29 +358,29 @@ static int ast_moh_files_next(struct ast_channel *chan)
} else {
/* This is easy, just increment our position and make sure we don't exceed the total file count */
state->pos++;
state->pos %= state->class->total_files;
state->pos %= file_count;
state->save_pos = -1;
state->samples = 0;
}
for (tries = 0; tries < state->class->total_files; ++tries) {
if (ast_openstream_full(chan, state->class->filearray[state->pos], ast_channel_language(chan), 1)) {
for (tries = 0; tries < file_count; ++tries) {
if (ast_openstream_full(chan, AST_VECTOR_GET(&state->class->files, state->pos), ast_channel_language(chan), 1)) {
break;
}
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", AST_VECTOR_GET(&state->class->files, state->pos), strerror(errno));
state->pos++;
state->pos %= state->class->total_files;
state->pos %= file_count;
}
if (tries == state->class->total_files) {
if (tries == file_count) {
return -1;
}
/* Record the pointer to the filename for position resuming later */
ast_copy_string(state->save_pos_filename, state->class->filearray[state->pos], sizeof(state->save_pos_filename));
ast_copy_string(state->save_pos_filename, AST_VECTOR_GET(&state->class->files, state->pos), sizeof(state->save_pos_filename));
ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->class->filearray[state->pos]);
ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->save_pos_filename);
if (state->samples) {
size_t loc;
@ -490,6 +488,7 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
{
struct moh_files_state *state;
struct mohclass *class = params;
size_t file_count;
state = ast_channel_music_state(chan);
if (!state && (state = ast_calloc(1, sizeof(*state)))) {
@ -505,14 +504,16 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
}
}
file_count = AST_VECTOR_SIZE(&class->files);
/* Resume MOH from where we left off last time or start from scratch? */
if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) {
if (state->save_total != file_count || strcmp(state->name, class->name) != 0) {
/* Start MOH from scratch. */
ao2_cleanup(state->origwfmt);
ao2_cleanup(state->mohwfmt);
memset(state, 0, sizeof(*state));
if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
state->pos = ast_random() % class->total_files;
if (ast_test_flag(class, MOH_RANDOMIZE) && file_count) {
state->pos = ast_random() % file_count;
}
}
@ -522,7 +523,7 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
ao2_replace(state->mohwfmt, ast_channel_writeformat(chan));
/* For comparison on restart of MOH (see above) */
ast_copy_string(state->name, class->name, sizeof(state->name));
state->save_total = class->total_files;
state->save_total = file_count;
moh_post_start(chan, class->name);
@ -1131,45 +1132,6 @@ static void moh_parse_options(struct ast_variable *var, struct mohclass *mohclas
}
}
static int moh_add_file(struct mohclass *class, const char *filepath)
{
if (!class->allowed_files) {
class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray));
if (!class->filearray) {
return -1;
}
class->allowed_files = INITIAL_NUM_FILES;
} else if (class->total_files == class->allowed_files) {
char **new_array;
new_array = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2);
if (!new_array) {
return -1;
}
class->filearray = new_array;
class->allowed_files *= 2;
}
class->filearray[class->total_files] = ast_strdup(filepath);
if (!class->filearray[class->total_files]) {
return -1;
}
class->total_files++;
return 0;
}
static int moh_sort_compare(const void *i1, const void *i2)
{
char *s1, *s2;
s1 = ((char **)i1)[0];
s2 = ((char **)i2)[0];
return strcasecmp(s1, s2);
}
static int moh_scan_files(struct mohclass *class) {
DIR *files_DIR;
@ -1178,7 +1140,7 @@ static int moh_scan_files(struct mohclass *class) {
char filepath[PATH_MAX];
char *ext;
struct stat statbuf;
int i;
int res;
if (class->dir[0] != '/') {
snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir);
@ -1192,12 +1154,11 @@ static int moh_scan_files(struct mohclass *class) {
return -1;
}
for (i = 0; i < class->total_files; i++) {
ast_free(class->filearray[i]);
}
class->total_files = 0;
AST_VECTOR_RESET(&class->files, ast_free);
while ((files_dirent = readdir(files_DIR))) {
char *filepath_copy;
/* The file name must be at least long enough to have the file type extension */
if ((strlen(files_dirent->d_name) < 4))
continue;
@ -1222,20 +1183,32 @@ static int moh_scan_files(struct mohclass *class) {
*ext = '\0';
/* if the file is present in multiple formats, ensure we only put it into the list once */
for (i = 0; i < class->total_files; i++)
if (!strcmp(filepath, class->filearray[i]))
break;
if (AST_VECTOR_GET_CMP(&class->files, &filepath[0], !strcmp)) {
continue;
}
if (i == class->total_files) {
if (moh_add_file(class, filepath))
break;
filepath_copy = ast_strdup(filepath);
if (!filepath_copy) {
break;
}
if (ast_test_flag(class, MOH_SORTALPHA)) {
res = AST_VECTOR_ADD_SORTED(&class->files, filepath_copy, strcasecmp);
} else {
res = AST_VECTOR_APPEND(&class->files, filepath_copy);
}
if (res) {
ast_free(filepath_copy);
break;
}
}
closedir(files_DIR);
if (ast_test_flag(class, MOH_SORTALPHA))
qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
return class->total_files;
AST_VECTOR_COMPACT(&class->files);
return AST_VECTOR_SIZE(&class->files);
}
static int init_files_class(struct mohclass *class)
@ -1420,6 +1393,7 @@ static struct mohclass *_moh_class_malloc(const char *file, int line, const char
class->format = ao2_bump(ast_format_slin);
class->srcfd = -1;
class->kill_delay = 100000;
AST_VECTOR_INIT(&class->files, 0);
}
return class;
@ -1614,7 +1588,7 @@ static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, con
}
if (!state || !state->class || strcmp(mohclass->name, state->class->name)) {
if (mohclass->total_files) {
if (AST_VECTOR_SIZE(&mohclass->files)) {
res = ast_activate_generator(chan, &moh_file_stream, mohclass);
} else {
res = ast_activate_generator(chan, &mohgen, mohclass);
@ -1693,14 +1667,8 @@ static void moh_class_destructor(void *obj)
class->srcfd = -1;
}
if (class->filearray) {
int i;
for (i = 0; i < class->total_files; i++) {
ast_free(class->filearray[i]);
}
ast_free(class->filearray);
class->filearray = NULL;
}
AST_VECTOR_RESET(&class->files, ast_free);
AST_VECTOR_FREE(&class->files);
if (class->timer) {
ast_timer_close(class->timer);
@ -1885,13 +1853,13 @@ static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct
for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
int x;
if (!class->total_files) {
if (!AST_VECTOR_SIZE(&class->files)) {
continue;
}
ast_cli(a->fd, "Class: %s\n", class->name);
for (x = 0; x < class->total_files; x++) {
ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
for (x = 0; x < AST_VECTOR_SIZE(&class->files); x++) {
ast_cli(a->fd, "\tFile: %s\n", AST_VECTOR_GET(&class->files, x));
}
}
ao2_iterator_destroy(&i);