2 * Asterisk -- A telephony toolkit for Linux.
4 * Generic File Format Support.
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #include <sys/types.h>
22 #include <sys/types.h>
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29 #include "asterisk/frame.h"
30 #include "asterisk/file.h"
31 #include "asterisk/cli.h"
32 #include "asterisk/logger.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/sched.h"
35 #include "asterisk/options.h"
36 #include "asterisk/translate.h"
37 #include "asterisk/utils.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/app.h"
44 /* Extensions (separated by | if more than one)
45 this format can read. First is assumed for writing (e.g. .mp3) */
47 /* Format of frames it uses/provides (one only) */
49 /* Open an input stream, and start playback */
50 struct ast_filestream * (*open)(int fd);
51 /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
52 struct ast_filestream * (*rewrite)(int fd, const char *comment);
53 /* Write a frame to a channel */
54 int (*write)(struct ast_filestream *, struct ast_frame *);
55 /* seek num samples into file, whence(think normal seek) */
56 int (*seek)(struct ast_filestream *, long offset, int whence);
57 /* trunc file to current position */
58 int (*trunc)(struct ast_filestream *fs);
59 /* tell current position */
60 long (*tell)(struct ast_filestream *fs);
61 /* Read the next frame from the filestream (if available) and report when to get next one
63 struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
64 /* Close file, and destroy filestream structure */
65 void (*close)(struct ast_filestream *);
66 /* Retrieve file comment */
67 char * (*getcomment)(struct ast_filestream *);
69 struct ast_format *next;
72 struct ast_filestream {
73 /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
74 struct ast_format *fmt;
79 /* Video file stream */
80 struct ast_filestream *vfs;
81 /* Transparently translate from another format -- just once */
82 struct ast_trans_pvt *trans;
83 struct ast_tranlator_pvt *tr;
86 struct ast_channel *owner;
89 AST_MUTEX_DEFINE_STATIC(formatlock);
91 static struct ast_format *formats = NULL;
93 int ast_format_register(const char *name, const char *exts, int format,
94 struct ast_filestream * (*open)(int fd),
95 struct ast_filestream * (*rewrite)(int fd, const char *comment),
96 int (*write)(struct ast_filestream *, struct ast_frame *),
97 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
98 int (*trunc)(struct ast_filestream *),
99 long (*tell)(struct ast_filestream *),
100 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
101 void (*close)(struct ast_filestream *),
102 char * (*getcomment)(struct ast_filestream *))
104 struct ast_format *tmp;
105 if (ast_mutex_lock(&formatlock)) {
106 ast_log(LOG_WARNING, "Unable to lock format list\n");
111 if (!strcasecmp(name, tmp->name)) {
112 ast_mutex_unlock(&formatlock);
113 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
118 tmp = malloc(sizeof(struct ast_format));
120 ast_log(LOG_WARNING, "Out of memory\n");
121 ast_mutex_unlock(&formatlock);
124 ast_copy_string(tmp->name, name, sizeof(tmp->name));
125 ast_copy_string(tmp->exts, exts, sizeof(tmp->exts));
127 tmp->rewrite = rewrite;
134 tmp->format = format;
135 tmp->getcomment = getcomment;
138 ast_mutex_unlock(&formatlock);
139 if (option_verbose > 1)
140 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
144 int ast_format_unregister(const char *name)
146 struct ast_format *tmp, *tmpl = NULL;
147 if (ast_mutex_lock(&formatlock)) {
148 ast_log(LOG_WARNING, "Unable to lock format list\n");
153 if (!strcasecmp(name, tmp->name)) {
155 tmpl->next = tmp->next;
159 ast_mutex_unlock(&formatlock);
160 if (option_verbose > 1)
161 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
167 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
171 int ast_stopstream(struct ast_channel *tmp)
173 /* Stop a running stream if there is one */
175 ast_closestream(tmp->vstream);
177 ast_closestream(tmp->stream);
178 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
179 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
184 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
186 struct ast_frame *trf;
189 if (f->frametype == AST_FRAME_VIDEO) {
190 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
191 /* This is the audio portion. Call the video one... */
192 if (!fs->vfs && fs->filename) {
193 /* XXX Support other video formats XXX */
194 const char *type = "h263";
195 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
196 ast_log(LOG_DEBUG, "Opened video output file\n");
199 return ast_writestream(fs->vfs, f);
203 /* Might / might not have mark set */
206 } else if (f->frametype != AST_FRAME_VOICE) {
207 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
210 if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
211 res = fs->fmt->write(fs, f);
213 ast_log(LOG_WARNING, "Natural write failed\n");
215 ast_log(LOG_WARNING, "Huh??\n");
218 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
219 the one we've setup a translator for, we do the "wrong thing" XXX */
220 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
221 ast_translator_free_path(fs->trans);
225 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
227 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
229 fs->lastwriteformat = f->subclass;
231 /* Get the translated frame but don't consume the original in case they're using it on another stream */
232 trf = ast_translate(fs->trans, f, 0);
234 res = fs->fmt->write(fs, trf);
236 ast_log(LOG_WARNING, "Translated frame write failed\n");
244 static int copy(const char *infile, const char *outfile)
252 if ((ifd = open(infile, O_RDONLY)) < 0) {
253 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
256 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
257 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
262 len = read(ifd, buf, sizeof(buf));
264 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
270 res = write(ofd, buf, len);
272 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
284 static char *build_filename(const char *filename, const char *ext)
289 if (!strcmp(ext, "wav49")) {
290 ast_copy_string(type, "WAV", sizeof(type));
292 ast_copy_string(type, ext, sizeof(type));
295 if (filename[0] == '/') {
296 fnsize = strlen(filename) + strlen(type) + 2;
299 snprintf(fn, fnsize, "%s.%s", filename, type);
301 char tmp[AST_CONFIG_MAX_PATH] = "";
303 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds");
304 fnsize = strlen(tmp) + strlen(filename) + strlen(type) + 3;
307 snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, type);
313 static int exts_compare(const char *exts, const char *type)
315 char *stringp = NULL, *ext;
318 ast_copy_string(tmp, exts, sizeof(tmp));
320 while ((ext = strsep(&stringp, "|"))) {
321 if (!strcmp(ext, type)) {
329 #define ACTION_EXISTS 1
330 #define ACTION_DELETE 2
331 #define ACTION_RENAME 3
332 #define ACTION_OPEN 4
333 #define ACTION_COPY 5
335 static int ast_filehelper(const char *filename, const char *filename2, const char *fmt, int action)
338 struct ast_format *f;
339 struct ast_filestream *s;
341 char *ext=NULL, *exts, *fn, *nfn;
342 struct ast_channel *chan = (struct ast_channel *)filename2;
344 /* Start with negative response */
345 if (action == ACTION_EXISTS)
349 if (action == ACTION_OPEN)
351 /* Check for a specific format */
352 if (ast_mutex_lock(&formatlock)) {
353 ast_log(LOG_WARNING, "Unable to lock format list\n");
354 if (action == ACTION_EXISTS)
361 if (!fmt || exts_compare(f->exts, fmt)) {
363 exts = ast_strdupa(f->exts);
364 /* Try each kind of extension */
366 ext = strsep(&stringp, "|");
368 fn = build_filename(filename, ext);
379 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
382 nfn = build_filename(filename2, ext);
384 res = rename(fn, nfn);
386 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
389 ast_log(LOG_WARNING, "Out of memory\n");
392 nfn = build_filename(filename2, ext);
396 ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
399 ast_log(LOG_WARNING, "Out of memory\n");
402 if ((ret < 0) && ((chan->writeformat & f->format) ||
403 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
404 ret = open(fn, O_RDONLY);
412 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
418 ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
421 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
425 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
427 /* Conveniently this logic is the same for all */
433 ext = strsep(&stringp, "|");
439 ast_mutex_unlock(&formatlock);
440 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
441 res = ret ? ret : -1;
444 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
446 return ast_openstream_full(chan, filename, preflang, 0);
449 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
451 /* This is a fairly complex routine. Essentially we should do
454 1) Find which file handlers produce our type of format.
455 2) Look for a filename which it can handle.
456 3) If we find one, then great.
457 4) If not, see what files are there
458 5) See what we can actually support
459 6) Choose the one with the least costly translator path and
465 char filename2[256]="";
466 char filename3[256]="";
471 /* do this first, otherwise we detect the wrong writeformat */
472 ast_stopstream(chan);
474 ast_deactivate_generator(chan);
476 if (preflang && !ast_strlen_zero(preflang)) {
477 ast_copy_string(filename3, filename, sizeof(filename3));
478 endpart = strrchr(filename3, '/');
482 snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
484 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
485 fmts = ast_fileexists(filename2, NULL, NULL);
488 ast_copy_string(filename2, filename, sizeof(filename2));
489 fmts = ast_fileexists(filename2, NULL, NULL);
492 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
495 chan->oldwriteformat = chan->writeformat;
496 /* Set the channel to a format we can work with */
497 res = ast_set_write_format(chan, fmts);
499 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
505 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
507 /* This is a fairly complex routine. Essentially we should do
510 1) Find which file handlers produce our type of format.
511 2) Look for a filename which it can handle.
512 3) If we find one, then great.
513 4) If not, see what files are there
514 5) See what we can actually support
515 6) Choose the one with the least costly translator path and
522 char lang2[MAX_LANGUAGE];
523 /* XXX H.263 only XXX */
525 if (preflang && !ast_strlen_zero(preflang)) {
526 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
527 fmts = ast_fileexists(filename2, fmt, NULL);
529 ast_copy_string(lang2, preflang, sizeof(lang2));
530 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
531 fmts = ast_fileexists(filename2, fmt, NULL);
535 ast_copy_string(filename2, filename, sizeof(filename2));
536 fmts = ast_fileexists(filename2, fmt, NULL);
541 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
543 return chan->vstream;
544 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
548 struct ast_frame *ast_readframe(struct ast_filestream *s)
550 struct ast_frame *f = NULL;
553 f = s->fmt->read(s, &whennext);
557 static int ast_readaudio_callback(void *data)
559 struct ast_filestream *s = data;
560 struct ast_frame *fr;
564 fr = s->fmt->read(s, &whennext);
566 if (ast_write(s->owner, fr)) {
567 ast_log(LOG_WARNING, "Failed to write frame\n");
568 s->owner->streamid = -1;
569 #ifdef ZAPTEL_OPTIMIZATIONS
570 ast_settimeout(s->owner, 0, NULL, NULL);
575 /* Stream has finished */
576 s->owner->streamid = -1;
577 #ifdef ZAPTEL_OPTIMIZATIONS
578 ast_settimeout(s->owner, 0, NULL, NULL);
583 if (whennext != s->lasttimeout) {
584 #ifdef ZAPTEL_OPTIMIZATIONS
585 if (s->owner->timingfd > -1)
586 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
589 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
590 s->lasttimeout = whennext;
596 static int ast_readvideo_callback(void *data)
598 struct ast_filestream *s = data;
599 struct ast_frame *fr;
603 fr = s->fmt->read(s, &whennext);
605 if (ast_write(s->owner, fr)) {
606 ast_log(LOG_WARNING, "Failed to write frame\n");
607 s->owner->vstreamid = -1;
611 /* Stream has finished */
612 s->owner->vstreamid = -1;
616 if (whennext != s->lasttimeout) {
617 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
618 s->lasttimeout = whennext;
624 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
630 int ast_playstream(struct ast_filestream *s)
632 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
633 ast_readaudio_callback(s);
635 ast_readvideo_callback(s);
639 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
641 return fs->fmt->seek(fs, sample_offset, whence);
644 int ast_truncstream(struct ast_filestream *fs)
646 return fs->fmt->trunc(fs);
649 long ast_tellstream(struct ast_filestream *fs)
651 return fs->fmt->tell(fs);
654 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
656 /* I think this is right, 8000 samples per second, 1000 ms a second so 8
658 long samples = ms * 8;
659 return ast_seekstream(fs, samples, SEEK_CUR);
662 int ast_stream_rewind(struct ast_filestream *fs, long ms)
664 long samples = ms * 8;
665 samples = samples * -1;
666 return ast_seekstream(fs, samples, SEEK_CUR);
669 int ast_closestream(struct ast_filestream *f)
673 /* Stop a running stream if there is one */
675 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
676 f->owner->stream = NULL;
677 if (f->owner->streamid > -1)
678 ast_sched_del(f->owner->sched, f->owner->streamid);
679 f->owner->streamid = -1;
680 #ifdef ZAPTEL_OPTIMIZATIONS
681 ast_settimeout(f->owner, 0, NULL, NULL);
684 f->owner->vstream = NULL;
685 if (f->owner->vstreamid > -1)
686 ast_sched_del(f->owner->sched, f->owner->vstreamid);
687 f->owner->vstreamid = -1;
690 /* destroy the translator on exit */
692 ast_translator_free_path(f->trans);
696 if (f->realfilename && f->filename) {
697 size = strlen(f->filename) + strlen(f->realfilename) + 15;
700 snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
701 ast_safe_system(cmd);
708 if (f->realfilename) {
709 free(f->realfilename);
710 f->realfilename = NULL;
717 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
724 char lang2[MAX_LANGUAGE];
726 if (preflang && !ast_strlen_zero(preflang)) {
727 /* Insert the language between the last two parts of the path */
728 ast_copy_string(tmp, filename, sizeof(tmp));
729 c = strrchr(tmp, '/');
734 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
738 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, postfix);
740 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
743 ast_copy_string(lang2, preflang, sizeof(lang2));
745 strsep(&stringp, "_");
746 /* If language is a specific locality of a language (like es_MX), strip the locality and try again */
747 if (strcmp(lang2, preflang)) {
748 if (ast_strlen_zero(prefix)) {
749 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, postfix);
751 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
753 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
758 /* Fallback to no language (usually winds up being American English) */
760 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
765 int ast_filedelete(const char *filename, const char *fmt)
767 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
770 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
772 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
775 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
777 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
780 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
782 struct ast_filestream *fs;
783 struct ast_filestream *vfs;
785 fs = ast_openstream(chan, filename, preflang);
786 vfs = ast_openvstream(chan, filename, preflang);
788 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
790 if (ast_applystream(chan, fs))
792 if (vfs && ast_applystream(chan, vfs))
794 if (ast_playstream(fs))
796 if (vfs && ast_playstream(vfs))
799 if (option_verbose > 2)
800 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
804 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
808 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
811 struct ast_format *f;
812 struct ast_filestream *fs=NULL;
814 if (ast_mutex_lock(&formatlock)) {
815 ast_log(LOG_WARNING, "Unable to lock format list\n");
820 if (exts_compare(f->exts, type)) {
821 fn = build_filename(filename, type);
822 fd = open(fn, flags | myflags);
825 if ((fs = f->open(fd))) {
830 fs->filename = strdup(filename);
833 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
837 } else if (errno != EEXIST)
838 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
844 ast_mutex_unlock(&formatlock);
846 ast_log(LOG_WARNING, "No such format '%s'\n", type);
850 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
853 struct ast_format *f;
854 struct ast_filestream *fs=NULL;
855 char *fn,*orig_fn=NULL;
859 if (ast_mutex_lock(&formatlock)) {
860 ast_log(LOG_WARNING, "Unable to lock format list\n");
863 /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
864 if (flags & O_APPEND) {
865 /* We really can't use O_APPEND as it will break WAV header updates */
871 myflags |= O_WRONLY | O_CREAT;
875 if (exts_compare(f->exts, type)) {
876 fn = build_filename(filename, type);
877 fd = open(fn, flags | myflags, mode);
879 if (option_cache_record_files && fd >= 0) {
882 We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
883 What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
885 orig_fn = ast_strdupa(fn);
886 for (size=0;size<strlen(fn);size++) {
891 size += (strlen(record_cache_dir) + 10);
893 memset(buf, 0, size);
894 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
897 fd = open(fn, flags | myflags, mode);
901 if ((fs = f->rewrite(fd, comment))) {
906 if (option_cache_record_files) {
907 fs->realfilename = build_filename(filename, type);
908 fs->filename = strdup(fn);
910 fs->realfilename = NULL;
911 fs->filename = strdup(filename);
915 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
921 } else if (errno != EEXIST) {
922 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
926 if (!buf) /* if buf != NULL then fn is already free and pointing to it */
933 ast_mutex_unlock(&formatlock);
935 ast_log(LOG_WARNING, "No such format '%s'\n", type);
939 int ast_waitstream(struct ast_channel *c, const char *breakon)
941 /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
943 struct ast_frame *fr;
944 if (!breakon) breakon = "";
946 res = ast_sched_wait(c->sched);
947 if ((res < 0) && !c->timingfunc) {
953 res = ast_waitfor(c, res);
955 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
957 } else if (res > 0) {
961 ast_log(LOG_DEBUG, "Got hung up\n");
966 switch(fr->frametype) {
969 if (strchr(breakon, res)) {
974 case AST_FRAME_CONTROL:
975 switch(fr->subclass) {
976 case AST_CONTROL_HANGUP:
979 case AST_CONTROL_RINGING:
980 case AST_CONTROL_ANSWER:
984 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
990 ast_sched_runq(c->sched);
992 return (c->_softhangup ? -1 : 0);
995 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
998 struct ast_frame *fr;
1008 res = ast_sched_wait(c->sched);
1009 if ((res < 0) && !c->timingfunc) {
1015 res = ast_waitfor(c, res);
1017 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1024 ast_log(LOG_DEBUG, "Got hung up\n");
1029 switch(fr->frametype) {
1030 case AST_FRAME_DTMF:
1032 if (strchr(forward,res)) {
1033 ast_stream_fastforward(c->stream, ms);
1034 } else if (strchr(rewind,res)) {
1035 ast_stream_rewind(c->stream, ms);
1036 } else if (strchr(breakon, res)) {
1041 case AST_FRAME_CONTROL:
1042 switch(fr->subclass) {
1043 case AST_CONTROL_HANGUP:
1046 case AST_CONTROL_RINGING:
1047 case AST_CONTROL_ANSWER:
1051 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1057 ast_sched_runq(c->sched);
1061 return (c->_softhangup ? -1 : 0);
1064 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1069 struct ast_frame *fr;
1070 struct ast_channel *rchan;
1076 ms = ast_sched_wait(c->sched);
1077 if ((ms < 0) && !c->timingfunc) {
1083 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1084 if (!rchan && (outfd < 0) && (ms)) {
1088 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1090 } else if (outfd > -1) {
1091 /* The FD we were watching has something waiting */
1097 ast_log(LOG_DEBUG, "Got hung up\n");
1102 switch(fr->frametype) {
1103 case AST_FRAME_DTMF:
1105 if (strchr(breakon, res)) {
1110 case AST_FRAME_CONTROL:
1111 switch(fr->subclass) {
1112 case AST_CONTROL_HANGUP:
1115 case AST_CONTROL_RINGING:
1116 case AST_CONTROL_ANSWER:
1120 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1122 case AST_FRAME_VOICE:
1123 /* Write audio if appropriate */
1125 write(audiofd, fr->data, fr->datalen);
1130 ast_sched_runq(c->sched);
1132 return (c->_softhangup ? -1 : 0);
1135 static int show_file_formats(int fd, int argc, char *argv[])
1137 #define FORMAT "%-10s %-10s %-20s\n"
1138 #define FORMAT2 "%-10s %-10s %-20s\n"
1139 struct ast_format *f;
1141 return RESULT_SHOWUSAGE;
1142 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1144 if (ast_mutex_lock(&formatlock)) {
1145 ast_log(LOG_WARNING, "Unable to lock format list\n");
1151 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1154 ast_mutex_unlock(&formatlock);
1155 return RESULT_SUCCESS;
1158 struct ast_cli_entry show_file =
1160 { "show", "file", "formats" },
1162 "Displays file formats",
1163 "Usage: show file formats\n"
1164 " displays currently registered file formats (if any)\n"
1167 int ast_file_init(void)
1169 ast_cli_register(&show_file);