Asterisk - The Open Source Telephony Project  18.5.0
media_index.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Kinsey Moore <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  * \brief Sound file format and description indexer.
21  */
22 
23 #include "asterisk.h"
24 
25 #include <dirent.h>
26 #include <sys/stat.h>
27 
28 #include "asterisk/utils.h"
29 #include "asterisk/lock.h"
30 #include "asterisk/format.h"
31 #include "asterisk/format_cap.h"
32 #include "asterisk/media_index.h"
33 #include "asterisk/file.h"
34 
35 /*** MODULEINFO
36  <support_level>core</support_level>
37  ***/
38 
39 /*! \brief The number of buckets to be used for storing variant-keyed objects */
40 #define VARIANT_BUCKETS 7
41 
42 /*! \brief The number of buckets to be used for storing media filename-keyed objects */
43 #define INDEX_BUCKETS 157
44 
45 /*! \brief Structure to hold a list of the format variations for a media file for a specific variant */
46 struct media_variant {
48  AST_STRING_FIELD(description); /*!< The description of the media */
49  );
50  struct ast_format_cap *formats; /*!< The formats this media is available in for this variant */
51  char variant[0]; /*!< The variant this media is available in */
52 };
53 
54 static void media_variant_destroy(void *obj)
55 {
56  struct media_variant *variant = obj;
57 
59  ao2_cleanup(variant->formats);
60 }
61 
62 static struct media_variant *media_variant_alloc(const char *variant_str)
63 {
64  size_t str_sz = strlen(variant_str) + 1;
65  struct media_variant *variant;
66 
67  variant = ao2_alloc_options(sizeof(*variant) + str_sz, media_variant_destroy,
69  if (!variant) {
70  return NULL;
71  }
72 
73  memcpy(variant->variant, variant_str, str_sz);
74 
76  if (!variant->formats || ast_string_field_init(variant, 8)) {
77  ao2_ref(variant, -1);
78 
79  return NULL;
80  }
81 
82  return variant;
83 }
84 
85 static int media_variant_hash(const void *obj, const int flags)
86 {
87  const char *variant = (flags & OBJ_KEY) ? obj : ((struct media_variant*) obj)->variant;
88  return ast_str_case_hash(variant);
89 }
90 
91 static int media_variant_cmp(void *obj, void *arg, int flags)
92 {
93  struct media_variant *opt1 = obj, *opt2 = arg;
94  const char *variant = (flags & OBJ_KEY) ? arg : opt2->variant;
95  return strcasecmp(opt1->variant, variant) ? 0 : CMP_MATCH | CMP_STOP;
96 }
97 
98 /*! \brief Structure to hold information about a media file */
99 struct media_info {
100  struct ao2_container *variants; /*!< The variants for which this media is available */
101  char name[0]; /*!< The file name of the media */
102 };
103 
104 static void media_info_destroy(void *obj)
105 {
106  struct media_info *info = obj;
107 
108  ao2_cleanup(info->variants);
109 }
110 
111 static struct media_info *media_info_alloc(const char *name)
112 {
113  size_t name_sz = strlen(name) + 1;
114  struct media_info *info;
115 
116  info = ao2_alloc_options(sizeof(*info) + name_sz, media_info_destroy,
118  if (!info) {
119  return NULL;
120  }
121 
122  memcpy(info->name, name, name_sz);
123 
126  if (!info->variants) {
127  ao2_ref(info, -1);
128 
129  return NULL;
130  }
131 
132  return info;
133 }
134 
135 static int media_info_hash(const void *obj, const int flags)
136 {
137  const char *name = (flags & OBJ_KEY) ? obj : ((struct media_info*) obj)->name;
138  return ast_str_case_hash(name);
139 }
140 
141 static int media_info_cmp(void *obj, void *arg, int flags)
142 {
143  struct media_info *opt1 = obj, *opt2 = arg;
144  const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
145  return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
146 }
147 
149  struct ao2_container *index; /*!< The index of media that has requested */
150  struct ao2_container *media_list_cache; /*!< Cache of filenames to prevent them from being regenerated so often */
151  char base_dir[0]; /*!< Base directory for indexing */
152 };
153 
154 static void media_index_dtor(void *obj)
155 {
156  struct ast_media_index *index = obj;
157 
158  ao2_cleanup(index->index);
160 }
161 
163 {
164  size_t base_dir_sz = strlen(base_dir) + 1;
165  struct ast_media_index *index = ao2_alloc(sizeof(*index) + base_dir_sz, media_index_dtor);
166 
167  if (!index) {
168  return NULL;
169  }
170 
171  memcpy(index->base_dir, base_dir, base_dir_sz);
172 
175  if (!index->index) {
176  ao2_ref(index, -1);
177 
178  return NULL;
179  }
180 
181  return index;
182 }
183 
184 static struct media_variant *find_variant(struct ast_media_index *index, const char *filename, const char *variant)
185 {
186  RAII_VAR(struct media_info *, info, NULL, ao2_cleanup);
187 
188  info = ao2_find(index->index, filename, OBJ_KEY);
189  if (!info) {
190  return NULL;
191  }
192 
193  return ao2_find(info->variants, variant, OBJ_KEY);
194 }
195 
196 /*! \brief create the appropriate media_variant and any necessary structures */
197 static struct media_variant *alloc_variant(struct ast_media_index *index, const char *filename, const char *variant_str)
198 {
199  struct media_info *info;
200  struct media_variant *variant = NULL;
201 
202  info = ao2_find(index->index, filename, OBJ_KEY);
203  if (!info) {
204  /* This is the first time the index has seen this filename,
205  * allocate and link */
206  info = media_info_alloc(filename);
207  if (!info) {
208  return NULL;
209  }
210 
211  ao2_link(index->index, info);
212  } else {
213  variant = ao2_find(info->variants, variant_str, OBJ_KEY);
214  }
215 
216  if (!variant) {
217  /* This is the first time the index has seen this variant for
218  * this filename, allocate and link */
219  variant = media_variant_alloc(variant_str);
220  if (variant) {
221  ao2_link(info->variants, variant);
222  }
223  }
224 
225  ao2_ref(info, -1);
226 
227  return variant;
228 }
229 
230 const char *ast_media_get_description(struct ast_media_index *index, const char *filename, const char *variant_str)
231 {
233  if (ast_strlen_zero(filename) || ast_strlen_zero(variant_str)) {
234  return NULL;
235  }
236 
237  variant = find_variant(index, filename, variant_str);
238  if (!variant) {
239  return NULL;
240  }
241 
242  return variant->description;
243 }
244 
245 struct ast_format_cap *ast_media_get_format_cap(struct ast_media_index *index, const char *filename, const char *variant_str)
246 {
247  struct ast_format_cap *dupcap;
249  if (ast_strlen_zero(filename) || ast_strlen_zero(variant_str)) {
250  return NULL;
251  }
252 
253  variant = find_variant(index, filename, variant_str);
254  if (!variant) {
255  return NULL;
256  }
257 
259  if (dupcap) {
261  }
262  return dupcap;
263 }
264 
265 /*! \brief Add the variant to the list of variants requested */
266 static int add_variant_cb(void *obj, void *arg, int flags)
267 {
268  struct media_variant *variant = obj;
269  struct ao2_container *variants= arg;
270  ast_str_container_add(variants, variant->variant);
271  return 0;
272 }
273 
274 struct ao2_container *ast_media_get_variants(struct ast_media_index *index, const char *filename)
275 {
276  RAII_VAR(struct media_info *, info, NULL, ao2_cleanup);
277  RAII_VAR(struct ao2_container *, variants, NULL, ao2_cleanup);
278  if (!filename) {
279  return NULL;
280  }
281 
283  if (!variants) {
284  return NULL;
285  }
286 
287  info = ao2_find(index->index, filename, OBJ_KEY);
288  if (!info) {
289  return NULL;
290  }
291 
292  ao2_callback(info->variants, OBJ_NODATA, add_variant_cb, variants);
293 
294  ao2_ref(variants, +1);
295  return variants;
296 }
297 
298 /*! \brief Add the media_info's filename to the container of filenames requested */
299 static int add_media_cb(void *obj, void *arg, int flags)
300 {
301  struct media_info *info = obj;
302  struct ao2_container *media = arg;
303  ast_str_container_add(media, info->name);
304  return 0;
305 }
306 
308 {
309  RAII_VAR(struct ao2_container *, media, NULL, ao2_cleanup);
310 
311  if (!index->media_list_cache) {
313  if (!media) {
314  return NULL;
315  }
316 
317  ao2_callback(index->index, OBJ_NODATA, add_media_cb, media);
318 
319  /* Ref to the cache */
320  ao2_ref(media, +1);
321  index->media_list_cache = media;
322  }
323 
324  /* Ref to the caller */
325  ao2_ref(index->media_list_cache, +1);
326  return index->media_list_cache;
327 }
328 
329 /*! \brief Update an index with new format/variant information */
330 static int update_file_format_info(struct ast_media_index *index, const char *filename, const char *variant_str, struct ast_format *file_format)
331 {
332  struct media_variant *variant;
333 
334  variant = alloc_variant(index, filename, variant_str);
335  if (!variant) {
336  return -1;
337  }
338 
339  ast_format_cap_append(variant->formats, file_format, 0);
340  ao2_ref(variant, -1);
341 
342  return 0;
343 }
344 
345 /*! \brief Process a media file into the index */
346 static int process_media_file(struct ast_media_index *index, const char *variant, const char *subdir, const char *filename_stripped, const char *ext)
347 {
348  struct ast_format *file_format;
349  const char *file_identifier = filename_stripped;
350  char *file_id_str = NULL;
351  int res;
352 
353  file_format = ast_get_format_for_file_ext(ext);
354  if (!file_format) {
355  /* extension not registered */
356  return 0;
357  }
358 
359  /* handle updating the file information */
360  if (subdir) {
361  if (ast_asprintf(&file_id_str, "%s/%s", subdir, filename_stripped) == -1) {
362  return -1;
363  }
364 
365  file_identifier = file_id_str;
366  }
367 
368  res = update_file_format_info(index, file_identifier, variant, file_format);
369  ast_free(file_id_str);
370 
371  return res;
372 }
373 
374 /*!
375  * \brief Process a media description text file
376  *
377  * This currently processes core-sounds-*.txt and extra-sounds-*.txt, but will
378  * process others if present.
379  */
380 static int process_description_file(struct ast_media_index *index,
381  const char *subdir,
382  const char *variant_str,
383  const char *filename,
384  const char *match_filename)
385 {
386  RAII_VAR(struct ast_str *, description_file_path, ast_str_create(64), ast_free);
387  RAII_VAR(struct ast_str *, cumulative_description, ast_str_create(64), ast_free);
388  char *file_id_persist = NULL;
389  int res = 0;
390  FILE *f = NULL;
391 #if defined(LOW_MEMORY)
392  char buf[256];
393 #else
394  char buf[2048];
395 #endif
396 
397  if (!description_file_path || !cumulative_description) {
398  return -1;
399  }
400 
401  if (ast_strlen_zero(subdir)) {
402  ast_str_set(&description_file_path, 0, "%s/%s/%s", index->base_dir, variant_str, filename);
403  } else {
404  ast_str_set(&description_file_path, 0, "%s/%s/%s/%s", index->base_dir, variant_str, subdir, filename);
405  }
406  f = fopen(ast_str_buffer(description_file_path), "r");
407  if (!f) {
408  ast_log(LOG_WARNING, "Could not open media description file '%s': %s\n", ast_str_buffer(description_file_path), strerror(errno));
409  return -1;
410  }
411 
412  while (!feof(f)) {
413  char *file_identifier, *description;
414  if (!fgets(buf, sizeof(buf), f)) {
415  if (ferror(f)) {
416  ast_log(LOG_ERROR, "Error reading from file %s: %s\n", ast_str_buffer(description_file_path), strerror(errno));
417  }
418  continue;
419  }
420 
421  /* Skip lines that are too long */
422  if (strlen(buf) == sizeof(buf) - 1 && buf[sizeof(buf) - 1] != '\n') {
423  ast_log(LOG_WARNING, "Line too long, skipping. It begins with: %.32s...\n", buf);
424  while (fgets(buf, sizeof(buf), f)) {
425  if (strlen(buf) != sizeof(buf) - 1 || buf[sizeof(buf) - 1] == '\n') {
426  break;
427  }
428  }
429  if (ferror(f)) {
430  ast_log(LOG_ERROR, "Error reading from file %s: %s\n", ast_str_buffer(description_file_path), strerror(errno));
431  }
432  continue;
433  }
434 
435  if (buf[0] == ';') {
436  /* ignore comments */
437  continue;
438  }
439 
440  ast_trim_blanks(buf);
441  description = buf;
442  file_identifier = strsep(&description, ":");
443  if (!description) {
444  /* no ':' means this is a continuation */
445  if (file_id_persist) {
446  ast_str_append(&cumulative_description, 0, "\n%s", file_identifier);
447  }
448  continue;
449  } else {
450  /* if there's text in cumulative_description, archive it and start anew */
451  if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
452  struct media_variant *variant;
453 
454  /*
455  * If we were only searching for a specific sound filename
456  * don't include others.
457  */
458  if (ast_strlen_zero(match_filename) || strcmp(match_filename, file_id_persist) == 0) {
459  variant = alloc_variant(index, file_id_persist, variant_str);
460  if (!variant) {
461  res = -1;
462  break;
463  }
464  ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
465  ao2_ref(variant, -1);
466  }
467 
468  ast_str_reset(cumulative_description);
469  }
470 
471  ast_free(file_id_persist);
472  file_id_persist = ast_strdup(file_identifier);
473  description = ast_skip_blanks(description);
474  ast_str_set(&cumulative_description, 0, "%s", description);
475  }
476  }
477 
478  /* handle the last one */
479  if (file_id_persist && !ast_strlen_zero(ast_str_buffer(cumulative_description))) {
480  struct media_variant *variant;
481 
482  /*
483  * If we were only searching for a specific sound filename
484  * don't include others.
485  */
486  if (ast_strlen_zero(match_filename) || strcmp(match_filename, file_id_persist) == 0) {
487  variant = alloc_variant(index, file_id_persist, variant_str);
488  if (variant) {
489  ast_string_field_set(variant, description, ast_str_buffer(cumulative_description));
490  ao2_ref(variant, -1);
491  } else {
492  res = -1;
493  }
494  }
495  }
496 
497  ast_free(file_id_persist);
498  fclose(f);
499  return res;
500 }
501 
503  const char *search_filename;
505  const char *search_variant;
507  size_t dirname_len;
508 };
509 
510 static int read_dirs_cb(const char *dir_name, const char *filename, void *obj)
511 {
512  struct read_dirs_data *data = obj;
513  char *ext;
514  size_t match_len;
515  char *match;
516  size_t match_base_len;
517  char *subdirs = (char *)dir_name + data->dirname_len;
518 
519  /*
520  * Example:
521  * From the filesystem:
522  * index's base_dir = "/var/lib/asterisk/sounds"
523  * search_variant = "en"
524  * search directory base = "/var/lib/asterisk/sounds/en"
525  * dirname_len = 27
526  * current dir_name = "/var/lib/asterisk/sounds/en/digits"
527  * subdirs = "/digits"
528  * filename = "1.ulaw"
529  *
530  * From the search criteria:
531  * search_filename = "digits/1"
532  * search_filename_len = 8
533  */
534 
535  if (*subdirs == '/') {
536  subdirs++;
537  }
538 
539  /* subdirs = "digits" */
540 
541  match_len = strlen(subdirs) + strlen(filename) + 2;
542  match = ast_alloca(match_len);
543  snprintf(match, match_len, "%s%s%s", subdirs,
544  ast_strlen_zero(subdirs) ? "" : "/", filename);
545 
546  /* match = discovered filename relative to language = "digits/1.ulaw" */
547 
548  ext = strrchr(match, '.');
549  if (!ext) {
550  return 0;
551  }
552 
553  /* ext = ".ulaw" */
554 
555  if (data->search_filename_len > 0) {
556  match_base_len = ext - match;
557  /*
558  * match_base_len = length of "digits/1" = 8 which
559  * happens to match the length of search_filename.
560  * However if the discovered filename was 11.ulaw
561  * it would be length of "digits/11" = 9.
562  * We need to use the larger during the compare to
563  * make sure we don't match just search_filename
564  * as a substring of the discovered filename.
565  */
566  if (data->search_filename_len > match_base_len) {
567  match_base_len = data->search_filename_len;
568  }
569  }
570 
571  /* We always process txt files because they should contain description. */
572  if (strcmp(ext, ".txt") == 0) {
574  match, data->search_filename)) {
575  return -1;
576  }
577  } else if (data->search_filename_len == 0
578  || strncmp(data->search_filename, match, match_base_len ) == 0) {
579  *ext = '\0';
580  ext++;
581  process_media_file(data->index, data->search_variant, NULL, match, ext);
582  }
583 
584  return 0;
585 }
586 
588  const char *variant, const char *filename)
589 {
590  struct timeval start;
591  struct timeval end;
592  int64_t elapsed;
593  int rc;
594  size_t dirname_len = strlen(index->base_dir) + strlen(S_OR(variant, "")) + 1;
595  struct read_dirs_data data = {
596  .search_filename = S_OR(filename, ""),
597  .search_filename_len = strlen(S_OR(filename, "")),
598  .search_variant = S_OR(variant, ""),
599  .index = index,
600  .dirname_len = dirname_len,
601  };
602  char *search_dir = ast_alloca(dirname_len + 1);
603 
604  sprintf(search_dir, "%s%s%s", index->base_dir, ast_strlen_zero(variant) ? "" : "/",
605  data.search_variant);
606 
607  gettimeofday(&start, NULL);
608  rc = ast_file_read_dirs(search_dir, read_dirs_cb, &data, -1);
609  gettimeofday(&end, NULL);
610  elapsed = ast_tvdiff_us(end, start);
611  ast_debug(1, "Media for language '%s' indexed in %8.6f seconds\n", data.search_variant, elapsed / 1E6);
612 
613  return rc;
614 }
static int media_info_cmp(void *obj, void *arg, int flags)
Definition: media_index.c:141
static struct media_variant * find_variant(struct ast_media_index *index, const char *filename, const char *variant)
Definition: media_index.c:184
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static int read_dirs_cb(const char *dir_name, const char *filename, void *obj)
Definition: media_index.c:510
#define OBJ_KEY
Definition: astobj2.h:1155
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int media_variant_cmp(void *obj, void *arg, int flags)
Definition: media_index.c:91
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
struct ao2_container * variants
Definition: media_index.c:100
#define ast_str_container_alloc(buckets)
Allocates a hash container for bare strings.
Definition: strings.h:1312
static void media_variant_destroy(void *obj)
Definition: media_index.c:54
if(!yyg->yy_init)
Definition: ast_expr2f.c:868
struct ao2_container * ast_media_get_variants(struct ast_media_index *index, const char *filename)
Get the languages in which a media file is available.
Definition: media_index.c:274
Definition of a media format.
Definition: format.c:43
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
#define INDEX_BUCKETS
The number of buckets to be used for storing media filename-keyed objects.
Definition: media_index.c:43
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:337
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
const char * search_filename
Definition: media_index.c:503
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2315
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define NULL
Definition: resample.c:96
const char * ext
Definition: http.c:147
int ast_media_index_update_for_file(struct ast_media_index *index, const char *variant, const char *filename)
Update a media index for a specific sound file.
Definition: media_index.c:587
int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
Recursively iterate through files and directories up to max_depth.
Definition: file.c:1231
struct ao2_container * media_list_cache
Definition: media_index.c:150
Structure to hold a list of the format variations for a media file for a specific variant...
Definition: media_index.c:46
Utility functions.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
Media Format API.
#define ast_strlen_zero(foo)
Definition: strings.h:52
const char * ast_media_get_description(struct ast_media_index *index, const char *filename, const char *variant_str)
Get the description for a media file.
Definition: media_index.c:230
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
size_t search_filename_len
Definition: media_index.c:504
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:299
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
static struct media_info * media_info_alloc(const char *name)
Definition: media_index.c:111
char name[0]
Definition: media_index.c:101
Format Capabilities API.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
Structure to hold information about a media file.
Definition: media_index.c:99
static int process_media_file(struct ast_media_index *index, const char *variant, const char *subdir, const char *filename_stripped, const char *ext)
Process a media file into the index.
Definition: media_index.c:346
#define LOG_ERROR
Definition: logger.h:285
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Definition: astobj2.h:1310
file_format
Definition: func_env.c:318
static int media_variant_hash(const void *obj, const int flags)
Definition: media_index.c:85
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
struct ast_format_cap * formats
Definition: media_index.c:50
def info(msg)
int errno
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
const ast_string_field description
Definition: media_index.c:49
size_t dirname_len
Definition: media_index.c:507
char * ast_trim_blanks(char *str)
Trims trailing whitespace characters from a string.
Definition: strings.h:182
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
struct ast_format_cap * ast_media_get_format_cap(struct ast_media_index *index, const char *filename, const char *variant_str)
Get the ast_format_cap for a media file.
Definition: media_index.c:245
static struct media_variant * alloc_variant(struct ast_media_index *index, const char *filename, const char *variant_str)
create the appropriate media_variant and any necessary structures
Definition: media_index.c:197
struct ao2_container * index
Definition: media_index.c:149
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
struct ast_format * ast_get_format_for_file_ext(const char *file_ext)
Get the ast_format associated with the given file extension.
Definition: file.c:1938
#define VARIANT_BUCKETS
The number of buckets to be used for storing variant-keyed objects.
Definition: media_index.c:40
const char * search_variant
Definition: media_index.c:505
static void media_info_destroy(void *obj)
Definition: media_index.c:104
static int process_description_file(struct ast_media_index *index, const char *subdir, const char *variant_str, const char *filename, const char *match_filename)
Process a media description text file.
Definition: media_index.c:380
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
char * strsep(char **str, const char *delims)
static void media_index_dtor(void *obj)
Definition: media_index.c:154
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static int add_media_cb(void *obj, void *arg, int flags)
Add the media_info&#39;s filename to the container of filenames requested.
Definition: media_index.c:299
static struct media_variant * media_variant_alloc(const char *variant_str)
Definition: media_index.c:62
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
char base_dir[0]
Definition: media_index.c:151
Media file format and description indexing engine.
struct ast_media_index * index
Definition: media_index.c:506
int64_t ast_tvdiff_us(struct timeval end, struct timeval start)
Computes the difference (in microseconds) between two struct timeval instances.
Definition: time.h:78
struct ao2_container * ast_media_get_media(struct ast_media_index *index)
Get the a container of all media available on the system.
Definition: media_index.c:307
Generic container type.
int ast_format_cap_append_from_cap(struct ast_format_cap *dst, const struct ast_format_cap *src, enum ast_media_type type)
Append the formats of provided type in src to dst.
Definition: format_cap.c:269
static int media_info_hash(const void *obj, const int flags)
Definition: media_index.c:135
struct ast_media_index * ast_media_index_create(const char *base_dir)
Creates a new media index.
Definition: media_index.c:162
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
int ast_str_container_add(struct ao2_container *str_container, const char *add)
Adds a string to a string container allocated by ast_str_container_alloc.
Definition: strings.c:206
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1250
static int update_file_format_info(struct ast_media_index *index, const char *filename, const char *variant_str, struct ast_format *file_format)
Update an index with new format/variant information.
Definition: media_index.c:330
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
char variant[0]
Definition: media_index.c:51
static int add_variant_cb(void *obj, void *arg, int flags)
Add the variant to the list of variants requested.
Definition: media_index.c:266
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
#define ao2_link(container, obj)
Definition: astobj2.h:1549