Asterisk - The Open Source Telephony Project GIT-master-57e2743
Loading...
Searching...
No Matches
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#include <dirent.h>
33#include <sys/stat.h>
34#include <sys/wait.h>
35#include <math.h>
36
37#include "asterisk/_private.h" /* declare ast_file_init() */
38#include "asterisk/paths.h" /* use ast_config_AST_DATA_DIR */
39#include "asterisk/mod_format.h"
40#include "asterisk/cli.h"
41#include "asterisk/channel.h"
42#include "asterisk/cel.h"
43#include "asterisk/sched.h"
44#include "asterisk/translate.h"
45#include "asterisk/utils.h"
46#include "asterisk/lock.h"
47#include "asterisk/app.h"
48#include "asterisk/pbx.h"
50#include "asterisk/module.h"
51#include "asterisk/astobj2.h"
52#include "asterisk/test.h"
53#include "asterisk/stasis.h"
54#include "asterisk/json.h"
57
59
62
63static struct ast_json *json_array_from_list(const char *list, const char *sep)
64{
66 char *stringp, *ext;
67
68 stringp = ast_strdupa(list); /* this is in the stack so does not need to be freed */
69 if (!array || !stringp) {
70 return NULL;
71 }
72
73 while ((ext = strsep(&stringp, sep))) {
75 return NULL;
76 }
77 }
78
79 return ast_json_ref(array);
80}
81
83{
84 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
85 RAII_VAR(struct ast_json_payload *, json_payload, NULL, ao2_cleanup);
86 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
87
88 if (!type) {
89 return -1;
90 }
91
92 json_object = ast_json_pack("{s: s, s: o}",
93 "format", f->name,
94 "extensions", json_array_from_list(f->exts, "|"));
95 if (!json_object) {
96 return -1;
97 }
98
99 json_payload = ast_json_payload_create(json_object);
100 if (!json_payload) {
101 return -1;
102 }
103
104 msg = stasis_message_create(type, json_payload);
105 if (!msg) {
106 return -1;
107 }
108
110 return 0;
111}
112
113/*!
114 * \brief Space required to store the longest extension from all registered file formats
115 *
116 * Stores the length, in bytes, of the longest extension from all registered file formats
117 * (<tt>struct ast_format_def</tt>). This is only updated during registration because it
118 * was easier to implement this way and only wastes a few bytes in the worst case.
119 *
120 * \note Protected by the \c formats list lock.
121 */
123
124int __ast_format_def_register(const struct ast_format_def *f, struct ast_module *mod)
125{
126 struct ast_format_def *tmp;
127
130 if (!strcasecmp(f->name, tmp->name)) {
132 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
133 return -1;
134 }
135 }
136 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
138 return -1;
139 }
140 *tmp = *f;
141 tmp->module = mod;
142 if (tmp->buf_size) {
143 /*
144 * Align buf_size properly, rounding up to the machine-specific
145 * alignment for pointers.
146 */
147 struct _test_align { void *a, *b; } p;
148 int align = (char *)&p.b - (char *)&p.a;
149 tmp->buf_size = ((f->buf_size + align - 1) / align) * align;
150 }
151
152 memset(&tmp->list, 0, sizeof(tmp->list));
153
154 /* Calculate the maximum extension length */
155 {
156 char *storage = ast_strdupa(tmp->exts);
157 char *stringp = storage;
158 const char *ext;
159
160 while ((ext = strsep(&stringp, "|"))) {
162 }
163 }
164
165 AST_RWLIST_INSERT_HEAD(&formats, tmp, list);
167 ast_verb(5, "Registered file format %s, extension(s) %s\n", f->name, f->exts);
169
170 return 0;
171}
172
174{
175 struct ast_format_def *tmp;
176 int res = -1;
177
180 if (!strcasecmp(name, tmp->name)) {
183 ast_free(tmp);
184 res = 0;
185 }
186 }
189
190 if (!res)
191 ast_verb(5, "Unregistered format %s\n", name);
192 else
193 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
194
195 return res;
196}
197
198FILE *ast_file_mkftemp(char *template_name, mode_t mode)
199{
200 FILE *p = NULL;
201 int pfd = mkstemp(template_name);
202 chmod(template_name, mode);
203 if (pfd > -1) {
204 p = fdopen(pfd, "w+");
205 if (!p) {
206 close(pfd);
207 pfd = -1;
208 }
209 }
210 return p;
211}
212
213int ast_file_fdtemp(const char *path, char **filename, const char *template_name)
214{
215 int fd;
216
217 if (ast_asprintf(filename, "%s/%s", path, template_name) < 0) {
218 ast_log(LOG_ERROR, "Failed to set up temporary file path\n");
219 return -1;
220 }
221
222 ast_mkdir(path, 0644);
223
224 if ((fd = mkstemp(*filename)) < 0) {
225 ast_log(LOG_NOTICE, "Failed to create temporary file\n");
226 ast_free(*filename);
227 return -1;
228 }
229
230 return fd;
231}
232
234{
235 struct ast_json * cel_event = NULL;
236
237 ast_channel_lock(tmp);
238
239 /* Stop a running stream if there is one */
240 if (ast_channel_stream(tmp)) {
243
244 cel_event = ast_json_pack("{ s: s }", "event", "FILE_STREAM_END");
245 if (cel_event) {
247 }
248
250 ast_log(LOG_WARNING, "Unable to restore format back to %s\n", ast_format_get_name(ast_channel_oldwriteformat(tmp)));
251 }
252 ast_json_unref(cel_event);
253
254 /* Stop the video stream too */
255 if (ast_channel_vstream(tmp) != NULL) {
258 }
259
261
262 return 0;
263}
264
265int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
266{
267 int res = -1;
268 if (f->frametype == AST_FRAME_VIDEO) {
270 /* This is the audio portion. Call the video one... */
271 if (!fs->vfs && fs->filename) {
272 const char *type = ast_format_get_name(f->subclass.format);
273 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
274 ast_debug(1, "Opened video output file\n");
275 }
276 if (fs->vfs)
277 return ast_writestream(fs->vfs, f);
278 /* else ignore */
279 return 0;
280 }
281 } else if (f->frametype != AST_FRAME_VOICE) {
282 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
283 return -1;
284 }
286 res = fs->fmt->write(fs, f);
287 if (res < 0)
288 ast_log(LOG_WARNING, "Natural write failed\n");
289 else if (res > 0)
290 ast_log(LOG_WARNING, "Huh??\n");
291 } else {
292 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
293 the one we've setup a translator for, we do the "wrong thing" XXX */
296 fs->trans = NULL;
297 }
298 if (!fs->trans) {
300 }
301 if (!fs->trans) {
302 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
304 } else {
305 struct ast_frame *trf;
307 /* Get the translated frame but don't consume the original in case they're using it on another stream */
308 if ((trf = ast_translate(fs->trans, f, 0))) {
309 struct ast_frame *cur;
310
311 /* the translator may have returned multiple frames, so process them */
312 for (cur = trf; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
313 if ((res = fs->fmt->write(fs, cur))) {
314 ast_log(LOG_WARNING, "Translated frame write failed\n");
315 break;
316 }
317 }
318 ast_frfree(trf);
319 } else {
320 res = 0;
321 }
322 }
323 }
324 return res;
325}
326
327static int copy(const char *infile, const char *outfile)
328{
329 int ifd, ofd, len;
330 char buf[4096]; /* XXX make it larger. */
331
332 if ((ifd = open(infile, O_RDONLY)) < 0) {
333 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
334 return -1;
335 }
336 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
337 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
338 close(ifd);
339 return -1;
340 }
341 while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
342 int res;
343 if (len < 0) {
344 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
345 break;
346 }
347 /* XXX handle partial writes */
348 res = write(ofd, buf, len);
349 if (res != len) {
350 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
351 len = -1; /* error marker */
352 break;
353 }
354 }
355 close(ifd);
356 close(ofd);
357 if (len < 0) {
358 unlink(outfile);
359 return -1; /* error */
360 }
361 return 0; /* success */
362}
363
364/*!
365 * \internal
366 * \brief Allocate a filename template with room for all registered extensions
367 *
368 * \note You must hold the \c formats list lock when calling this function
369 *
370 * \param[in] filename The name of the file, which may be an absolute path
371 * \param[out] extension_start On return, points to the memory offset within the returned
372 * string where candidate extensions should be stored
373 *
374 * \retval An allocated string large enough to accommodate all registered filename
375 * extensions which must be freed by the caller, or \c NULL on allocation failure
376 */
377static char *build_filename_template(const char *filename, char **extension_start)
378{
379 char *fn;
380 int prefix_length;
381 int res;
382
383 if (filename[0] == '/') {
384 res = ast_asprintf(&fn, "%s.%n%*s",
385 filename, &prefix_length, maximum_extension_length, "");
386 } else {
387 res = ast_asprintf(&fn, "%s/sounds/%s.%n%*s",
389 filename, &prefix_length, maximum_extension_length, "");
390 }
391
392 if (res == -1) {
393 return NULL;
394 }
395
396 *extension_start = fn + prefix_length;
397 return fn;
398}
399
400/*!
401 * \internal
402 * \brief Perform filename extension translation if necessary
403 *
404 * \note The length of any translated extension must be less than or equal to the length
405 * of the extension it is replacing.
406 */
407static const char *translate_extension(const char *extension)
408{
409 /* The wav49 -> WAV translation is duplicated in apps/app_mixmonitor.c, so
410 if you change it here you need to change it there as well */
411 if (!strcmp(extension, "wav49")) {
412 return "WAV";
413 }
414 return extension;
415}
416
417/*!
418 * \brief construct a filename. Absolute pathnames are preserved,
419 * relative names are prefixed by the sounds/ directory.
420 * Returns a malloc'ed string to be freed by the caller.
421 */
422static char *build_filename(const char *filename, const char *ext)
423{
424 char *fn = NULL;
425
426 if (filename[0] == '/') {
427 if (ast_asprintf(&fn, "%s.%s", filename, translate_extension(ext)) < 0) {
428 fn = NULL;
429 }
430 } else {
431 if (ast_asprintf(&fn, "%s/sounds/%s.%s",
433 fn = NULL;
434 }
435 }
436 return fn;
437}
438
439/* compare type against the list 'exts' */
440/* XXX need a better algorithm */
441static int type_in_list(const char *list, const char *type, int (*cmp)(const char *s1, const char *s2))
442{
443 char *stringp = ast_strdupa(list), *item;
444
445 while ((item = strsep(&stringp, "|"))) {
446 if (!cmp(item, type)) {
447 return 1;
448 }
449 }
450
451 return 0;
452}
453
454#define exts_compare(list, type) (type_in_list((list), (type), strcmp))
455
456/*!
457 * \internal
458 * \brief Close the file stream by canceling any pending read / write callbacks
459 */
460static void filestream_close(struct ast_filestream *f)
461{
462 enum ast_media_type format_type = ast_format_get_type(f->fmt->format);
463
464 if (!f->owner) {
465 return;
466 }
467
468 /* Stop a running stream if there is one */
469 switch (format_type)
470 {
474 ast_settimeout(f->owner, 0, NULL, NULL);
475 break;
479 break;
480 default:
481 ast_log(AST_LOG_WARNING, "Unable to schedule deletion of filestream with unsupported type %s\n", f->fmt->name);
482 break;
483 }
484}
485
486static void filestream_destructor(void *arg)
487{
488 struct ast_filestream *f = arg;
489 int status;
490 int pid = -1;
491
492 /* Stop a running stream if there is one */
494
495 /* destroy the translator on exit */
496 if (f->trans)
498
499 if (f->fmt->close) {
500 void (*closefn)(struct ast_filestream *) = f->fmt->close;
501 closefn(f);
502 }
503
504 if (f->f) {
505 fclose(f->f);
506 }
507
508 if (f->realfilename && f->filename) {
509 pid = ast_safe_fork(0);
510 if (!pid) {
511 execl("/bin/mv", "mv", "-f", f->filename, f->realfilename, SENTINEL);
512 _exit(1);
513 }
514 else if (pid > 0) {
515 /* Block the parent until the move is complete.*/
516 waitpid(pid, &status, 0);
517 }
518 }
519
520 ast_free(f->filename);
521 ast_free(f->realfilename);
522 ast_free(f->open_extension);
523 if (f->vfs)
524 ast_closestream(f->vfs);
525 ast_free(f->write_buffer);
526 ast_free((void *)f->orig_chan_name);
527 ao2_cleanup(f->lastwriteformat);
528 ao2_cleanup(f->fr.subclass.format);
529 ast_module_unref(f->fmt->module);
530}
531
532static struct ast_filestream *get_filestream(struct ast_format_def *fmt, FILE *bfile)
533{
534 struct ast_filestream *s;
535 int l = sizeof(*s) + fmt->buf_size + fmt->desc_size; /* total allocation size */
536
537 if (!ast_module_running_ref(fmt->module)) {
538 return NULL;
539 }
540
542 if (!s) {
543 ast_module_unref(fmt->module);
544 return NULL;
545 }
546 s->fmt = fmt;
547 s->f = bfile;
548
549 if (fmt->desc_size)
550 s->_private = ((char *)(s + 1)) + fmt->buf_size;
551 if (fmt->buf_size)
552 s->buf = (char *)(s + 1);
553 s->fr.src = fmt->name;
554
559 }
560 s->fr.mallocd = 0;
562
563 return s;
564}
565
566/*
567 * Default implementations of open and rewrite.
568 * Only use them if you don't have expensive stuff to do.
569 */
571
572static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
573{
574 struct ast_format_def *f = s->fmt;
575 int ret = -1;
576 int (*openfn)(struct ast_filestream *s);
577
578 if (mode == WRAP_OPEN && (openfn = f->open) && openfn(s))
579 ast_log(LOG_WARNING, "Unable to open format %s\n", f->name);
580 else if (mode == WRAP_REWRITE && f->rewrite && f->rewrite(s, comment))
581 ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
582 else {
583 /* preliminary checks succeed. */
584 ret = 0;
585 }
586 return ret;
587}
588
589static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
590{
591 return fn_wrapper(s, comment, WRAP_REWRITE);
592}
593
594static int open_wrapper(struct ast_filestream *s)
595{
596 return fn_wrapper(s, NULL, WRAP_OPEN);
597}
598
600 ACTION_EXISTS = 1, /* return matching format if file exists, 0 otherwise */
601 ACTION_DELETE, /* delete file, return 0 on success, -1 on error */
602 ACTION_RENAME, /* rename file. return 0 on success, -1 on error */
604 ACTION_COPY /* copy file. return 0 on success, -1 on error */
606
607/*!
608 * \internal
609 * \brief perform various actions on a file. Second argument
610 * \note arg2 depends on the command:
611 * unused for DELETE
612 * optional ast_format_cap holding all the formats found for a file, for EXISTS.
613 * destination file name (const char *) for COPY and RENAME
614 * struct ast_channel * for OPEN
615 * if fmt is NULL, OPEN will return the first matching entry,
616 * whereas other functions will run on all matching entries.
617 */
618static int filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
619{
620 struct ast_format_def *f;
621 int res = (action == ACTION_EXISTS) ? 0 : -1;
622
623 char *extension_start;
624 char *fn;
625
627
628 fn = build_filename_template(filename, &extension_start);
629 if (!fn) {
631 return res;
632 }
633
634 /* Check for a specific format */
636 char *ext = NULL;
637 char storage[strlen(f->exts) + 1];
638 char *stringp;
639
640 if (fmt && !exts_compare(f->exts, fmt))
641 continue;
642
643 /* Look for a file matching the supported extensions.
644 * The file must exist, and for OPEN, must match
645 * one of the formats supported by the channel.
646 */
647 strcpy(storage, f->exts); /* safe - this is in the stack so does not need to be freed */
648 stringp = storage;
649 while ( (ext = strsep(&stringp, "|")) ) {
650 struct stat st;
651
652 /* Append the extension to our template */
653 strcpy(extension_start, translate_extension(ext));
654
655 if ( stat(fn, &st) ) { /* file not existent */
656 continue;
657 }
658 /* for 'OPEN' we need to be sure that the format matches
659 * what the channel can process
660 */
661 if (action == ACTION_OPEN) {
662 struct ast_channel *chan = (struct ast_channel *)arg2;
663 FILE *bfile;
664 struct ast_filestream *s;
665
667 !(((ast_format_get_type(f->format) == AST_MEDIA_TYPE_AUDIO) && fmt) ||
668 ((ast_format_get_type(f->format) == AST_MEDIA_TYPE_VIDEO) && fmt))) {
669 ast_debug(3, "File %s format is not compatible with the channel\n", fn);
670 continue; /* not a supported format */
671 }
672 if ( (bfile = fopen(fn, "r")) == NULL) {
673 ast_log(LOG_WARNING, "Failed to open file %s due to: %s\n", fn, strerror(errno));
674 continue; /* cannot open file */
675 }
676 s = get_filestream(f, bfile);
677 if (!s) {
678 ast_log(LOG_WARNING, "Failed to open file %s due to: file stream creation failure\n", fn);
679 fclose(bfile);
680 continue; /* cannot allocate descriptor */
681 }
682 if (open_wrapper(s)) {
684 continue; /* cannot run open on file */
685 }
686 if (st.st_size == 0) {
687 ast_log(LOG_WARNING, "File %s detected to have zero size.\n", fn);
688 }
689 /* ok this is good for OPEN */
690 res = 1; /* found */
691 s->lasttimeout = -1;
692 s->fmt = f;
693 s->trans = NULL;
694 s->filename = NULL;
697 if (ast_channel_stream(chan))
699 ast_channel_stream_set(chan, s);
700 } else {
701 if (ast_channel_vstream(chan))
704 }
705 break;
706 }
707 switch (action) {
708 case ACTION_OPEN:
709 break; /* will never get here */
710
711 case ACTION_EXISTS: /* return the matching format */
712 /* if arg2 is present, it is a format capabilities structure.
713 * Add this format to the set of formats this file can be played in */
714 if (arg2) {
715 ast_format_cap_append((struct ast_format_cap *) arg2, f->format, 0);
716 }
717 res = 1; /* file does exist and format it exists in is returned in arg2 */
718 break;
719
720 case ACTION_DELETE:
721 if ( (res = unlink(fn)) )
722 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
723 break;
724
725 case ACTION_RENAME:
726 case ACTION_COPY: {
727 char *nfn = build_filename((const char *)arg2, ext);
728 if (!nfn)
729 ast_log(LOG_WARNING, "Out of memory\n");
730 else {
731 res = action == ACTION_COPY ? copy(fn, nfn) : rename(fn, nfn);
732 if (res)
733 ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
734 action == ACTION_COPY ? "copy" : "rename",
735 fn, nfn, strerror(errno));
736 ast_free(nfn);
737 }
738 }
739 break;
740
741 default:
742 ast_log(LOG_WARNING, "Unknown helper %u\n", action);
743 }
744 }
745
746 /* If we have successfully opened a file, we are done. */
747 if (action == ACTION_OPEN && res == 1) {
748 break;
749 }
750 }
752 ast_free(fn);
753 return res;
754}
755
756static int is_absolute_path(const char *filename)
757{
758 return filename[0] == '/';
759}
760
761static int is_remote_path(const char *filename)
762{
763 return strstr(filename, "://") ? 1 : 0;
764}
765
766/*!
767 * \brief test if a file exists for a given format.
768 * \note result_cap is OPTIONAL
769 * \retval 1 true and result_cap represents format capabilities file exists in.
770 * \retval 0 false
771 */
772static int fileexists_test(const char *filename, const char *fmt, const char *lang,
773 char *buf, int buflen, struct ast_format_cap *result_cap)
774{
775 if (buf == NULL) {
776 return 0;
777 }
778
780 return filehelper(buf, result_cap, NULL, ACTION_EXISTS);
781 }
782
784 if (lang) {
785 snprintf(buf, buflen, "%s/%s", lang, filename);
786 } else {
787 snprintf(buf, buflen, "%s", filename);
788 }
789 } else {
790 strcpy(buf, filename); /* first copy the full string */
791 if (lang) {
792 /* insert the language and suffix if needed */
793 const char *c = strrchr(filename, '/');
794 int offset = c ? c - filename + 1 : 0; /* points right after the last '/' */
795 snprintf(buf + offset, buflen - offset, "%s/%s", lang, filename + offset);
796 }
797 }
798
799 return filehelper(buf, result_cap, fmt, ACTION_EXISTS);
800}
801
802/*!
803 * \brief helper routine to locate a file with a given format
804 * and language preference.
805 *
806 * \note Try preflang, preflang with stripped '_' suffices, or NULL.
807 *
808 * \note The last parameter(s) point to a buffer of sufficient size,
809 * which on success is filled with the matching filename.
810 *
811 * \param filename Name of the file.
812 * \param fmt Format to look for the file in. OPTIONAL
813 * \param preflang The preferred language
814 * \param buf Returns the matching filename
815 * \param buflen Size of the buf
816 * \param result_cap OPTIONAL format capabilities result structure
817 * returns what formats the file was found in.
818 *
819 * \retval 1 true. file exists and result format is set
820 * \retval 0 false. file does not exist.
821 */
822static int fileexists_core(const char *filename, const char *fmt, const char *preflang,
823 char *buf, int buflen, struct ast_format_cap *result_cap)
824{
825 char *lang;
826
827 if (buf == NULL) {
828 return 0;
829 }
830
831 /* We try languages in the following order:
832 * preflang (may include dialect and style codes)
833 * lang (preflang without dialect - if any)
834 * <none>
835 * default (unless the same as preflang or lang without dialect)
836 */
837
838 lang = ast_strdupa(preflang);
839
840 /* Try preferred language, including removing any style or dialect codes */
841 while (!ast_strlen_zero(lang)) {
842 char *end;
843
844 if (fileexists_test(filename, fmt, lang, buf, buflen, result_cap)) {
845 return 1;
846 }
847
848 if ((end = strrchr(lang, '_')) != NULL) {
849 *end = '\0';
850 continue;
851 }
852
853 break;
854 }
855
856 /* Try without any language */
857 if (fileexists_test(filename, fmt, NULL, buf, buflen, result_cap)) {
858 return 1;
859 }
860
861 /* Finally try the default language unless it was already tried before */
862 if ((ast_strlen_zero(preflang) || strcmp(preflang, DEFAULT_LANGUAGE)) && (ast_strlen_zero(lang) || strcmp(lang, DEFAULT_LANGUAGE))) {
863 if ((fileexists_test(filename, fmt, DEFAULT_LANGUAGE, buf, buflen, result_cap)) > 0) {
864 return 1;
865 }
866 }
867
868 return 0;
869}
870
872 const char *filename, const char *preflang, int asis, int quiet)
873{
874 /*
875 * Use fileexists_core() to find a file in a compatible
876 * language and format, set up a suitable translator,
877 * and open the stream.
878 */
879 struct ast_format_cap *file_fmt_cap;
880 int res;
881 int buflen;
882 char *buf;
883
884 if (!asis) {
885 /* do this first, otherwise we detect the wrong writeformat */
886 ast_stopstream(chan);
887 if (ast_channel_generator(chan))
889 }
890 if (preflang == NULL)
891 preflang = "";
892 buflen = strlen(preflang) + strlen(filename) + 4;
893 buf = ast_alloca(buflen);
894
895 if (!(file_fmt_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
896 return NULL;
897 }
898 if (!fileexists_core(filename, NULL, preflang, buf, buflen, file_fmt_cap) ||
900
901 if (!quiet) {
902 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
903 }
904 ao2_ref(file_fmt_cap, -1);
905 return NULL;
906 }
907
908 /* Set the channel to a format we can work with and save off the previous format. */
909 ast_channel_lock(chan);
911 /* Set the channel to the best format that exists for the file. */
912 res = ast_set_write_format_from_cap(chan, file_fmt_cap);
913 ast_channel_unlock(chan);
914 /* don't need this anymore now that the channel's write format is set. */
915 ao2_ref(file_fmt_cap, -1);
916
917 if (res == -1) { /* No format available that works with this channel */
918 return NULL;
919 }
920 res = filehelper(buf, chan, NULL, ACTION_OPEN);
921 if (res >= 0)
922 return ast_channel_stream(chan);
923 return NULL;
924}
925
926struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
927{
928 return openstream_internal(chan, filename, preflang, 0, 0);
929}
930
932 const char *filename, const char *preflang, int asis)
933{
934 return openstream_internal(chan, filename, preflang, asis, 0);
935}
936
938 const char *filename, const char *preflang)
939{
940 /* As above, but for video. But here we don't have translators
941 * so we must enforce a format.
942 */
943 struct ast_format_cap *nativeformats, *tmp_cap;
944 char *buf;
945 int buflen;
946 int i, fd;
947
948 if (preflang == NULL) {
949 preflang = "";
950 }
951 buflen = strlen(preflang) + strlen(filename) + 4;
952 buf = ast_alloca(buflen);
953
954 ast_channel_lock(chan);
955 nativeformats = ao2_bump(ast_channel_nativeformats(chan));
956 ast_channel_unlock(chan);
957
958 /* is the channel capable of video without translation ?*/
959 if (!ast_format_cap_has_type(nativeformats, AST_MEDIA_TYPE_VIDEO)) {
960 ao2_cleanup(nativeformats);
961 return NULL;
962 }
964 ao2_cleanup(nativeformats);
965 return NULL;
966 }
967 /* Video is supported, so see what video formats exist for this file */
968 if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) {
969 ao2_ref(tmp_cap, -1);
970 ao2_cleanup(nativeformats);
971 return NULL;
972 }
973
974 /* iterate over file formats and pick the first one compatible with the channel's native formats */
975 for (i = 0; i < ast_format_cap_count(tmp_cap); ++i) {
976 struct ast_format *format = ast_format_cap_get_format(tmp_cap, i);
977
978 if ((ast_format_get_type(format) != AST_MEDIA_TYPE_VIDEO) ||
979 !ast_format_cap_iscompatible(nativeformats, tmp_cap)) {
980 ao2_ref(format, -1);
981 continue;
982 }
983
984 fd = filehelper(buf, chan, ast_format_get_name(format), ACTION_OPEN);
985 if (fd >= 0) {
986 ao2_ref(format, -1);
987 ao2_ref(tmp_cap, -1);
988 ao2_cleanup(nativeformats);
989 return ast_channel_vstream(chan);
990 }
991 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
992 ao2_ref(format, -1);
993 }
994 ao2_ref(tmp_cap, -1);
995 ao2_cleanup(nativeformats);
996
997 return NULL;
998}
999
1000static struct ast_frame *read_frame(struct ast_filestream *s, int *whennext)
1001{
1002 struct ast_frame *fr, *new_fr;
1003
1004 if (!s || !s->fmt) {
1005 return NULL;
1006 }
1007
1008 if (!(fr = s->fmt->read(s, whennext))) {
1009 return NULL;
1010 }
1011
1012 if (!(new_fr = ast_frisolate(fr))) {
1013 ast_frfree(fr);
1014 return NULL;
1015 }
1016
1017 if (new_fr != fr) {
1018 ast_frfree(fr);
1019 fr = new_fr;
1020 }
1021
1022 return fr;
1023}
1024
1026{
1027 int whennext = 0;
1028
1029 return read_frame(s, &whennext);
1030}
1031
1037
1038static int ast_fsread_audio(const void *data);
1039
1041{
1042 int whennext = 0;
1043
1044 while (!whennext) {
1045 struct ast_frame *fr;
1046
1047 if (s->orig_chan_name && strcasecmp(ast_channel_name(s->owner), s->orig_chan_name)) {
1048 goto return_failure;
1049 }
1050
1051 fr = read_frame(s, &whennext);
1052
1053 if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
1054 if (fr) {
1055 ast_debug(2, "Failed to write frame\n");
1056 ast_frfree(fr);
1057 }
1058 goto return_failure;
1059 }
1060
1061 if (fr) {
1062 ast_frfree(fr);
1063 }
1064 }
1065
1066 if (whennext != s->lasttimeout) {
1067 if (ast_channel_timingfd(s->owner) > -1) {
1068 float samp_rate = (float) ast_format_get_sample_rate(s->fmt->format);
1069 unsigned int rate;
1070
1071 rate = (unsigned int) roundf(samp_rate / ((float) whennext));
1072
1074 } else {
1076 }
1077 s->lasttimeout = whennext;
1079 }
1080 return FSREAD_SUCCESS_SCHED;
1081
1082return_failure:
1084 ast_settimeout(s->owner, 0, NULL, NULL);
1085 return FSREAD_FAILURE;
1086}
1087
1088static int ast_fsread_audio(const void *data)
1089{
1090 struct ast_filestream *fs = (struct ast_filestream *)data;
1091 enum fsread_res res;
1092
1093 res = ast_readaudio_callback(fs);
1094
1095 if (res == FSREAD_SUCCESS_SCHED)
1096 return 1;
1097
1098 return 0;
1099}
1100
1101static int ast_fsread_video(const void *data);
1102
1104{
1105 int whennext = 0;
1106
1107 while (!whennext) {
1108 struct ast_frame *fr = read_frame(s, &whennext);
1109
1110 if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
1111 if (fr) {
1112 ast_debug(2, "Failed to write frame\n");
1113 ast_frfree(fr);
1114 }
1116 return FSREAD_FAILURE;
1117 }
1118
1119 if (fr) {
1120 ast_frfree(fr);
1121 }
1122 }
1123
1124 if (whennext != s->lasttimeout) {
1126 s->lasttimeout = whennext;
1128 }
1129
1130 return FSREAD_SUCCESS_SCHED;
1131}
1132
1133static int ast_fsread_video(const void *data)
1134{
1135 struct ast_filestream *fs = (struct ast_filestream *)data;
1136 enum fsread_res res;
1137
1138 res = ast_readvideo_callback(fs);
1139
1140 if (res == FSREAD_SUCCESS_SCHED)
1141 return 1;
1142
1143 return 0;
1144}
1145
1146int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
1147{
1148 s->owner = chan;
1149 return 0;
1150}
1151
1153{
1154 enum fsread_res res;
1155
1157 res = ast_readaudio_callback(s);
1158 else
1159 res = ast_readvideo_callback(s);
1160
1161 return (res == FSREAD_FAILURE) ? -1 : 0;
1162}
1163
1164int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
1165{
1166 return fs->fmt->seek(fs, sample_offset, whence);
1167}
1168
1170{
1171 return fs->fmt->trunc(fs);
1172}
1173
1175{
1176 return fs->fmt->tell(fs);
1177}
1178
1180{
1182}
1183
1185{
1186 return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
1187}
1188
1189int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
1190{
1191 off_t offset = ast_tellstream(fs);
1192 if (ms * DEFAULT_SAMPLES_PER_MS > offset) {
1193 /* Don't even bother asking the file format to seek to a negative offset... */
1194 ast_debug(1, "Restarting, rather than seeking to negative offset %ld\n", (long) (offset - (ms * DEFAULT_SAMPLES_PER_MS)));
1195 return ast_seekstream(fs, 0, SEEK_SET);
1196 }
1197 return ast_seekstream(fs, -ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
1198}
1199
1201{
1202 /* This used to destroy the filestream, but it now just decrements a refcount.
1203 * We close the stream in order to quit queuing frames now, because we might
1204 * change the writeformat, which could result in a subsequent write error, if
1205 * the format is different. */
1206 if (f == NULL) {
1207 return 0;
1208 }
1210 ao2_ref(f, -1);
1211 return 0;
1212}
1213
1214
1215/*
1216 * Look the various language-specific places where a file could exist.
1217 */
1218int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
1219{
1220 char *buf;
1221 int buflen;
1222
1223 if (preflang == NULL)
1224 preflang = "";
1225 buflen = strlen(preflang) + strlen(filename) + 4; /* room for everything */
1226 buf = ast_alloca(buflen);
1227 return fileexists_core(filename, fmt, preflang, buf, buflen, NULL) ? 1 : 0;
1228}
1229
1230int ast_filedelete(const char *filename, const char *fmt)
1231{
1233}
1234
1235int ast_filerename(const char *filename, const char *filename2, const char *fmt)
1236{
1237 return filehelper(filename, filename2, fmt, ACTION_RENAME);
1238}
1239
1240int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
1241{
1242 return filehelper(filename, filename2, fmt, ACTION_COPY);
1243}
1244
1245static int __ast_file_read_dirs(const char *path, ast_file_on_file on_file,
1246 void *obj, int max_depth)
1247{
1248 DIR *dir;
1249 struct dirent *entry;
1250 int res;
1251
1252 if (!(dir = opendir(path))) {
1253 ast_log(LOG_ERROR, "Error opening directory - %s: %s\n",
1254 path, strerror(errno));
1255 return -1;
1256 }
1257
1258 --max_depth;
1259
1260 res = 0;
1261
1262 while ((entry = readdir(dir)) != NULL && !errno) {
1263 int is_file = 0;
1264 int is_dir = 0;
1265 RAII_VAR(char *, full_path, NULL, ast_free);
1266
1267 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
1268 continue;
1269 }
1270
1271/*
1272 * If the dirent structure has a d_type use it to determine if we are dealing with
1273 * a file or directory. Unfortunately if it doesn't have it, or if the type is
1274 * unknown, or a link then we'll need to use the stat function instead.
1275 */
1276#ifdef _DIRENT_HAVE_D_TYPE
1277 if (entry->d_type != DT_UNKNOWN && entry->d_type != DT_LNK) {
1278 is_file = entry->d_type == DT_REG;
1279 is_dir = entry->d_type == DT_DIR;
1280 } else
1281#endif
1282 {
1283 struct stat statbuf;
1284
1285 /*
1286 * Don't use alloca or we risk blowing out the stack if recursing
1287 * into subdirectories.
1288 */
1289 full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2);
1290 if (!full_path) {
1291 return -1;
1292 }
1293 sprintf(full_path, "%s/%s", path, entry->d_name);
1294
1295 if (stat(full_path, &statbuf)) {
1296 ast_log(LOG_ERROR, "Error reading path stats - %s: %s\n",
1297 full_path, strerror(errno));
1298 /*
1299 * Output an error, but keep going. It could just be
1300 * a broken link and other files could be fine.
1301 */
1302 continue;
1303 }
1304
1305 is_file = S_ISREG(statbuf.st_mode);
1306 is_dir = S_ISDIR(statbuf.st_mode);
1307 }
1308
1309 if (is_file) {
1310 /* If the handler returns non-zero then stop */
1311 if ((res = on_file(path, entry->d_name, obj))) {
1312 break;
1313 }
1314 /* Otherwise move on to next item in directory */
1315 continue;
1316 }
1317
1318 if (!is_dir) {
1319 ast_debug(5, "Skipping %s: not a regular file or directory\n", full_path);
1320 continue;
1321 }
1322
1323 /* Only re-curse into sub-directories if not at the max depth */
1324 if (max_depth != 0) {
1325 if (!full_path) {
1326 /* Don't use alloca. See note above. */
1327 full_path = ast_malloc(strlen(path) + strlen(entry->d_name) + 2);
1328 if (!full_path) {
1329 return -1;
1330 }
1331 sprintf(full_path, "%s/%s", path, entry->d_name);
1332 }
1333
1334 if ((res = __ast_file_read_dirs(full_path, on_file, obj, max_depth))) {
1335 break;
1336 }
1337 }
1338 }
1339
1340 closedir(dir);
1341
1342 if (!res && errno) {
1343 ast_log(LOG_ERROR, "Error while reading directories - %s: %s\n",
1344 path, strerror(errno));
1345 res = -1;
1346 }
1347
1348 return res;
1349}
1350
1351#if !defined(__GLIBC__)
1352/*!
1353 * \brief Lock to hold when iterating over directories.
1354 *
1355 * Currently, 'readdir' is not required to be thread-safe. In most modern implementations
1356 * it should be safe to make concurrent calls into 'readdir' that specify different directory
1357 * streams (glibc would be one of these). However, since it is potentially unsafe for some
1358 * implementations we'll use our own locking in order to achieve synchronization for those.
1359 */
1361#endif
1362
1363int ast_file_read_dirs(const char *dir_name, ast_file_on_file on_file, void *obj, int max_depth)
1364{
1365 int res;
1366
1367 errno = 0;
1368
1369#if !defined(__GLIBC__)
1371#endif
1372
1373 res = __ast_file_read_dirs(dir_name, on_file, obj, max_depth);
1374
1375#if !defined(__GLIBC__)
1377#endif
1378
1379 return res;
1380}
1381
1382int ast_streamfile(struct ast_channel *chan, const char *filename,
1383 const char *preflang)
1384{
1385 struct ast_json * cel_event = NULL;
1386 struct ast_filestream *fs = NULL;
1387 struct ast_filestream *vfs = NULL;
1388 off_t pos;
1389 int seekattempt;
1390 int res;
1391 char custom_filename[256];
1392 char *tmp_filename;
1393
1394 /* If file with the same name exists in /var/lib/asterisk/sounds/custom directory, use that file.
1395 * Otherwise, use the original file*/
1396
1398 memset(custom_filename, 0, sizeof(custom_filename));
1399 snprintf(custom_filename, sizeof(custom_filename), "custom/%s", filename);
1400 fs = openstream_internal(chan, custom_filename, preflang, 0, 1); /* open stream, do not warn for missing files */
1401 if (fs) {
1402 tmp_filename = custom_filename;
1403 ast_debug(3, "Found file %s in custom directory\n", filename);
1404 }
1405 }
1406
1407 if (!fs) {
1408 fs = ast_openstream(chan, filename, preflang);
1409 if (!fs) {
1410 struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
1411 ast_channel_lock(chan);
1412 ast_log(LOG_WARNING, "Unable to open %s (format %s)\n",
1413 filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf));
1414 ast_channel_unlock(chan);
1415 return -1;
1416 }
1417 tmp_filename = (char *)filename;
1418 }
1419
1420 /* check to see if there is any data present (not a zero length file),
1421 * done this way because there is no where for ast_openstream_full to
1422 * return the file had no data. */
1423 pos = ftello(fs->f);
1424 seekattempt = fseeko(fs->f, -1, SEEK_END);
1425 if (seekattempt) {
1426 if (errno == EINVAL) {
1427 /* Zero-length file, as opposed to a pipe */
1428 return 0;
1429 } else {
1430 ast_seekstream(fs, 0, SEEK_SET);
1431 }
1432 } else {
1433 fseeko(fs->f, pos, SEEK_SET);
1434 }
1435
1436 vfs = ast_openvstream(chan, tmp_filename, preflang);
1437 if (vfs) {
1438 ast_debug(1, "Ooh, found a video stream, too, format %s\n", ast_format_get_name(vfs->fmt->format));
1439 }
1440
1443 if (ast_applystream(chan, fs))
1444 return -1;
1445 if (vfs && ast_applystream(chan, vfs))
1446 return -1;
1447 ast_test_suite_event_notify("PLAYBACK", "Message: %s\r\nChannel: %s", tmp_filename, ast_channel_name(chan));
1448 res = ast_playstream(fs);
1449 if (!res && vfs)
1450 res = ast_playstream(vfs);
1451
1452 cel_event = ast_json_pack("{ s: s, s: {s: s, s: s, s: s}}",
1453 "event", "FILE_STREAM_BEGIN",
1454 "extra",
1455 "sound", tmp_filename,
1457 "language", preflang ? preflang : "default"
1458 );
1459 if (cel_event) {
1461 } else {
1462 ast_log(LOG_WARNING, "Unable to build extradata for sound file STREAM_BEGIN event on channel %s", ast_channel_name(chan));
1463 }
1464 ast_json_unref(cel_event);
1465
1466 if (VERBOSITY_ATLEAST(3)) {
1467 ast_channel_lock(chan);
1468 ast_verb(3, "<%s> Playing '%s' (format '%s', language '%s')\n", ast_channel_name(chan), tmp_filename, S_OR(fs->open_extension, "unknown"), preflang ? preflang : "default");
1469 ast_channel_unlock(chan);
1470 }
1471
1472 return res;
1473}
1474
1475struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
1476{
1477 FILE *bfile;
1478 struct ast_format_def *f;
1479 struct ast_filestream *fs = NULL;
1480 char *fn;
1481 int format_found = 0;
1482
1484
1485 AST_RWLIST_TRAVERSE(&formats, f, list) {
1486 fs = NULL;
1487 if (!exts_compare(f->exts, type))
1488 continue;
1489 else
1490 format_found = 1;
1491
1493 if (!fn) {
1494 continue;
1495 }
1496 errno = 0;
1497 bfile = fopen(fn, "r");
1498
1499 if (!bfile || (fs = get_filestream(f, bfile)) == NULL || open_wrapper(fs) ) {
1500 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
1501 if (fs) {
1502 ast_closestream(fs);
1503 }
1504 fs = NULL;
1505 bfile = NULL;
1506 ast_free(fn);
1507 break;
1508 }
1509 /* found it */
1510 fs->trans = NULL;
1511 fs->fmt = f;
1512 fs->flags = flags;
1513 fs->mode = mode;
1515 fs->vfs = NULL;
1516 ast_free(fn);
1517 break;
1518 }
1519
1521 if (!format_found)
1522 ast_log(LOG_WARNING, "No such format '%s'\n", type);
1523
1524 return fs;
1525}
1526
1527struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
1528{
1529 int fd, myflags = 0;
1530 /* compiler claims this variable can be used before initialization... */
1531 FILE *bfile = NULL;
1532 struct ast_format_def *f;
1533 struct ast_filestream *fs = NULL;
1534 char *buf = NULL;
1535 size_t size = 0;
1536 int format_found = 0;
1537
1539
1540 /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
1541 /* We really can't use O_APPEND as it will break WAV header updates */
1542 if (flags & O_APPEND) {
1543 flags &= ~O_APPEND;
1544 } else {
1545 myflags = O_TRUNC;
1546 }
1547
1548 myflags |= O_WRONLY | O_CREAT;
1549
1550 /* XXX need to fix this - we should just do the fopen,
1551 * not open followed by fdopen()
1552 */
1553 AST_RWLIST_TRAVERSE(&formats, f, list) {
1554 char *fn, *orig_fn = NULL;
1555 if (fs)
1556 break;
1557
1558 if (!exts_compare(f->exts, type))
1559 continue;
1560 else
1561 format_found = 1;
1562
1564 if (!fn) {
1565 continue;
1566 }
1567 fd = open(fn, flags | myflags, mode);
1568 if (fd > -1) {
1569 /* fdopen() the resulting file stream */
1570 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
1571 if (!bfile) {
1572 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
1573 close(fd);
1574 fd = -1;
1575 }
1576 }
1577
1578 if (ast_opt_cache_record_files && (fd > -1)) {
1579 char *c;
1580
1581 fclose(bfile); /* this also closes fd */
1582 /*
1583 We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
1584 What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
1585 */
1586 orig_fn = ast_strdup(fn);
1587 for (c = fn; *c; c++)
1588 if (*c == '/')
1589 *c = '_';
1590
1591 size = strlen(fn) + strlen(record_cache_dir) + 2;
1592 buf = ast_malloc(size);
1593 strcpy(buf, record_cache_dir);
1594 strcat(buf, "/");
1595 strcat(buf, fn);
1596 ast_free(fn);
1597 fn = buf;
1598 fd = open(fn, flags | myflags, mode);
1599 if (fd > -1) {
1600 /* fdopen() the resulting file stream */
1601 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
1602 if (!bfile) {
1603 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
1604 close(fd);
1605 fd = -1;
1606 }
1607 }
1608 }
1609 if (fd > -1) {
1610 errno = 0;
1611 fs = get_filestream(f, bfile);
1612 if (fs) {
1613 if ((fs->write_buffer = ast_malloc(32768))) {
1614 setvbuf(fs->f, fs->write_buffer, _IOFBF, 32768);
1615 }
1616 }
1617 if (!fs || rewrite_wrapper(fs, comment)) {
1618 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
1619 close(fd);
1620 if (orig_fn) {
1621 unlink(fn);
1622 unlink(orig_fn);
1623 ast_free(orig_fn);
1624 }
1625 if (fs) {
1626 ast_closestream(fs);
1627 fs = NULL;
1628 }
1629 /*
1630 * 'fn' was has either been allocated from build_filename, or that was freed
1631 * and now 'fn' points to memory allocated for 'buf'. Either way the memory
1632 * now needs to be released.
1633 */
1634 ast_free(fn);
1635 continue;
1636 }
1637 fs->trans = NULL;
1638 fs->fmt = f;
1639 fs->flags = flags;
1640 fs->mode = mode;
1641 if (orig_fn) {
1642 fs->realfilename = orig_fn;
1643 fs->filename = fn;
1644 /*
1645 * The above now manages the memory allocated for 'orig_fn' and 'fn', so
1646 * set them to NULL, so they don't get released at the end of the loop.
1647 */
1648 orig_fn = NULL;
1649 fn = NULL;
1650 } else {
1651 fs->realfilename = NULL;
1653 }
1654 fs->vfs = NULL;
1655 /* If truncated, we'll be at the beginning; if not truncated, then append */
1656 f->seek(fs, 0, SEEK_END);
1657 } else if (errno != EEXIST) {
1658 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
1659 if (orig_fn)
1660 unlink(orig_fn);
1661 }
1662 /* Free 'fn', or if 'fn' points to 'buf' then free 'buf' */
1663 ast_free(fn);
1664 ast_free(orig_fn);
1665 }
1666
1668
1669 if (!format_found)
1670 ast_log(LOG_WARNING, "No such format '%s'\n", type);
1671
1672 return fs;
1673}
1674
1678 int skip_ms)
1679{
1680 switch (type)
1681 {
1683 {
1684 int eoftest;
1686 eoftest = fgetc(ast_channel_stream(c)->f);
1687 if (feof(ast_channel_stream(c)->f)) {
1689 } else {
1690 ungetc(eoftest, ast_channel_stream(c)->f);
1691 }
1692 }
1693 break;
1696 break;
1697 default:
1698 break;
1699 }
1700
1701 if (cb) {
1703 cb(c, ms_len, type);
1704 }
1705
1706 ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1707 "Control: %s\r\n"
1708 "SkipMs: %d\r\n",
1710 (type == AST_WAITSTREAM_CB_FASTFORWARD) ? "FastForward" : "Rewind",
1711 skip_ms);
1712}
1713
1714/*!
1715 * \brief the core of all waitstream() functions
1716 */
1717static int waitstream_core(struct ast_channel *c,
1718 const char *breakon,
1719 const char *forward,
1720 const char *reverse,
1721 int skip_ms,
1722 int audiofd,
1723 int cmdfd,
1724 const char *context,
1726{
1727 const char *orig_chan_name = NULL;
1728
1729 int err = 0;
1730
1731 if (!breakon)
1732 breakon = "";
1733 if (!forward)
1734 forward = "";
1735 if (!reverse)
1736 reverse = "";
1737
1738 /* Switch the channel to end DTMF frame only. waitstream_core doesn't care about the start of DTMF. */
1740
1743
1744 if (ast_channel_stream(c) && cb) {
1746 cb(c, ms_len, AST_WAITSTREAM_CB_START);
1747 }
1748
1749 while (ast_channel_stream(c)) {
1750 int res;
1751 int ms;
1752
1753 if (orig_chan_name && strcasecmp(orig_chan_name, ast_channel_name(c))) {
1755 err = 1;
1756 break;
1757 }
1758
1760
1761 if (ms < 0 && !ast_channel_timingfunc(c)) {
1763 break;
1764 }
1765 if (ms < 0)
1766 ms = 1000;
1767 if (cmdfd < 0) {
1768 res = ast_waitfor(c, ms);
1769 if (res < 0) {
1770 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1772 return res;
1773 }
1774 } else {
1775 int outfd;
1776 struct ast_channel *rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1777 if (!rchan && (outfd < 0) && (ms)) {
1778 /* Continue */
1779 if (errno == EINTR)
1780 continue;
1781 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1783 return -1;
1784 } else if (outfd > -1) { /* this requires cmdfd set */
1785 /* The FD we were watching has something waiting */
1787 return 1;
1788 }
1789 /* if rchan is set, it is 'c' */
1790 res = rchan ? 1 : 0; /* map into 'res' values */
1791 }
1792 if (res > 0) {
1793 struct ast_frame *fr = ast_read(c);
1794 if (!fr) {
1796 return -1;
1797 }
1798 switch (fr->frametype) {
1799 case AST_FRAME_DTMF_END:
1800 if (context) {
1801 const char exten[2] = { fr->subclass.integer, '\0' };
1802 if (ast_exists_extension(c, context, exten, 1,
1803 S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, NULL))) {
1804 res = fr->subclass.integer;
1805 ast_frfree(fr);
1807 return res;
1808 }
1809 } else {
1810 res = fr->subclass.integer;
1811 if (strchr(forward, res)) {
1813 } else if (strchr(reverse, res)) {
1815 } else if (strchr(breakon, res)) {
1816 ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1817 "Control: %s\r\n",
1819 "Break");
1820
1821 ast_frfree(fr);
1823 return res;
1824 }
1825 }
1826 break;
1827 case AST_FRAME_CONTROL:
1828 switch (fr->subclass.integer) {
1832 /* Fall-through and break out */
1833 ast_test_suite_event_notify("PLAYBACK","Channel: %s\r\n"
1834 "Control: %s\r\n",
1836 "Break");
1837 res = fr->subclass.integer;
1838 ast_frfree(fr);
1840 return res;
1842 if (!skip_ms) {
1843 skip_ms = 3000;
1844 }
1846 break;
1848 if (!skip_ms) {
1849 skip_ms = 3000;
1850 }
1852 break;
1853 case AST_CONTROL_HANGUP:
1854 case AST_CONTROL_BUSY:
1856 ast_frfree(fr);
1858 return -1;
1861 case AST_CONTROL_ANSWER:
1865 case AST_CONTROL_HOLD:
1866 case AST_CONTROL_UNHOLD:
1869 case AST_CONTROL_AOC:
1872 case AST_CONTROL_FLASH:
1873 case AST_CONTROL_WINK:
1874 case -1:
1875 /* Unimportant */
1876 break;
1877 default:
1878 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass.integer);
1879 }
1880 break;
1881 case AST_FRAME_VOICE:
1882 /* Write audio if appropriate */
1883 if (audiofd > -1) {
1884 if (write(audiofd, fr->data.ptr, fr->datalen) < 0) {
1885 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
1886 }
1887 }
1888 default:
1889 /* Ignore all others */
1890 break;
1891 }
1892 ast_frfree(fr);
1893 }
1895 }
1896
1898
1899 return (err || ast_channel_softhangup_internal_flag(c)) ? -1 : 0;
1900}
1901
1903 const char *breakon,
1904 const char *forward,
1905 const char *reverse,
1906 int ms,
1908{
1909 return waitstream_core(c, breakon, forward, reverse, ms,
1910 -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */, cb);
1911}
1912
1913int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int ms)
1914{
1915 return waitstream_core(c, breakon, forward, reverse, ms,
1916 -1 /* no audiofd */, -1 /* no cmdfd */, NULL /* no context */, NULL /* no callback */);
1917}
1918
1919/*! \internal
1920 * \brief Clean up the return value of a waitstream call
1921 *
1922 * It's possible for a control frame to come in from an external source and break the
1923 * playback. From a consumer of most ast_waitstream_* function callers, this should
1924 * appear like normal playback termination, i.e., return 0 and not the value of the
1925 * control frame.
1926 */
1927static int sanitize_waitstream_return(int return_value)
1928{
1929 switch (return_value) {
1933 /* Fall through and set return_value to 0 */
1934 return_value = 0;
1935 break;
1936 default:
1937 /* Do nothing */
1938 break;
1939 }
1940
1941 return return_value;
1942}
1943
1944int ast_waitstream(struct ast_channel *c, const char *breakon)
1945{
1946 int res;
1947
1948 res = waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL, NULL /* no callback */);
1949
1950 return sanitize_waitstream_return(res);
1951}
1952
1953int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1954{
1955 int res;
1956
1957 res = waitstream_core(c, breakon, NULL, NULL, 0,
1958 audiofd, cmdfd, NULL /* no context */, NULL /* no callback */);
1959
1960 return sanitize_waitstream_return(res);
1961}
1962
1963int ast_waitstream_exten(struct ast_channel *c, const char *context)
1964{
1965 int res;
1966
1967 /* Waitstream, with return in the case of a valid 1 digit extension */
1968 /* in the current or specified context being pressed */
1969 if (!context)
1970 context = ast_channel_context(c);
1971 res = waitstream_core(c, NULL, NULL, NULL, 0,
1972 -1, -1, context, NULL /* no callback */);
1973
1974 return sanitize_waitstream_return(res);
1975}
1976
1977/*
1978 * if the file name is non-empty, try to play it.
1979 * Return 0 if success, -1 if error, digit if interrupted by a digit.
1980 * If digits == "" then we can simply check for non-zero.
1981 */
1982int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
1983{
1984 int res = 0;
1985 if (!ast_strlen_zero(file)) {
1986 res = ast_streamfile(chan, file, ast_channel_language(chan));
1987 if (!res) {
1988 res = ast_waitstream(chan, digits);
1989 }
1990 }
1991 if (res == -1) {
1992 ast_stopstream(chan);
1993 }
1994
1995 return res;
1996}
1997
1998char *ast_format_str_reduce(char *fmts)
1999{
2000 struct ast_format_def *f;
2001 struct ast_format_def *fmts_ptr[AST_MAX_FORMATS];
2002 char *fmts_str[AST_MAX_FORMATS];
2003 char *stringp, *type;
2004 char *orig = fmts;
2005 int i, j, x, first, found = 0;
2006 int len = strlen(fmts) + 1;
2007 int res;
2008
2009 if (AST_RWLIST_RDLOCK(&formats)) {
2010 ast_log(LOG_WARNING, "Unable to lock format list\n");
2011 return NULL;
2012 }
2013
2014 stringp = ast_strdupa(fmts);
2015
2016 for (x = 0; (type = strsep(&stringp, "|")) && x < AST_MAX_FORMATS; x++) {
2018 if (exts_compare(f->exts, type)) {
2019 found = 1;
2020 break;
2021 }
2022 }
2023
2024 fmts_str[x] = type;
2025 if (found) {
2026 fmts_ptr[x] = f;
2027 } else {
2028 fmts_ptr[x] = NULL;
2029 }
2030 }
2032
2033 first = 1;
2034 for (i = 0; i < x; i++) {
2035 /* ignore invalid entries */
2036 if (!fmts_ptr[i]) {
2037 ast_log(LOG_WARNING, "ignoring unknown format '%s'\n", fmts_str[i]);
2038 continue;
2039 }
2040
2041 /* special handling for the first entry */
2042 if (first) {
2043 res = snprintf(fmts, len, "%s", fmts_str[i]);
2044 fmts += res;
2045 len -= res;
2046 first = 0;
2047 continue;
2048 }
2049
2050 found = 0;
2051 for (j = 0; j < i; j++) {
2052 /* this is a duplicate */
2053 if (fmts_ptr[j] == fmts_ptr[i]) {
2054 found = 1;
2055 break;
2056 }
2057 }
2058
2059 if (!found) {
2060 res = snprintf(fmts, len, "|%s", fmts_str[i]);
2061 fmts += res;
2062 len -= res;
2063 }
2064 }
2065
2066 if (first) {
2067 ast_log(LOG_WARNING, "no known formats found in format list (%s)\n", orig);
2068 return NULL;
2069 }
2070
2071 return orig;
2072}
2073
2074static char *handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2075{
2076#define FORMAT "%-10s %-10s %-20s\n"
2077#define FORMAT2 "%-10s %-10s %-20s\n"
2078 struct ast_format_def *f;
2079 int count_fmt = 0;
2080
2081 switch (cmd) {
2082 case CLI_INIT:
2083 e->command = "core show file formats";
2084 e->usage =
2085 "Usage: core show file formats\n"
2086 " Displays currently registered file formats (if any).\n";
2087 return NULL;
2088 case CLI_GENERATE:
2089 return NULL;
2090 }
2091
2092 if (a->argc != 4)
2093 return CLI_SHOWUSAGE;
2094
2095 ast_cli(a->fd, FORMAT, "Format", "Name", "Extensions");
2096 ast_cli(a->fd, FORMAT, "------", "----", "----------");
2097
2100 ast_cli(a->fd, FORMAT2, ast_format_get_name(f->format), f->name, f->exts);
2101 count_fmt++;
2102 }
2104 ast_cli(a->fd, "%d file formats registered.\n", count_fmt);
2105 return CLI_SUCCESS;
2106#undef FORMAT
2107#undef FORMAT2
2108}
2109
2110struct ast_format *ast_get_format_for_file_ext(const char *file_ext)
2111{
2112 struct ast_format_def *f;
2115 if (exts_compare(f->exts, file_ext)) {
2116 return f->format;
2117 }
2118 }
2119
2120 return NULL;
2121}
2122
2123int ast_get_extension_for_mime_type(const char *mime_type, char *buffer, size_t capacity)
2124{
2125 struct ast_format_def *f;
2127
2128 ast_assert(buffer && capacity);
2129
2131 if (type_in_list(f->mime_types, mime_type, strcasecmp)) {
2132 size_t item_len = strcspn(f->exts, "|");
2133 size_t bytes_written = snprintf(buffer, capacity, ".%.*s", (int) item_len, f->exts);
2134 if (bytes_written < capacity) {
2135 /* Only return success if we didn't truncate */
2136 return 1;
2137 }
2138 }
2139 }
2140
2141 return 0;
2142}
2143
2144static struct ast_cli_entry cli_file[] = {
2145 AST_CLI_DEFINE(handle_cli_core_show_file_formats, "Displays file formats")
2146};
2147
2154
Prototypes for public functions only of internal interest,.
#define comment
Definition ael_lex.c:965
static int quiet
Definition ael_main.c:123
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
jack_status_t status
Definition app_jack.c:149
struct sla_ringing_trunk * first
Definition app_sla.c:338
ast_mutex_t lock
Definition app_sla.c:337
char * strsep(char **str, const char *delims)
float roundf(float x)
Asterisk main include file. File version handling, generic pbx functions.
#define DEFAULT_LANGUAGE
Definition asterisk.h:46
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define AST_FILE_MODE
Definition asterisk.h:32
#define DEFAULT_SAMPLES_PER_MS
Definition asterisk.h:49
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
#define ast_log
Definition astobj2.c:42
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
Definition astobj2.h:501
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
Call Event Logging API.
void ast_cel_publish_event(struct ast_channel *chan, enum ast_cel_event_type event_type, struct ast_json *blob)
Publish a CEL event.
Definition cel.c:1762
@ AST_CEL_STREAM_BEGIN
A stream started.
Definition cel.h:82
@ AST_CEL_STREAM_END
A stream ended.
Definition cel.h:84
static const char type[]
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
Definition channel.c:2992
void ast_channel_clear_flag(struct ast_channel *chan, unsigned int flag)
Clear a flag on a channel.
Definition channel.c:11214
void ast_channel_set_oldwriteformat(struct ast_channel *chan, struct ast_format *format)
#define ast_channel_lock(chan)
Definition channel.h:2983
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
@ AST_FLAG_MASQ_NOSTREAM
Definition channel.h:1034
@ AST_FLAG_END_DTMF_ONLY
Definition channel.h:1027
void ast_channel_vstreamid_set(struct ast_channel *chan, int value)
struct ast_format * ast_channel_oldwriteformat(struct ast_channel *chan)
int ast_waitfor(struct ast_channel *chan, int ms)
Wait for input on a channel.
Definition channel.c:3166
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
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:3189
void ast_channel_streamid_set(struct ast_channel *chan, int value)
const char * ast_channel_context(const struct ast_channel *chan)
void ast_deactivate_generator(struct ast_channel *chan)
Definition channel.c:2892
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:5167
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4278
int ast_channel_timingfd(const struct ast_channel *chan)
void ast_channel_set_flag(struct ast_channel *chan, unsigned int flag)
Set a flag on a channel.
Definition channel.c:11207
int ast_channel_vstreamid(const struct ast_channel *chan)
ast_timing_func_t ast_channel_timingfunc(const struct ast_channel *chan)
struct ast_filestream * ast_channel_vstream(const struct ast_channel *chan)
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
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:3184
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition channel.c:5826
struct ast_generator * ast_channel_generator(const struct ast_channel *chan)
const char * ast_channel_language(const struct ast_channel *chan)
int ast_channel_streamid(const struct ast_channel *chan)
struct ast_sched_context * ast_channel_sched(const struct ast_channel *chan)
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition channel.h:2984
void ast_channel_vstream_set(struct ast_channel *chan, struct ast_filestream *value)
int ast_set_write_format_from_cap(struct ast_channel *chan, struct ast_format_cap *formats)
Sets write format on channel chan Set write format for channel to whichever component of "format" is ...
Definition channel.c:5844
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition cli.h:45
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
ast_media_type
Types of media.
Definition codec.h:30
@ AST_MEDIA_TYPE_AUDIO
Definition codec.h:32
@ AST_MEDIA_TYPE_VIDEO
Definition codec.h:33
#define SENTINEL
Definition compiler.h:87
char * end
Definition eagi_proxy.c:73
char buf[BUFSIZE]
Definition eagi_proxy.c:66
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition file.c:1174
fsread_res
Definition file.c:1032
@ FSREAD_FAILURE
Definition file.c:1033
@ FSREAD_SUCCESS_SCHED
Definition file.c:1034
@ FSREAD_SUCCESS_NOSCHED
Definition file.c:1035
static char * build_filename_template(const char *filename, char **extension_start)
Definition file.c:377
static int filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
Definition file.c:618
int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
Definition file.c:1953
int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
Streams a file.
Definition file.c:1382
int ast_file_fdtemp(const char *path, char **filename, const char *template_name)
Create a temporary file located at path.
Definition file.c:213
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:926
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:931
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition file.c:1025
int ast_stopstream(struct ast_channel *tmp)
Stops a stream.
Definition file.c:233
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
Writes a frame to a stream.
Definition file.c:265
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition file.c:1164
static int ast_fsread_video(const void *data)
Definition file.c:1133
wrap_fn
Definition file.c:570
@ WRAP_OPEN
Definition file.c:570
@ WRAP_REWRITE
Definition file.c:570
int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int ms)
Same as waitstream but allows stream to be forwarded or rewound.
Definition file.c:1913
static char * handle_cli_core_show_file_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition file.c:2074
int ast_format_def_unregister(const char *name)
Unregisters a file format.
Definition file.c:173
static void file_shutdown(void)
Definition file.c:2148
int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
Rewind stream ms.
Definition file.c:1189
static int sanitize_waitstream_return(int return_value)
Definition file.c:1927
static unsigned maximum_extension_length
Space required to store the longest extension from all registered file formats.
Definition file.c:122
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
Applies a open stream to a channel.
Definition file.c:1146
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:1363
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:1475
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:937
static struct ast_json * json_array_from_list(const char *list, const char *sep)
Definition file.c:63
FILE * ast_file_mkftemp(char *template_name, mode_t mode)
same as mkstemp, but return a FILE
Definition file.c:198
static void filestream_destructor(void *arg)
Definition file.c:486
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:2110
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:422
static void waitstream_control(struct ast_channel *c, enum ast_waitstream_fr_cb_values type, ast_waitstream_fr_cb cb, int skip_ms)
Definition file.c:1675
static int type_in_list(const char *list, const char *type, int(*cmp)(const char *s1, const char *s2))
Definition file.c:441
int ast_filerename(const char *filename, const char *filename2, const char *fmt)
Renames a file.
Definition file.c:1235
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:1527
static void filestream_close(struct ast_filestream *f)
Definition file.c:460
file_action
Definition file.c:599
@ ACTION_OPEN
Definition file.c:603
@ ACTION_EXISTS
Definition file.c:600
@ ACTION_COPY
Definition file.c:604
@ ACTION_DELETE
Definition file.c:601
@ ACTION_RENAME
Definition file.c:602
static struct ast_filestream * openstream_internal(struct ast_channel *chan, const char *filename, const char *preflang, int asis, int quiet)
Definition file.c:871
static int copy(const char *infile, const char *outfile)
Definition file.c:327
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:1982
static int is_remote_path(const char *filename)
Definition file.c:761
static int ast_fsread_audio(const void *data)
Definition file.c:1088
static ast_mutex_t read_dirs_lock
Lock to hold when iterating over directories.
Definition file.c:1360
static int __ast_file_read_dirs(const char *path, ast_file_on_file on_file, void *obj, int max_depth)
Definition file.c:1245
char * ast_format_str_reduce(char *fmts)
Definition file.c:1998
int ast_truncstream(struct ast_filestream *fs)
Trunc stream at current location.
Definition file.c:1169
static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
Definition file.c:1040
static int is_absolute_path(const char *filename)
Definition file.c:756
int ast_ratestream(struct ast_filestream *fs)
Return the sample rate of the stream's format.
Definition file.c:1179
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition file.c:1200
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, ast_waitstream_fr_cb cb)
the core of all waitstream() functions
Definition file.c:1717
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition file.c:1218
static struct ast_cli_entry cli_file[]
Definition file.c:2144
static int open_wrapper(struct ast_filestream *s)
Definition file.c:594
int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
Fast forward stream ms.
Definition file.c:1184
static const char * translate_extension(const char *extension)
Definition file.c:407
static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
Definition file.c:572
#define FORMAT
static int fileexists_core(const char *filename, const char *fmt, const char *preflang, char *buf, int buflen, struct ast_format_cap *result_cap)
helper routine to locate a file with a given format and language preference.
Definition file.c:822
static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
Definition file.c:589
static struct ast_filestream * get_filestream(struct ast_format_def *fmt, FILE *bfile)
Definition file.c:532
static int fileexists_test(const char *filename, const char *fmt, const char *lang, char *buf, int buflen, struct ast_format_cap *result_cap)
test if a file exists for a given format.
Definition file.c:772
int ast_get_extension_for_mime_type(const char *mime_type, char *buffer, size_t capacity)
Get a suitable filename extension for the given MIME type.
Definition file.c:2123
#define FORMAT2
int ast_waitstream_fr_w_cb(struct ast_channel *c, const char *breakon, const char *forward, const char *reverse, int ms, ast_waitstream_fr_cb cb)
Same as waitstream_fr but allows a callback to be alerted when a user fastforwards or rewinds the fil...
Definition file.c:1902
int ast_playstream(struct ast_filestream *s)
Play a open stream on a channel.
Definition file.c:1152
#define exts_compare(list, type)
Definition file.c:454
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
Definition file.c:1230
static struct ast_frame * read_frame(struct ast_filestream *s, int *whennext)
Definition file.c:1000
static int publish_format_update(const struct ast_format_def *f, struct stasis_message_type *type)
Definition file.c:82
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:1963
int ast_file_init(void)
Definition file.c:2155
int __ast_format_def_register(const struct ast_format_def *f, struct ast_module *mod)
Register a new file format capability. Adds a format to Asterisk's format abilities.
Definition file.c:124
static enum fsread_res ast_readvideo_callback(struct ast_filestream *s)
Definition file.c:1103
int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
Copies a file.
Definition file.c:1240
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition file.c:1944
ast_waitstream_fr_cb_values
Definition file.h:54
@ AST_WAITSTREAM_CB_FASTFORWARD
Definition file.h:56
@ AST_WAITSTREAM_CB_REWIND
Definition file.h:55
@ AST_WAITSTREAM_CB_START
Definition file.h:57
void() ast_waitstream_fr_cb(struct ast_channel *chan, long ms, enum ast_waitstream_fr_cb_values val)
callback used during dtmf controlled file playback to indicate location of playback in a file after r...
Definition file.h:65
int(* ast_file_on_file)(const char *dir_name, const char *filename, void *obj)
Callback called for each file found when reading directories.
Definition file.h:180
#define AST_MAX_FORMATS
Definition file.h:44
enum ast_media_type ast_format_get_type(const struct ast_format *format)
Get the media type of a format.
Definition format.c:354
struct stasis_message_type * ast_format_unregister_type(void)
Get the message type used for signaling a format unregistration.
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition format.c:379
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition format.c:201
@ AST_FORMAT_CMP_EQUAL
Definition format.h:36
@ AST_FORMAT_CMP_NOT_EQUAL
Definition format.h:38
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition format.c:334
struct stasis_message_type * ast_format_register_type(void)
Get the message type used for signaling a format registration.
#define AST_FORMAT_CAP_NAMES_LEN
Definition format_cap.h:324
struct ast_format * ast_format_cap_get_format(const struct ast_format_cap *cap, int position)
Get the format at a specific index.
Definition format_cap.c:408
@ AST_FORMAT_CAP_FLAG_DEFAULT
Definition format_cap.h:38
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition format_cap.c:742
int ast_format_cap_has_type(const struct ast_format_cap *cap, enum ast_media_type type)
Find out if the capabilities structure has any formats of a specific type.
Definition format_cap.c:621
int ast_format_cap_iscompatible(const struct ast_format_cap *cap1, const struct ast_format_cap *cap2)
Determine if any joint capabilities exist between two capabilities structures.
Definition format_cap.c:661
#define ast_format_cap_append(cap, format, framing)
Add format capability to capabilities structure.
Definition format_cap.h:99
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition format_cap.h:49
size_t ast_format_cap_count(const struct ast_format_cap *cap)
Get the number of formats present within the capabilities structure.
Definition format_cap.c:403
static const char name[]
Definition format_mp3.c:68
static int array(struct ast_channel *chan, const char *cmd, char *var, const char *value)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const char * ext
Definition http.c:151
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
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 main/app.c:3208
#define ast_frisolate(fr)
Makes a frame independent of any static storage.
#define ast_frfree(fr)
@ AST_FRAME_DTMF_END
@ AST_FRAME_CONTROL
@ AST_CONTROL_SRCUPDATE
@ AST_CONTROL_PROGRESS
@ AST_CONTROL_STREAM_RESTART
@ AST_CONTROL_STREAM_SUSPEND
@ AST_CONTROL_UNHOLD
@ AST_CONTROL_VIDUPDATE
@ AST_CONTROL_STREAM_REVERSE
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HANGUP
@ AST_CONTROL_STREAM_STOP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_STREAM_FORWARD
@ AST_CONTROL_FLASH
@ AST_CONTROL_SRCCHANGE
@ AST_CONTROL_PVT_CAUSE_CODE
@ AST_CONTROL_UPDATE_RTP_PEER
#define AST_LOG_WARNING
#define ast_debug(level,...)
Log a DEBUG message.
#define VERBOSITY_ATLEAST(level)
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
Asterisk JSON abstraction layer.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition json.c:378
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition json.c:756
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition json.c:612
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition json.c:362
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition json.c:67
A set of macros to manage forward-linked lists.
#define AST_RWLIST_REMOVE_CURRENT
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition linkedlists.h:78
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_TRAVERSE
#define AST_RWLIST_INSERT_HEAD
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Asterisk locking-related definitions:
#define ast_mutex_unlock(a)
Definition lock.h:197
#define SCOPED_RDLOCK(varname, lock)
scoped lock specialization for read locks
Definition lock.h:601
#define ast_mutex_lock(a)
Definition lock.h:196
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition lock.h:527
int errno
An in-memory media cache.
int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, char *file_path, size_t len)
Retrieve an item from the cache.
Header for providers of file and format handling routines. Clients of these routines should include "...
Asterisk module definitions.
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition module.h:469
char record_cache_dir[AST_CACHE_DIR_LEN]
Definition options.c:97
#define ast_opt_cache_record_files
Definition options.h:130
#define ast_opt_sounds_search_custom
Definition options.h:148
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_DATA_DIR
Definition options.c:159
Core PBX routines and definitions.
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:2735
#define NULL
Definition resample.c:96
Scheduler Routines (derived from cheops)
#define AST_SCHED_DEL_ACCESSOR(sched, obj, getter, setter)
Definition sched.h:59
int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result
Adds a scheduled event.
Definition sched.c:567
int ast_sched_runq(struct ast_sched_context *con)
Runs the queue.
Definition sched.c:786
int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result
Determines number of seconds until the next outstanding event to take place.
Definition sched.c:433
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition stasis.h:1546
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition stasis.h:1524
#define STASIS_MESSAGE_TYPE_DEFN(name,...)
Boiler-plate messaging macro for defining public message types.
Definition stasis.h:1471
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition stasis.c:1589
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
#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:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_alloca(init_len)
Definition strings.h:848
Main Channel structure associated with a channel.
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition mod_format.h:101
struct ast_filestream * vfs
Definition mod_format.h:110
struct ast_frame fr
frame produced by read, typically
Definition mod_format.h:122
char * realfilename
Definition mod_format.h:108
char * write_buffer
Definition mod_format.h:126
struct ast_format_def * fmt
Definition mod_format.h:103
struct ast_channel * owner
Definition mod_format.h:116
struct ast_format * lastwriteformat
Definition mod_format.h:114
struct ast_trans_pvt * trans
Definition mod_format.h:112
char * open_extension
Definition mod_format.h:106
const char * orig_chan_name
Definition mod_format.h:125
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Each supported file format is described by the following structure.
Definition mod_format.h:43
int(* trunc)(struct ast_filestream *fs)
Definition mod_format.h:69
int(* seek)(struct ast_filestream *, off_t, int)
Definition mod_format.h:68
struct ast_frame *(* read)(struct ast_filestream *, int *whennext)
Definition mod_format.h:74
int(* write)(struct ast_filestream *, struct ast_frame *)
Definition mod_format.h:66
char name[80]
Definition mod_format.h:44
char mime_types[80]
Definition mod_format.h:47
off_t(* tell)(struct ast_filestream *fs)
Definition mod_format.h:70
struct ast_format * format
Definition mod_format.h:48
void(* close)(struct ast_filestream *)
Definition mod_format.h:77
struct ast_format_def::@252 list
char exts[80]
Definition mod_format.h:45
Definition of a media format.
Definition format.c:43
struct ast_format * format
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@237 data
Abstract JSON element (object, array, string, int, ...).
Support for dynamic strings.
Definition strings.h:623
structure to hold extensions
Definition file.c:58
ast_rwlock_t lock
Definition file.c:58
Number structure.
Test Framework API.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
static struct aco_type item
static struct test_val b
static struct test_val a
static struct test_val c
Support for translation of data formats. translate.c.
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:623
void ast_translator_free_path(struct ast_trans_pvt *tr)
Frees a translator path Frees the given translator path structure.
Definition translate.c:533
struct ast_trans_pvt * ast_translator_build_path(struct ast_format *dest, struct ast_format *source)
Builds a translator path Build a path (possibly NULL) from source to dest.
Definition translate.c:543
Utility functions.
#define ast_test_flag(p, flag)
Definition utils.h:64
#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:981
#define ast_assert(a)
Definition utils.h:779
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
Definition utils.c:2513
#define ARRAY_LEN(a)
Definition utils.h:706
#define MAX(a, b)
Definition utils.h:254