Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


file.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
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  *
21  * \brief Generic File Format Support.
22  *
23  * \author Mark Spencer <markster@digium.com>
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 421059 $")
33 
34 #include <dirent.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37 #include <math.h>
38 
39 #include "asterisk/_private.h" /* declare ast_file_init() */
40 #include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
41 #include "asterisk/mod_format.h"
42 #include "asterisk/cli.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/sched.h"
45 #include "asterisk/translate.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/app.h"
49 #include "asterisk/pbx.h"
50 #include "asterisk/linkedlists.h"
51 #include "asterisk/module.h"
52 #include "asterisk/astobj2.h"
53 #include "asterisk/test.h"
54 
55 /*
56  * The following variable controls the layout of localized sound files.
57  * If 0, use the historical layout with prefix just before the filename
58  * (i.e. digits/en/1.gsm , digits/it/1.gsm or default to digits/1.gsm),
59  * if 1 put the prefix at the beginning of the filename
60  * (i.e. en/digits/1.gsm, it/digits/1.gsm or default to digits/1.gsm).
61  * The latter permits a language to be entirely in one directory.
62  */
64 
66 
67 int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
68 {
69  struct ast_format *tmp;
70 
73  if (!strcasecmp(f->name, tmp->name)) {
75  ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
76  return -1;
77  }
78  }
79  if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
81  return -1;
82  }
83  *tmp = *f;
84  tmp->module = mod;
85  if (tmp->buf_size) {
86  /*
87  * Align buf_size properly, rounding up to the machine-specific
88  * alignment for pointers.
89  */
90  struct _test_align { void *a, *b; } p;
91  int align = (char *)&p.b - (char *)&p.a;
92  tmp->buf_size = ((f->buf_size + align - 1) / align) * align;
93  }
94 
95  memset(&tmp->list, 0, sizeof(tmp->list));
96 
97  AST_RWLIST_INSERT_HEAD(&formats, tmp, list);
99  ast_verb(2, "Registered file format %s, extension(s) %s\n", f->name, f->exts);
100 
101  return 0;
102 }
103 
104 int ast_format_unregister(const char *name)
105 {
106  struct ast_format *tmp;
107  int res = -1;
108 
111  if (!strcasecmp(name, tmp->name)) {
113  ast_free(tmp);
114  res = 0;
115  }
116  }
119 
120  if (!res)
121  ast_verb(2, "Unregistered format %s\n", name);
122  else
123  ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
124 
125  return res;
126 }
127 
128 int ast_stopstream(struct ast_channel *tmp)
129 {
130  ast_channel_lock(tmp);
131 
132  /* Stop a running stream if there is one */
133  if (tmp->stream) {
134  ast_closestream(tmp->stream);
135  tmp->stream = NULL;
136  if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
137  ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_getformatname(tmp->oldwriteformat));
138  }
139  /* Stop the video stream too */
140  if (tmp->vstream != NULL) {
141  ast_closestream(tmp->vstream);
142  tmp->vstream = NULL;
143  }
144 
145  ast_channel_unlock(tmp);
146 
147  return 0;
148 }
149 
150 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
151 {
152  int res = -1;
153  int alt = 0;
154  if (f->frametype == AST_FRAME_VIDEO) {
155  if (fs->fmt->format & AST_FORMAT_AUDIO_MASK) {
156  /* This is the audio portion. Call the video one... */
157  if (!fs->vfs && fs->filename) {
158  const char *type = ast_getformatname(f->subclass.codec & ~0x1);
159  fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
160  ast_debug(1, "Opened video output file\n");
161  }
162  if (fs->vfs)
163  return ast_writestream(fs->vfs, f);
164  /* else ignore */
165  return 0;
166  } else {
167  /* Might / might not have mark set */
168  alt = 1;
169  }
170  } else if (f->frametype != AST_FRAME_VOICE) {
171  ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
172  return -1;
173  }
174  if (((fs->fmt->format | alt) & f->subclass.codec) == f->subclass.codec) {
175  res = fs->fmt->write(fs, f);
176  if (res < 0)
177  ast_log(LOG_WARNING, "Natural write failed\n");
178  else if (res > 0)
179  ast_log(LOG_WARNING, "Huh??\n");
180  } else {
181  /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
182  the one we've setup a translator for, we do the "wrong thing" XXX */
183  if (fs->trans && f->subclass.codec != fs->lastwriteformat) {
185  fs->trans = NULL;
186  }
187  if (!fs->trans)
189  if (!fs->trans)
190  ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
192  else {
193  struct ast_frame *trf;
194  fs->lastwriteformat = f->subclass.codec;
195  /* Get the translated frame but don't consume the original in case they're using it on another stream */
196  if ((trf = ast_translate(fs->trans, f, 0))) {
197  struct ast_frame *cur;
198 
199  /* the translator may have returned multiple frames, so process them */
200  for (cur = trf; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
201  if ((res = fs->fmt->write(fs, trf))) {
202  ast_log(LOG_WARNING, "Translated frame write failed\n");
203  break;
204  }
205  }
206  ast_frfree(trf);
207  } else {
208  res = 0;
209  }
210  }
211  }
212  return res;
213 }
214 
215 static int copy(const char *infile, const char *outfile)
216 {
217  int ifd, ofd, len;
218  char buf[4096]; /* XXX make it lerger. */
219 
220  if ((ifd = open(infile, O_RDONLY)) < 0) {
221  ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
222  return -1;
223  }
224  if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
225  ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
226  close(ifd);
227  return -1;
228  }
229  while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
230  int res;
231  if (len < 0) {
232  ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
233  break;
234  }
235  /* XXX handle partial writes */
236  res = write(ofd, buf, len);
237  if (res != len) {
238  ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
239  len = -1; /* error marker */
240  break;
241  }
242  }
243  close(ifd);
244  close(ofd);
245  if (len < 0) {
246  unlink(outfile);
247  return -1; /* error */
248  }
249  return 0; /* success */
250 }
251 
252 /*!
253  * \brief construct a filename. Absolute pathnames are preserved,
254  * relative names are prefixed by the sounds/ directory.
255  * The wav49 suffix is replaced by 'WAV'.
256  * Returns a malloc'ed string to be freed by the caller.
257  */
258 static char *build_filename(const char *filename, const char *ext)
259 {
260  char *fn = NULL;
261 
262  if (!strcmp(ext, "wav49"))
263  ext = "WAV";
264 
265  if (filename[0] == '/') {
266  if (ast_asprintf(&fn, "%s.%s", filename, ext) < 0) {
267  fn = NULL;
268  }
269  } else {
270  if (ast_asprintf(&fn, "%s/sounds/%s.%s",
271  ast_config_AST_DATA_DIR, filename, ext) < 0) {
272  fn = NULL;
273  }
274  }
275  return fn;
276 }
277 
278 /* compare type against the list 'exts' */
279 /* XXX need a better algorithm */
280 static int exts_compare(const char *exts, const char *type)
281 {
282  char tmp[256];
283  char *stringp = tmp, *ext;
284 
285  ast_copy_string(tmp, exts, sizeof(tmp));
286  while ((ext = strsep(&stringp, "|"))) {
287  if (!strcmp(ext, type))
288  return 1;
289  }
290 
291  return 0;
292 }
293 
294 /*! \internal \brief Close the file stream by canceling any pending read / write callbacks */
295 static void filestream_close(struct ast_filestream *f)
296 {
297  /* Stop a running stream if there is one */
298  if (f->owner) {
299  if (f->fmt->format & AST_FORMAT_AUDIO_MASK) {
300  f->owner->stream = NULL;
302  ast_settimeout(f->owner, 0, NULL, NULL);
303  } else if (f->fmt->format & AST_FORMAT_VIDEO_MASK) {
304  f->owner->vstream = NULL;
306  } else {
307  ast_log(AST_LOG_WARNING, "Unable to schedule deletion of filestream with unsupported type %s\n", f->fmt->name);
308  }
309  }
310 }
311 
312 static void filestream_destructor(void *arg)
313 {
314  struct ast_filestream *f = arg;
315  int status;
316  int pid = -1;
317 
318  /* Stop a running stream if there is one */
319  filestream_close(f);
320 
321  /* destroy the translator on exit */
322  if (f->trans)
324 
325  if (f->fmt->close) {
326  void (*closefn)(struct ast_filestream *) = f->fmt->close;
327  closefn(f);
328  }
329 
330  if (f->f) {
331  fclose(f->f);
332  }
333 
334  if (f->realfilename && f->filename) {
335  pid = ast_safe_fork(0);
336  if (!pid) {
337  execl("/bin/mv", "mv", "-f", f->filename, f->realfilename, SENTINEL);
338  _exit(1);
339  }
340  else if (pid > 0) {
341  /* Block the parent until the move is complete.*/
342  waitpid(pid, &status, 0);
343  }
344  }
345 
346  if (f->filename)
347  free(f->filename);
348  if (f->realfilename)
349  free(f->realfilename);
350  if (f->vfs)
351  ast_closestream(f->vfs);
352  if (f->write_buffer) {
354  }
355  if (f->orig_chan_name)
356  free((void *) f->orig_chan_name);
358 }
359 
360 static struct ast_filestream *get_filestream(struct ast_format *fmt, FILE *bfile)
361 {
362  struct ast_filestream *s;
363 
364  int l = sizeof(*s) + fmt->buf_size + fmt->desc_size; /* total allocation size */
365  if ( (s = ao2_alloc(l, filestream_destructor)) == NULL)
366  return NULL;
367  s->fmt = fmt;
368  s->f = bfile;
369 
370  if (fmt->desc_size)
371  s->_private = ((char *)(s + 1)) + fmt->buf_size;
372  if (fmt->buf_size)
373  s->buf = (char *)(s + 1);
374  s->fr.src = fmt->name;
375  return s;
376 }
377 
378 /*
379  * Default implementations of open and rewrite.
380  * Only use them if you don't have expensive stuff to do.
381  */
383 
384 static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
385 {
386  struct ast_format *f = s->fmt;
387  int ret = -1;
388  int (*openfn)(struct ast_filestream *s);
389 
390  if (mode == WRAP_OPEN && (openfn = f->open) && openfn(s))
391  ast_log(LOG_WARNING, "Unable to open format %s\n", f->name);
392  else if (mode == WRAP_REWRITE && f->rewrite && f->rewrite(s, comment))
393  ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
394  else {
395  /* preliminary checks succeed. update usecount */
397  ret = 0;
398  }
399  return ret;
400 }
401 
402 static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
403 {
404  return fn_wrapper(s, comment, WRAP_REWRITE);
405 }
406 
407 static int open_wrapper(struct ast_filestream *s)
408 {
409  return fn_wrapper(s, NULL, WRAP_OPEN);
410 }
411 
413  ACTION_EXISTS = 1, /* return matching format if file exists, 0 otherwise */
414  ACTION_DELETE, /* delete file, return 0 on success, -1 on error */
415  ACTION_RENAME, /* rename file. return 0 on success, -1 on error */
417  ACTION_COPY /* copy file. return 0 on success, -1 on error */
418 };
419 
420 /*!
421  * \brief perform various actions on a file. Second argument
422  * arg2 depends on the command:
423  * unused for EXISTS and DELETE
424  * destination file name (const char *) for COPY and RENAME
425  * struct ast_channel * for OPEN
426  * if fmt is NULL, OPEN will return the first matching entry,
427  * whereas other functions will run on all matching entries.
428  */
429 static format_t ast_filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
430 {
431  struct ast_format *f;
432  format_t res = (action == ACTION_EXISTS) ? 0 : -1;
433 
435  /* Check for a specific format */
437  char *stringp, *ext = NULL;
438 
439  if (fmt && !exts_compare(f->exts, fmt))
440  continue;
441 
442  /* Look for a file matching the supported extensions.
443  * The file must exist, and for OPEN, must match
444  * one of the formats supported by the channel.
445  */
446  stringp = ast_strdupa(f->exts); /* this is in the stack so does not need to be freed */
447  while ( (ext = strsep(&stringp, "|")) ) {
448  struct stat st;
449  char *fn = build_filename(filename, ext);
450 
451  if (fn == NULL)
452  continue;
453 
454  if ( stat(fn, &st) ) { /* file not existent */
455  ast_free(fn);
456  continue;
457  }
458  /* for 'OPEN' we need to be sure that the format matches
459  * what the channel can process
460  */
461  if (action == ACTION_OPEN) {
462  struct ast_channel *chan = (struct ast_channel *)arg2;
463  FILE *bfile;
464  struct ast_filestream *s;
465 
466  if ( !(chan->writeformat & f->format) &&
467  !((f->format & AST_FORMAT_AUDIO_MASK && fmt) ||
468  (f->format & AST_FORMAT_VIDEO_MASK && fmt))) {
469  ast_free(fn);
470  continue; /* not a supported format */
471  }
472  if ( (bfile = fopen(fn, "r")) == NULL) {
473  ast_free(fn);
474  continue; /* cannot open file */
475  }
476  s = get_filestream(f, bfile);
477  if (!s) {
478  fclose(bfile);
479  ast_free(fn); /* cannot allocate descriptor */
480  continue;
481  }
482  if (open_wrapper(s)) {
483  ast_free(fn);
484  ast_closestream(s);
485  continue; /* cannot run open on file */
486  }
487  if (st.st_size == 0) {
488  ast_log(LOG_WARNING, "File %s detected to have zero size.\n", fn);
489  }
490  /* ok this is good for OPEN */
491  res = 1; /* found */
492  s->lasttimeout = -1;
493  s->fmt = f;
494  s->trans = NULL;
495  s->filename = NULL;
496  if (s->fmt->format & AST_FORMAT_AUDIO_MASK) {
497  if (chan->stream)
498  ast_closestream(chan->stream);
499  chan->stream = s;
500  } else {
501  if (chan->vstream)
502  ast_closestream(chan->vstream);
503  chan->vstream = s;
504  }
505  ast_free(fn);
506  break;
507  }
508  switch (action) {
509  case ACTION_OPEN:
510  break; /* will never get here */
511 
512  case ACTION_EXISTS: /* return the matching format */
513  res |= f->format;
514  break;
515 
516  case ACTION_DELETE:
517  if ( (res = unlink(fn)) )
518  ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
519  break;
520 
521  case ACTION_RENAME:
522  case ACTION_COPY: {
523  char *nfn = build_filename((const char *)arg2, ext);
524  if (!nfn)
525  ast_log(LOG_WARNING, "Out of memory\n");
526  else {
527  res = action == ACTION_COPY ? copy(fn, nfn) : rename(fn, nfn);
528  if (res)
529  ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
530  action == ACTION_COPY ? "copy" : "rename",
531  fn, nfn, strerror(errno));
532  ast_free(nfn);
533  }
534  }
535  break;
536 
537  default:
538  ast_log(LOG_WARNING, "Unknown helper %u\n", action);
539  }
540  ast_free(fn);
541  }
542  }
544  return res;
545 }
546 
547 static int is_absolute_path(const char *filename)
548 {
549  return filename[0] == '/';
550 }
551 
552 static format_t fileexists_test(const char *filename, const char *fmt, const char *lang,
553  char *buf, int buflen)
554 {
555  if (buf == NULL) {
556  return -1;
557  }
558 
559  if (ast_language_is_prefix && !is_absolute_path(filename)) { /* new layout */
560  if (lang) {
561  snprintf(buf, buflen, "%s/%s", lang, filename);
562  } else {
563  snprintf(buf, buflen, "%s", filename);
564  }
565  } else { /* old layout */
566  strcpy(buf, filename); /* first copy the full string */
567  if (lang) {
568  /* insert the language and suffix if needed */
569  const char *c = strrchr(filename, '/');
570  int offset = c ? c - filename + 1 : 0; /* points right after the last '/' */
571  snprintf(buf + offset, buflen - offset, "%s/%s", lang, filename + offset);
572  }
573  }
574 
575  return ast_filehelper(buf, NULL, fmt, ACTION_EXISTS);
576 }
577 
578 /*!
579  * \brief helper routine to locate a file with a given format
580  * and language preference.
581  * Try preflang, preflang with stripped '_' suffices, or NULL.
582  *
583  * The last parameter(s) point to a buffer of sufficient size,
584  * which on success is filled with the matching filename.
585  */
586 static format_t fileexists_core(const char *filename, const char *fmt, const char *preflang,
587  char *buf, int buflen)
588 {
589  format_t res = -1;
590  char *lang;
591 
592  if (buf == NULL) {
593  return -1;
594  }
595 
596  /* We try languages in the following order:
597  * preflang (may include dialect and style codes)
598  * lang (preflang without dialect - if any)
599  * <none>
600  * default (unless the same as preflang or lang without dialect)
601  */
602 
603  lang = ast_strdupa(preflang);
604 
605  /* Try preferred language, including removing any style or dialect codes */
606  while (!ast_strlen_zero(lang)) {
607  char *end;
608 
609  if ((res = fileexists_test(filename, fmt, lang, buf, buflen)) > 0) {
610  return res;
611  }
612 
613  if ((end = strrchr(lang, '_')) != NULL) {
614  *end = '\0';
615  continue;
616  }
617 
618  break;
619  }
620 
621  /* Try without any language */
622  if ((res = fileexists_test(filename, fmt, NULL, buf, buflen)) > 0) {
623  return res;
624  }
625 
626  /* Finally try the default language unless it was already tried before */
627  if ((ast_strlen_zero(preflang) || strcmp(preflang, DEFAULT_LANGUAGE)) && (ast_strlen_zero(lang) || strcmp(lang, DEFAULT_LANGUAGE))) {
628  if ((res = fileexists_test(filename, fmt, DEFAULT_LANGUAGE, buf, buflen)) > 0) {
629  return res;
630  }
631  }
632 
633  return 0;
634 }
635 
636 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
637 {
638  return ast_openstream_full(chan, filename, preflang, 0);
639 }
640 
641 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
642 {
643  /*
644  * Use fileexists_core() to find a file in a compatible
645  * language and format, set up a suitable translator,
646  * and open the stream.
647  */
648  format_t fmts, res;
649  int buflen;
650  char *buf;
651 
652  if (!asis) {
653  /* do this first, otherwise we detect the wrong writeformat */
654  ast_stopstream(chan);
655  if (chan->generator)
657  }
658  if (preflang == NULL)
659  preflang = "";
660  buflen = strlen(preflang) + strlen(filename) + 4;
661  buf = ast_alloca(buflen);
662  fmts = fileexists_core(filename, NULL, preflang, buf, buflen);
663  if (fmts > 0)
664  fmts &= AST_FORMAT_AUDIO_MASK;
665  if (fmts < 1) {
666  ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
667  return NULL;
668  }
669  chan->oldwriteformat = chan->writeformat;
670  /* Set the channel to a format we can work with */
671  res = ast_set_write_format(chan, fmts);
672  if (res == -1) { /* No format available that works with this channel */
673  return NULL;
674  }
675  res = ast_filehelper(buf, chan, NULL, ACTION_OPEN);
676  if (res >= 0)
677  return chan->stream;
678  return NULL;
679 }
680 
681 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
682 {
683  /* As above, but for video. But here we don't have translators
684  * so we must enforce a format.
685  */
687  char *buf;
688  int buflen;
689 
690  if (preflang == NULL)
691  preflang = "";
692  buflen = strlen(preflang) + strlen(filename) + 4;
693  buf = ast_alloca(buflen);
694 
695  for (format = AST_FORMAT_FIRST_VIDEO_BIT; format <= AST_FORMAT_VIDEO_MASK; format = format << 1) {
696  int fd;
697  const char *fmt;
698 
699  if (!(chan->nativeformats & format))
700  continue;
701  fmt = ast_getformatname(format);
702  if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1) /* no valid format */
703  continue;
704  fd = ast_filehelper(buf, chan, fmt, ACTION_OPEN);
705  if (fd >= 0)
706  return chan->vstream;
707  ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
708  }
709  return NULL;
710 }
711 
712 static struct ast_frame *read_frame(struct ast_filestream *s, int *whennext)
713 {
714  struct ast_frame *fr, *new_fr;
715 
716  if (!s || !s->fmt) {
717  return NULL;
718  }
719 
720  if (!(fr = s->fmt->read(s, whennext))) {
721  return NULL;
722  }
723 
724  if (!(new_fr = ast_frisolate(fr))) {
725  ast_frfree(fr);
726  return NULL;
727  }
728 
729  if (new_fr != fr) {
730  ast_frfree(fr);
731  fr = new_fr;
732  }
733 
734  return fr;
735 }
736 
738 {
739  int whennext = 0;
740 
741  return read_frame(s, &whennext);
742 }
743 
748 };
749 
750 static int ast_fsread_audio(const void *data);
751 
753 {
754  int whennext = 0;
755 
756  while (!whennext) {
757  struct ast_frame *fr;
758 
759  if (s->orig_chan_name && strcasecmp(s->owner->name, s->orig_chan_name)) {
760  goto return_failure;
761  }
762 
763  fr = read_frame(s, &whennext);
764 
765  if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
766  if (fr) {
767  ast_log(LOG_WARNING, "Failed to write frame\n");
768  ast_frfree(fr);
769  }
770  goto return_failure;
771  }
772 
773  if (fr) {
774  ast_frfree(fr);
775  }
776  }
777 
778  if (whennext != s->lasttimeout) {
779  if (s->owner->timingfd > -1) {
780  float samp_rate = (float) ast_format_rate(s->fmt->format);
781  unsigned int rate;
782 
783  rate = (unsigned int) roundf(samp_rate / ((float) whennext));
784 
785  ast_settimeout_full(s->owner, rate, ast_fsread_audio, s, 1);
786  } else {
788  whennext / (ast_format_rate(s->fmt->format) / 1000), ast_fsread_audio, s);
789  }
790  s->lasttimeout = whennext;
791  return FSREAD_SUCCESS_NOSCHED;
792  }
793  return FSREAD_SUCCESS_SCHED;
794 
795 return_failure:
796  s->owner->streamid = -1;
797  ast_settimeout(s->owner, 0, NULL, NULL);
798  return FSREAD_FAILURE;
799 }
800 
801 static int ast_fsread_audio(const void *data)
802 {
803  struct ast_filestream *fs = (struct ast_filestream *)data;
804  enum fsread_res res;
805 
806  res = ast_readaudio_callback(fs);
807 
808  if (res == FSREAD_SUCCESS_SCHED)
809  return 1;
810 
811  return 0;
812 }
813 
814 static int ast_fsread_video(const void *data);
815 
817 {
818  int whennext = 0;
819 
820  while (!whennext) {
821  struct ast_frame *fr = read_frame(s, &whennext);
822 
823  if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
824  if (fr) {
825  ast_log(LOG_WARNING, "Failed to write frame\n");
826  ast_frfree(fr);
827  }
828  s->owner->vstreamid = -1;
829  return FSREAD_FAILURE;
830  }
831 
832  if (fr) {
833  ast_frfree(fr);
834  }
835  }
836 
837  if (whennext != s->lasttimeout) {
839  whennext / (ast_format_rate(s->fmt->format) / 1000),
840  ast_fsread_video, s);
841  s->lasttimeout = whennext;
842  return FSREAD_SUCCESS_NOSCHED;
843  }
844 
845  return FSREAD_SUCCESS_SCHED;
846 }
847 
848 static int ast_fsread_video(const void *data)
849 {
850  struct ast_filestream *fs = (struct ast_filestream *)data;
851  enum fsread_res res;
852 
853  res = ast_readvideo_callback(fs);
854 
855  if (res == FSREAD_SUCCESS_SCHED)
856  return 1;
857 
858  return 0;
859 }
860 
861 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
862 {
863  s->owner = chan;
864  return 0;
865 }
866 
868 {
869  enum fsread_res res;
870 
871  if (s->fmt->format & AST_FORMAT_AUDIO_MASK)
872  res = ast_readaudio_callback(s);
873  else
874  res = ast_readvideo_callback(s);
875 
876  return (res == FSREAD_FAILURE) ? -1 : 0;
877 }
878 
879 int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
880 {
881  return fs->fmt->seek(fs, sample_offset, whence);
882 }
883 
885 {
886  return fs->fmt->trunc(fs);
887 }
888 
890 {
891  return fs->fmt->tell(fs);
892 }
893 
894 int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
895 {
896  return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
897 }
898 
899 int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
900 {
901  return ast_seekstream(fs, -ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
902 }
903 
905 {
906  /* This used to destroy the filestream, but it now just decrements a refcount.
907  * We close the stream in order to quit queuing frames now, because we might
908  * change the writeformat, which could result in a subsequent write error, if
909  * the format is different. */
910  filestream_close(f);
911  ao2_ref(f, -1);
912  return 0;
913 }
914 
915 
916 /*
917  * Look the various language-specific places where a file could exist.
918  */
919 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
920 {
921  char *buf;
922  int buflen;
923 
924  if (preflang == NULL)
925  preflang = "";
926  buflen = strlen(preflang) + strlen(filename) + 4; /* room for everything */
927  buf = ast_alloca(buflen);
928  return fileexists_core(filename, fmt, preflang, buf, buflen);
929 }
930 
931 int ast_filedelete(const char *filename, const char *fmt)
932 {
933  return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
934 }
935 
936 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
937 {
938  return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
939 }
940 
941 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
942 {
943  return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
944 }
945 
946 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
947 {
948  struct ast_filestream *fs;
949  struct ast_filestream *vfs=NULL;
950  char fmt[256];
951  off_t pos;
952  int seekattempt;
953  int res;
954 
955  fs = ast_openstream(chan, filename, preflang);
956  if (!fs) {
957  ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
958  return -1;
959  }
960 
961  /* check to see if there is any data present (not a zero length file),
962  * done this way because there is no where for ast_openstream_full to
963  * return the file had no data. */
964  pos = ftello(fs->f);
965  seekattempt = fseeko(fs->f, -1, SEEK_END);
966  if (seekattempt) {
967  if (errno == EINVAL) {
968  /* Zero-length file, as opposed to a pipe */
969  return 0;
970  } else {
971  ast_seekstream(fs, 0, SEEK_SET);
972  }
973  } else {
974  fseeko(fs->f, pos, SEEK_SET);
975  }
976 
977  vfs = ast_openvstream(chan, filename, preflang);
978  if (vfs) {
979  ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
980  }
981 
983  fs->orig_chan_name = ast_strdup(chan->name);
984  if (ast_applystream(chan, fs))
985  return -1;
986  if (vfs && ast_applystream(chan, vfs))
987  return -1;
988  ast_test_suite_event_notify("PLAYBACK", "Message: %s\r\nChannel: %s", filename, chan->name);
989  res = ast_playstream(fs);
990  if (!res && vfs)
991  res = ast_playstream(vfs);
992  ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", chan->name, filename, ast_getformatname(chan->writeformat), preflang ? preflang : "default");
993 
994  return res;
995 }
996 
997 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
998 {
999  FILE *bfile;
1000  struct ast_format *f;
1001  struct ast_filestream *fs = NULL;
1002  char *fn;
1003  int format_found = 0;
1004 
1006 
1007  AST_RWLIST_TRAVERSE(&formats, f, list) {
1008  fs = NULL;
1009  if (!exts_compare(f->exts, type))
1010  continue;
1011  else
1012  format_found = 1;
1013 
1014  fn = build_filename(filename, type);
1015  if (!fn) {
1016  continue;
1017  }
1018  errno = 0;
1019  bfile = fopen(fn, "r");
1020 
1021  if (!bfile || (fs = get_filestream(f, bfile)) == NULL || open_wrapper(fs) ) {
1022  ast_log(LOG_WARNING, "Unable to open %s\n", fn);
1023  if (fs) {
1024  ast_closestream(fs);
1025  }
1026  fs = NULL;
1027  bfile = NULL;
1028  ast_free(fn);
1029  break;
1030  }
1031  /* found it */
1032  fs->trans = NULL;
1033  fs->fmt = f;
1034  fs->flags = flags;
1035  fs->mode = mode;
1036  fs->filename = ast_strdup(filename);
1037  fs->vfs = NULL;
1038  ast_free(fn);
1039  break;
1040  }
1041 
1043  if (!format_found)
1044  ast_log(LOG_WARNING, "No such format '%s'\n", type);
1045 
1046  return fs;
1047 }
1048 
1049 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
1050 {
1051  int fd, myflags = 0;
1052  /* compiler claims this variable can be used before initialization... */
1053  FILE *bfile = NULL;
1054  struct ast_format *f;
1055  struct ast_filestream *fs = NULL;
1056  char *buf = NULL;
1057  size_t size = 0;
1058  int format_found = 0;
1059 
1061 
1062  /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
1063  /* We really can't use O_APPEND as it will break WAV header updates */
1064  if (flags & O_APPEND) {
1065  flags &= ~O_APPEND;
1066  } else {
1067  myflags = O_TRUNC;
1068  }
1069 
1070  myflags |= O_WRONLY | O_CREAT;
1071 
1072  /* XXX need to fix this - we should just do the fopen,
1073  * not open followed by fdopen()
1074  */
1075  AST_RWLIST_TRAVERSE(&formats, f, list) {
1076  char *fn, *orig_fn = NULL;
1077  if (fs)
1078  break;
1079 
1080  if (!exts_compare(f->exts, type))
1081  continue;
1082  else
1083  format_found = 1;
1084 
1085  fn = build_filename(filename, type);
1086  if (!fn) {
1087  continue;
1088  }
1089  fd = open(fn, flags | myflags, mode);
1090  if (fd > -1) {
1091  /* fdopen() the resulting file stream */
1092  bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
1093  if (!bfile) {
1094  ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
1095  close(fd);
1096  fd = -1;
1097  }
1098  }
1099 
1100  if (ast_opt_cache_record_files && (fd > -1)) {
1101  char *c;
1102 
1103  fclose(bfile); /* this also closes fd */
1104  /*
1105  We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
1106  What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
1107  */
1108  orig_fn = ast_strdupa(fn);
1109  for (c = fn; *c; c++)
1110  if (*c == '/')
1111  *c = '_';
1112 
1113  size = strlen(fn) + strlen(record_cache_dir) + 2;
1114  buf = ast_alloca(size);
1115  strcpy(buf, record_cache_dir);
1116  strcat(buf, "/");
1117  strcat(buf, fn);
1118  ast_free(fn);
1119  fn = buf;
1120  fd = open(fn, flags | myflags, mode);
1121  if (fd > -1) {
1122  /* fdopen() the resulting file stream */
1123  bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
1124  if (!bfile) {
1125  ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
1126  close(fd);
1127  fd = -1;
1128  }
1129  }
1130  }
1131  if (fd > -1) {
1132  errno = 0;
1133  fs = get_filestream(f, bfile);
1134  if (fs) {
1135  if ((fs->write_buffer = ast_malloc(32768))) {
1136  setvbuf(fs->f, fs->write_buffer, _IOFBF, 32768);
1137  }
1138  }
1139  if (!fs || rewrite_wrapper(fs, comment)) {
1140  ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
1141  close(fd);
1142  if (orig_fn) {
1143  unlink(fn);
1144  unlink(orig_fn);
1145  }
1146  if (fs) {
1147  ast_closestream(fs);
1148  fs = NULL;
1149  }
1150  if (!buf) {
1151  ast_free(fn);
1152  }
1153  continue;
1154  }
1155  fs->trans = NULL;
1156  fs->fmt = f;
1157  fs->flags = flags;
1158  fs->mode = mode;
1159  if (orig_fn) {
1160  fs->realfilename = ast_strdup(orig_fn);
1161  fs->filename = ast_strdup(fn);
1162  } else {
1163  fs->realfilename = NULL;
1164  fs->filename = ast_strdup(filename);
1165  }
1166  fs->vfs = NULL;
1167  /* If truncated, we'll be at the beginning; if not truncated, then append */
1168  f->seek(fs, 0, SEEK_END);
1169  } else if (errno != EEXIST) {
1170  ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
1171  if (orig_fn)
1172  unlink(orig_fn);
1173  }
1174  /* if buf != NULL then fn is already free and pointing to it */
1175  if (!buf)
1176  ast_free(fn);
1177  }
1178 
1180 
1181  if (!format_found)
1182  ast_log(LOG_WARNING, "No such format '%s'\n", type);
1183 
1184  return fs;
1185 }
1186 
1187 /*!
1188  * \brief the core of all waitstream() functions
1189  */
1190 static int waitstream_core(struct ast_channel *c, const char *breakon,
1191  const char *forward, const char *reverse, int skip_ms,
1192  int audiofd, int cmdfd, const char *context)
1193 {
1194  const char *orig_chan_name = NULL;
1195  int err = 0;
1196 
1197  if (!breakon)
1198  breakon = "";
1199  if (!forward)
1200  forward = "";
1201  if (!reverse)
1202  reverse = "";
1203 
1204  /* Switch the channel to end DTMF frame only. waitstream_core doesn't care about the start of DTMF. */
1206 
1208  orig_chan_name = ast_strdupa(c->name);
1209 
1210  while (c->stream) {
1211  int res;
1212  int ms;
1213 
1214  if (orig_chan_name && strcasecmp(orig_chan_name, c->name)) {
1215  ast_stopstream(c);
1216  err = 1;
1217  break;
1218  }
1219 
1220  ms = ast_sched_wait(c->sched);
1221 
1222  if (ms < 0 && !c->timingfunc) {
1223  ast_stopstream(c);
1224  break;
1225  }
1226  if (ms < 0)
1227  ms = 1000;
1228  if (cmdfd < 0) {
1229  res = ast_waitfor(c, ms);
1230  if (res < 0) {
1231  ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1233  return res;
1234  }
1235  } else {
1236  int outfd;
1237  struct ast_channel *rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1238  if (!rchan && (outfd < 0) && (ms)) {
1239  /* Continue */
1240  if (errno == EINTR)
1241  continue;
1242  ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1244  return -1;
1245  } else if (outfd > -1) { /* this requires cmdfd set */
1246  /* The FD we were watching has something waiting */
1248  return 1;
1249  }
1250  /* if rchan is set, it is 'c' */
1251  res = rchan ? 1 : 0; /* map into 'res' values */
1252  }
1253  if (res > 0) {
1254  struct ast_frame *fr = ast_read(c);
1255  if (!fr) {
1257  return -1;
1258  }
1259  switch (fr->frametype) {
1260  case AST_FRAME_DTMF_END:
1261  if (context) {
1262  const char exten[2] = { fr->subclass.integer, '\0' };
1263  if (ast_exists_extension(c, context, exten, 1,
1264  S_COR(c->caller.id.number.valid, c->caller.id.number.str, NULL))) {
1265  res = fr->subclass.integer;
1266  ast_frfree(fr);
1268  return res;
1269  }
1270  } else {
1271  res = fr->subclass.integer;
1272  if (strchr(forward, res)) {
1273  int eoftest;
1274  ast_stream_fastforward(c->stream, skip_ms);
1275  eoftest = fgetc(c->stream->f);
1276  if (feof(c->stream->f)) {
1277  ast_stream_rewind(c->stream, skip_ms);
1278  } else {
1279  ungetc(eoftest, c->stream->f);
1280  }
1281  } else if (strchr(reverse, res)) {
1282  ast_stream_rewind(c->stream, skip_ms);
1283  } else if (strchr(breakon, res)) {
1284  ast_frfree(fr);
1286  return res;
1287  }
1288  }
1289  break;
1290  case AST_FRAME_CONTROL:
1291  switch (fr->subclass.integer) {
1292  case AST_CONTROL_HANGUP:
1293  case AST_CONTROL_BUSY:
1295  ast_frfree(fr);
1297  return -1;
1298  case AST_CONTROL_RINGING:
1299  case AST_CONTROL_ANSWER:
1300  case AST_CONTROL_VIDUPDATE:
1301  case AST_CONTROL_SRCUPDATE:
1302  case AST_CONTROL_SRCCHANGE:
1303  case AST_CONTROL_HOLD:
1304  case AST_CONTROL_UNHOLD:
1307  case AST_CONTROL_AOC:
1309  case -1:
1310  /* Unimportant */
1311  break;
1312  default:
1313  ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass.integer);
1314  }
1315  break;
1316  case AST_FRAME_VOICE:
1317  /* Write audio if appropriate */
1318  if (audiofd > -1) {
1319  if (write(audiofd, fr->data.ptr, fr->datalen) < 0) {
1320  ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
1321  }
1322  }
1323  default:
1324  /* Ignore all others */
1325  break;
1326  }
1327  ast_frfree(fr);
1328  }
1329  ast_sched_runq(c->sched);
1330  }
1331 
1333 
1334  return (err || c->_softhangup) ? -1 : 0;
1335 }
1336 
1337 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int ms)
1338 {
1339  return waitstream_core(c, breakon, forward, reverse, ms,
1340  -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */);
1341 }
1342 
1343 int ast_waitstream(struct ast_channel *c, const char *breakon)
1344 {
1345  return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL);
1346 }
1347 
1348 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1349 {
1350  return waitstream_core(c, breakon, NULL, NULL, 0,
1351  audiofd, cmdfd, NULL /* no context */);
1352 }
1353 
1354 int ast_waitstream_exten(struct ast_channel *c, const char *context)
1355 {
1356  /* Waitstream, with return in the case of a valid 1 digit extension */
1357  /* in the current or specified context being pressed */
1358 
1359  if (!context)
1360  context = c->context;
1361  return waitstream_core(c, NULL, NULL, NULL, 0,
1362  -1, -1, context);
1363 }
1364 
1365 /*
1366  * if the file name is non-empty, try to play it.
1367  * Return 0 if success, -1 if error, digit if interrupted by a digit.
1368  * If digits == "" then we can simply check for non-zero.
1369  */
1370 int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
1371 {
1372  int res = 0;
1373  if (!ast_strlen_zero(file)) {
1374  res = ast_streamfile(chan, file, chan->language);
1375  if (!res) {
1376  res = ast_waitstream(chan, digits);
1377  }
1378  }
1379  return res;
1380 }
1381 
1382 char *ast_format_str_reduce(char *fmts)
1383 {
1384  struct ast_format *f;
1385  struct ast_format *fmts_ptr[AST_MAX_FORMATS];
1386  char *fmts_str[AST_MAX_FORMATS];
1387  char *stringp, *type;
1388  char *orig = fmts;
1389  int i, j, x, first, found = 0;
1390  int len = strlen(fmts) + 1;
1391  int res;
1392 
1393  if (AST_RWLIST_RDLOCK(&formats)) {
1394  ast_log(LOG_WARNING, "Unable to lock format list\n");
1395  return NULL;
1396  }
1397 
1398  stringp = ast_strdupa(fmts);
1399 
1400  for (x = 0; (type = strsep(&stringp, "|")) && x < AST_MAX_FORMATS; x++) {
1402  if (exts_compare(f->exts, type)) {
1403  found = 1;
1404  break;
1405  }
1406  }
1407 
1408  fmts_str[x] = type;
1409  if (found) {
1410  fmts_ptr[x] = f;
1411  } else {
1412  fmts_ptr[x] = NULL;
1413  }
1414  }
1416 
1417  first = 1;
1418  for (i = 0; i < x; i++) {
1419  /* ignore invalid entries */
1420  if (!fmts_ptr[i]) {
1421  ast_log(LOG_WARNING, "ignoring unknown format '%s'\n", fmts_str[i]);
1422  continue;
1423  }
1424 
1425  /* special handling for the first entry */
1426  if (first) {
1427  res = snprintf(fmts, len, "%s", fmts_str[i]);
1428  fmts += res;
1429  len -= res;
1430  first = 0;
1431  continue;
1432  }
1433 
1434  found = 0;
1435  for (j = 0; j < i; j++) {
1436  /* this is a duplicate */
1437  if (fmts_ptr[j] == fmts_ptr[i]) {
1438  found = 1;
1439  break;
1440  }
1441  }
1442 
1443  if (!found) {
1444  res = snprintf(fmts, len, "|%s", fmts_str[i]);
1445  fmts += res;
1446  len -= res;
1447  }
1448  }
1449 
1450  if (first) {
1451  ast_log(LOG_WARNING, "no known formats found in format list (%s)\n", orig);
1452  return NULL;
1453  }
1454 
1455  return orig;
1456 }
1457 
1458 static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1459 {
1460 #define FORMAT "%-10s %-10s %-20s\n"
1461 #define FORMAT2 "%-10s %-10s %-20s\n"
1462  struct ast_format *f;
1463  int count_fmt = 0;
1464 
1465  switch (cmd) {
1466  case CLI_INIT:
1467  e->command = "core show file formats";
1468  e->usage =
1469  "Usage: core show file formats\n"
1470  " Displays currently registered file formats (if any).\n";
1471  return NULL;
1472  case CLI_GENERATE:
1473  return NULL;
1474  }
1475 
1476  if (a->argc != 4)
1477  return CLI_SHOWUSAGE;
1478 
1479  ast_cli(a->fd, FORMAT, "Format", "Name", "Extensions");
1480  ast_cli(a->fd, FORMAT, "------", "----", "----------");
1481 
1484  ast_cli(a->fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1485  count_fmt++;
1486  }
1488  ast_cli(a->fd, "%d file formats registered.\n", count_fmt);
1489  return CLI_SUCCESS;
1490 #undef FORMAT
1491 #undef FORMAT2
1492 }
1493 
1494 static struct ast_cli_entry cli_file[] = {
1495  AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
1496 };
1497 
1498 static void file_shutdown(void)
1499 {
1500  ast_cli_unregister_multiple(cli_file, ARRAY_LEN(cli_file));
1501 }
1502 
1503 int ast_file_init(void)
1504 {
1505  ast_cli_register_multiple(cli_file, ARRAY_LEN(cli_file));
1507  return 0;
1508 }
int ast_filecopy(const char *oldname, const char *newname, const char *fmt)
Copies a file.
Definition: file.c:941
static enum fsread_res ast_readvideo_callback(struct ast_filestream *s)
Definition: file.c:816
union ast_frame_subclass subclass
Definition: frame.h:146
off_t(* tell)(struct ast_filestream *fs)
Definition: mod_format.h:69
#define ast_channel_lock(chan)
Definition: channel.h:2466
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
int ast_file_init(void)
Definition: file.c:1503
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:946
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static format_t fileexists_test(const char *filename, const char *fmt, const char *lang, char *buf, int buflen)
Definition: file.c:552
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void ast_module_unref(struct ast_module *)
Definition: loader.c:1312
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
char * strsep(char **str, const char *delims)
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
Definition: app.c:2242
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Definition: linkedlists.h:332
int timingfd
Definition: channel.h:838
#define ast_strdup(a)
Definition: astmm.h:109
format_t writeformat
Definition: channel.h:854
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define ast_test_flag(p, flag)
Definition: utils.h:63
Support for translation of data formats. translate.c.
static struct ast_cli_entry cli_file[]
Definition: file.c:1494
void * ptr
Definition: frame.h:160
int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event Schedule an event to take place at some point in the future. callback will be called with data as the argument, when milliseconds into the future (approximately) If callback returns 0, no further events will be re-scheduled.
Definition: sched.c:446
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:51
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define ast_set_flag(p, flag)
Definition: utils.h:70
static void filestream_close(struct ast_filestream *f)
Definition: file.c:295
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
int buf_size
Definition: mod_format.h:89
static format_t fileexists_core(const char *filename, const char *fmt, const char *preflang, char *buf, int buflen)
helper routine to locate a file with a given format and language preference. Try preflang, preflang with stripped &#39;_&#39; suffices, or NULL.
Definition: file.c:586
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:150
int ast_settimeout_full(struct ast_channel *c, unsigned int rate, int(*func)(const void *data), void *data, unsigned int is_ao2_obj)
Definition: channel.c:3562
int(* write)(struct ast_filestream *, struct ast_frame *)
Definition: mod_format.h:65
int(* rewrite)(struct ast_filestream *s, const char *comment)
Prepare a stream for output, and comment it appropriately if applicable.
Definition: mod_format.h:63
struct ast_generator * generator
Definition: channel.h:747
#define AST_LOG_WARNING
Definition: logger.h:149
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
Definition: file.c:402
Test Framework API.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
struct ast_frame *(* read)(struct ast_filestream *, int *whennext)
Definition: mod_format.h:73
Definition: cli.h:146
Each supported file format is described by the following structure.
Definition: mod_format.h:43
static int waitstream_core(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int skip_ms, int audiofd, int cmdfd, const char *context)
the core of all waitstream() functions
Definition: file.c:1190
static char * handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: file.c:1458
static force_inline int ast_format_rate(format_t format)
Get the sample rate for a given format.
Definition: frame.h:809
char * realfilename
Definition: mod_format.h:107
struct ast_filestream * ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
Opens stream for use in seeking, playing.
Definition: file.c:641
struct ast_frame * ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume)
translates one or more frames Apply an input frame into the translator and receive zero or one output...
Definition: translate.c:328
float roundf(float x)
format_t nativeformats
Definition: channel.h:852
struct ast_frame * ast_frisolate(struct ast_frame *fr)
Makes a frame independent of any static storage.
Definition: frame.c:391
format_t codec
Definition: frame.h:137
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition: file.c:931
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static void file_shutdown(void)
Definition: file.c:1498
const char * ext
Definition: http.c:112
#define AST_FILE_MODE
Definition: asterisk.h:36
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **chan, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition: channel.c:3188
#define ast_verb(level,...)
Definition: logger.h:243
static int ast_fsread_video(const void *data)
Definition: file.c:848
char exts[80]
Definition: mod_format.h:45
Header for providers of file and format handling routines. Clients of these routines should include &quot;...
int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
Fast forward stream ms.
Definition: file.c:894
static int open_wrapper(struct ast_filestream *s)
Definition: file.c:407
Utility functions.
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:889
char * write_buffer
Definition: mod_format.h:121
struct ast_trans_pvt * ast_translator_build_path(format_t dest, format_t source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition: translate.c:282
format_t format
Definition: mod_format.h:47
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:77
#define ast_asprintf(a, b, c...)
Definition: astmm.h:121
static int exts_compare(const char *exts, const char *type)
Definition: file.c:280
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:703
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
format_t oldwriteformat
Definition: channel.h:837
static char * build_filename(const char *filename, const char *ext)
construct a filename. Absolute pathnames are preserved, relative names are prefixed by the sounds/ di...
Definition: file.c:258
#define SENTINEL
Definition: compiler.h:75
static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
Definition: file.c:384
static int is_absolute_path(const char *filename)
Definition: file.c:547
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
Definition: file.c:867
struct ast_filestream * ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:681
General Asterisk PBX channel definitions.
#define AST_SCHED_DEL(sched, id)
a loop construct to ensure that the scheduled task get deleted. The idea is that if we loop attemptin...
Definition: sched.h:51
Asterisk file paths, configured in asterisk.conf.
const char * src
Definition: frame.h:158
wrap_fn
Definition: file.c:382
const int fd
Definition: cli.h:153
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
int ast_language_is_prefix
Definition: file.c:63
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:493
int datalen
Definition: frame.h:148
int ast_settimeout(struct ast_channel *c, unsigned int rate, int(*func)(const void *data), void *data)
Enable or disable timer ticks for a channel.
Definition: channel.c:3557
Scheduler Routines (derived from cheops)
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:83
const char * orig_chan_name
Definition: mod_format.h:120
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
struct ast_frame fr
Definition: mod_format.h:117
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:565
struct ast_format * fmt
Definition: mod_format.h:102
static format_t ast_filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
perform various actions on a file. Second argument arg2 depends on the command: unused for EXISTS and...
Definition: file.c:429
struct sched_context * sched
Definition: channel.h:756
A set of macros to manage forward-linked lists.
int streamid
Definition: channel.h:835
char * ast_format_str_reduce(char *fmts)
Definition: file.c:1382
int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
Same as waitstream but allows stream to be forwarded or rewound.
Definition: file.c:1337
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:5400
Core PBX routines and definitions.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:542
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:184
void * _private
Definition: mod_format.h:119
const char * ast_config_AST_DATA_DIR
Definition: asterisk.c:262
int ast_format_unregister(const char *name)
Unregisters a file format.
Definition: file.c:104
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
struct ast_format::@189 list
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
char name[80]
Definition: mod_format.h:44
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applys a open stream to a channel.
Definition: file.c:861
int64_t format_t
Definition: frame_defs.h:32
#define free(a)
Definition: astmm.h:94
#define CLI_SHOWUSAGE
Definition: cli.h:44
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition: file.c:737
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition: file.c:899
struct ast_channel * owner
Definition: mod_format.h:115
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
Register a new file format capability. Adds a format to Asterisk&#39;s format abilities.
Definition: file.c:67
#define comment
Definition: ael_lex.c:961
int(* open)(struct ast_filestream *s)
Prepare an input stream for playback.
Definition: mod_format.h:55
Definition: file.c:65
const ast_string_field name
Definition: channel.h:787
struct ast_filestream * ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts writing a file.
Definition: file.c:1049
struct sla_ringing_trunk * first
Definition: app_meetme.c:965
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
void(* close)(struct ast_filestream *)
Definition: mod_format.h:76
int _softhangup
Definition: channel.h:832
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
#define AST_FORMAT_FIRST_VIDEO_BIT
Definition: frame.h:281
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:879
struct ast_trans_pvt * trans
Definition: mod_format.h:111
#define AST_FORMAT_VIDEO_MASK
Definition: frame.h:290
#define FORMAT2
#define ast_channel_unlock(chan)
Definition: channel.h:2467
#define ast_opt_cache_record_files
Definition: options.h:116
int errno
static const char name[]
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
fsread_res
Definition: file.c:744
struct ast_filestream * vstream
Definition: channel.h:758
#define AST_FORMAT_AUDIO_MASK
Definition: frame.h:274
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1370
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:904
static struct ast_frame * read_frame(struct ast_filestream *s, int *whennext)
Definition: file.c:712
static struct ast_format f[]
Definition: format_g726.c:181
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:4916
Prototypes for public functions only of internal interest,.
if(yyss+yystacksize-1<=yyssp)
Definition: ast_expr2.c:1874
static const char type[]
Definition: chan_nbs.c:57
#define ast_clear_flag(p, flag)
Definition: utils.h:77
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition: file.c:884
int ast_sched_runq(struct sched_context *con)
Runs the queue.
Definition: sched.c:600
const char * usage
Definition: cli.h:171
struct ast_module * module
Definition: mod_format.h:92
char record_cache_dir[AST_CACHE_DIR_LEN]
Definition: asterisk.c:195
#define CLI_SUCCESS
Definition: cli.h:43
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:3107
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int monfd)
Definition: file.c:1348
char * filename
Definition: mod_format.h:106
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:100
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition: channel.c:3539
Standard Command Line Interface.
#define ast_calloc(a, b)
Definition: astmm.h:82
#define DEFAULT_LANGUAGE
Definition: asterisk.h:39
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition: file.c:150
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1343
int vstreamid
Definition: channel.h:836
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
#define DEFAULT_SAMPLES_PER_MS
Definition: asterisk.h:42
int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place Determine the number of s...
Definition: sched.c:334
static int ast_fsread_audio(const void *data)
Definition: file.c:801
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int(* seek)(struct ast_filestream *, off_t, int)
Definition: mod_format.h:67
char * ast_getformatname_multiple(char *buf, size_t size, format_t format)
Get the names of a set of formats.
Definition: frame.c:591
int desc_size
Definition: mod_format.h:90
Data structure associated with a single frame of data.
Definition: frame.h:142
struct ast_filestream * ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts reading from a file.
Definition: file.c:997
static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
Definition: file.c:752
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
Definition: file.c:936
enum ast_frame_type frametype
Definition: frame.h:144
#define FORMAT
static int copy(const char *infile, const char *outfile)
Definition: file.c:215
struct ast_filestream * vfs
Definition: mod_format.h:109
#define ast_frfree(fr)
Definition: frame.h:583
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:107
static void filestream_destructor(void *arg)
Definition: file.c:312
struct ast_filestream * stream
Definition: channel.h:757
#define ast_malloc(a)
Definition: astmm.h:91
Asterisk module definitions.
static snd_pcm_format_t format
Definition: chan_alsa.c:93
union ast_frame::@172 data
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:602
const ast_string_field language
Definition: channel.h:787
file_action
Definition: file.c:412
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:128
static struct ast_filestream * get_filestream(struct ast_format *fmt, FILE *bfile)
Definition: file.c:360
struct ast_filestream * ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
Opens stream for use in seeking, playing.
Definition: file.c:636
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition: translate.c:272
jack_status_t status
Definition: app_jack.c:143
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int ast_waitstream_exten(struct ast_channel *c, const char *context)
Waits for a stream to stop or digit matching a valid one digit exten to be pressed.
Definition: file.c:1354
int(* trunc)(struct ast_filestream *fs)
Definition: mod_format.h:68
#define AST_MAX_FORMATS
Definition: file.h:44
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292