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"
40 #include "asterisk/pbx.h"
45 /* Extensions (separated by | if more than one)
46 this format can read. First is assumed for writing (e.g. .mp3) */
48 /* Format of frames it uses/provides (one only) */
50 /* Open an input stream, and start playback */
51 struct ast_filestream * (*open)(int fd);
52 /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
53 struct ast_filestream * (*rewrite)(int fd, const char *comment);
54 /* Write a frame to a channel */
55 int (*write)(struct ast_filestream *, struct ast_frame *);
56 /* seek num samples into file, whence(think normal seek) */
57 int (*seek)(struct ast_filestream *, long offset, int whence);
58 /* trunc file to current position */
59 int (*trunc)(struct ast_filestream *fs);
60 /* tell current position */
61 long (*tell)(struct ast_filestream *fs);
62 /* Read the next frame from the filestream (if available) and report when to get next one
64 struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
65 /* Close file, and destroy filestream structure */
66 void (*close)(struct ast_filestream *);
67 /* Retrieve file comment */
68 char * (*getcomment)(struct ast_filestream *);
70 struct ast_format *next;
73 struct ast_filestream {
74 /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
75 struct ast_format *fmt;
80 /* Video file stream */
81 struct ast_filestream *vfs;
82 /* Transparently translate from another format -- just once */
83 struct ast_trans_pvt *trans;
84 struct ast_tranlator_pvt *tr;
87 struct ast_channel *owner;
90 AST_MUTEX_DEFINE_STATIC(formatlock);
92 static struct ast_format *formats = NULL;
94 int ast_format_register(const char *name, const char *exts, int format,
95 struct ast_filestream * (*open)(int fd),
96 struct ast_filestream * (*rewrite)(int fd, const char *comment),
97 int (*write)(struct ast_filestream *, struct ast_frame *),
98 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
99 int (*trunc)(struct ast_filestream *),
100 long (*tell)(struct ast_filestream *),
101 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
102 void (*close)(struct ast_filestream *),
103 char * (*getcomment)(struct ast_filestream *))
105 struct ast_format *tmp;
106 if (ast_mutex_lock(&formatlock)) {
107 ast_log(LOG_WARNING, "Unable to lock format list\n");
112 if (!strcasecmp(name, tmp->name)) {
113 ast_mutex_unlock(&formatlock);
114 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
119 tmp = malloc(sizeof(struct ast_format));
121 ast_log(LOG_WARNING, "Out of memory\n");
122 ast_mutex_unlock(&formatlock);
125 ast_copy_string(tmp->name, name, sizeof(tmp->name));
126 ast_copy_string(tmp->exts, exts, sizeof(tmp->exts));
128 tmp->rewrite = rewrite;
135 tmp->format = format;
136 tmp->getcomment = getcomment;
139 ast_mutex_unlock(&formatlock);
140 if (option_verbose > 1)
141 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
145 int ast_format_unregister(const char *name)
147 struct ast_format *tmp, *tmpl = NULL;
148 if (ast_mutex_lock(&formatlock)) {
149 ast_log(LOG_WARNING, "Unable to lock format list\n");
154 if (!strcasecmp(name, tmp->name)) {
156 tmpl->next = tmp->next;
160 ast_mutex_unlock(&formatlock);
161 if (option_verbose > 1)
162 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
168 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
172 int ast_stopstream(struct ast_channel *tmp)
174 /* Stop a running stream if there is one */
176 ast_closestream(tmp->vstream);
178 ast_closestream(tmp->stream);
179 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
180 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
185 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
187 struct ast_frame *trf;
190 if (f->frametype == AST_FRAME_VIDEO) {
191 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
192 /* This is the audio portion. Call the video one... */
193 if (!fs->vfs && fs->filename) {
194 /* XXX Support other video formats XXX */
195 const char *type = "h263";
196 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
197 ast_log(LOG_DEBUG, "Opened video output file\n");
200 return ast_writestream(fs->vfs, f);
204 /* Might / might not have mark set */
207 } else if (f->frametype != AST_FRAME_VOICE) {
208 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
211 if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
212 res = fs->fmt->write(fs, f);
214 ast_log(LOG_WARNING, "Natural write failed\n");
216 ast_log(LOG_WARNING, "Huh??\n");
219 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
220 the one we've setup a translator for, we do the "wrong thing" XXX */
221 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
222 ast_translator_free_path(fs->trans);
226 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
228 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
230 fs->lastwriteformat = f->subclass;
232 /* Get the translated frame but don't consume the original in case they're using it on another stream */
233 trf = ast_translate(fs->trans, f, 0);
235 res = fs->fmt->write(fs, trf);
237 ast_log(LOG_WARNING, "Translated frame write failed\n");
245 static int copy(const char *infile, const char *outfile)
253 if ((ifd = open(infile, O_RDONLY)) < 0) {
254 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
257 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
258 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
263 len = read(ifd, buf, sizeof(buf));
265 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
271 res = write(ofd, buf, len);
273 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
285 static char *build_filename(const char *filename, const char *ext)
290 if (!strcmp(ext, "wav49")) {
291 ast_copy_string(type, "WAV", sizeof(type));
293 ast_copy_string(type, ext, sizeof(type));
296 if (filename[0] == '/') {
297 fnsize = strlen(filename) + strlen(type) + 2;
300 snprintf(fn, fnsize, "%s.%s", filename, type);
302 char tmp[AST_CONFIG_MAX_PATH] = "";
304 snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds");
305 fnsize = strlen(tmp) + strlen(filename) + strlen(type) + 3;
308 snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, type);
314 static int exts_compare(const char *exts, const char *type)
316 char *stringp = NULL, *ext;
319 ast_copy_string(tmp, exts, sizeof(tmp));
321 while ((ext = strsep(&stringp, "|"))) {
322 if (!strcmp(ext, type)) {
330 #define ACTION_EXISTS 1
331 #define ACTION_DELETE 2
332 #define ACTION_RENAME 3
333 #define ACTION_OPEN 4
334 #define ACTION_COPY 5
336 static int ast_filehelper(const char *filename, const char *filename2, const char *fmt, int action)
339 struct ast_format *f;
340 struct ast_filestream *s;
342 char *ext=NULL, *exts, *fn, *nfn;
343 struct ast_channel *chan = (struct ast_channel *)filename2;
345 /* Start with negative response */
346 if (action == ACTION_EXISTS)
350 if (action == ACTION_OPEN)
352 /* Check for a specific format */
353 if (ast_mutex_lock(&formatlock)) {
354 ast_log(LOG_WARNING, "Unable to lock format list\n");
355 if (action == ACTION_EXISTS)
362 if (!fmt || exts_compare(f->exts, fmt)) {
364 exts = ast_strdupa(f->exts);
365 /* Try each kind of extension */
367 ext = strsep(&stringp, "|");
369 fn = build_filename(filename, ext);
380 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
383 nfn = build_filename(filename2, ext);
385 res = rename(fn, nfn);
387 ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
390 ast_log(LOG_WARNING, "Out of memory\n");
393 nfn = build_filename(filename2, ext);
397 ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
400 ast_log(LOG_WARNING, "Out of memory\n");
403 if ((ret < 0) && ((chan->writeformat & f->format) ||
404 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
405 ret = open(fn, O_RDONLY);
413 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
419 ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
422 ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
426 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
428 /* Conveniently this logic is the same for all */
434 ext = strsep(&stringp, "|");
440 ast_mutex_unlock(&formatlock);
441 if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
442 res = ret ? ret : -1;
445 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
447 return ast_openstream_full(chan, filename, preflang, 0);
450 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
452 /* This is a fairly complex routine. Essentially we should do
455 1) Find which file handlers produce our type of format.
456 2) Look for a filename which it can handle.
457 3) If we find one, then great.
458 4) If not, see what files are there
459 5) See what we can actually support
460 6) Choose the one with the least costly translator path and
466 char filename2[256]="";
467 char filename3[256]="";
472 /* do this first, otherwise we detect the wrong writeformat */
473 ast_stopstream(chan);
475 ast_deactivate_generator(chan);
477 if (preflang && !ast_strlen_zero(preflang)) {
478 ast_copy_string(filename3, filename, sizeof(filename3));
479 endpart = strrchr(filename3, '/');
483 snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
485 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
486 fmts = ast_fileexists(filename2, NULL, NULL);
489 ast_copy_string(filename2, filename, sizeof(filename2));
490 fmts = ast_fileexists(filename2, NULL, NULL);
493 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
496 chan->oldwriteformat = chan->writeformat;
497 /* Set the channel to a format we can work with */
498 res = ast_set_write_format(chan, fmts);
500 fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
506 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
508 /* This is a fairly complex routine. Essentially we should do
511 1) Find which file handlers produce our type of format.
512 2) Look for a filename which it can handle.
513 3) If we find one, then great.
514 4) If not, see what files are there
515 5) See what we can actually support
516 6) Choose the one with the least costly translator path and
523 char lang2[MAX_LANGUAGE];
524 /* XXX H.263 only XXX */
526 if (preflang && !ast_strlen_zero(preflang)) {
527 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
528 fmts = ast_fileexists(filename2, fmt, NULL);
530 ast_copy_string(lang2, preflang, sizeof(lang2));
531 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
532 fmts = ast_fileexists(filename2, fmt, NULL);
536 ast_copy_string(filename2, filename, sizeof(filename2));
537 fmts = ast_fileexists(filename2, fmt, NULL);
542 fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
544 return chan->vstream;
545 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
549 struct ast_frame *ast_readframe(struct ast_filestream *s)
551 struct ast_frame *f = NULL;
554 f = s->fmt->read(s, &whennext);
558 static int ast_readaudio_callback(void *data)
560 struct ast_filestream *s = data;
561 struct ast_frame *fr;
565 fr = s->fmt->read(s, &whennext);
567 if (ast_write(s->owner, fr)) {
568 ast_log(LOG_WARNING, "Failed to write frame\n");
569 s->owner->streamid = -1;
570 #ifdef ZAPTEL_OPTIMIZATIONS
571 ast_settimeout(s->owner, 0, NULL, NULL);
576 /* Stream has finished */
577 s->owner->streamid = -1;
578 #ifdef ZAPTEL_OPTIMIZATIONS
579 ast_settimeout(s->owner, 0, NULL, NULL);
584 if (whennext != s->lasttimeout) {
585 #ifdef ZAPTEL_OPTIMIZATIONS
586 if (s->owner->timingfd > -1)
587 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
590 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
591 s->lasttimeout = whennext;
597 static int ast_readvideo_callback(void *data)
599 struct ast_filestream *s = data;
600 struct ast_frame *fr;
604 fr = s->fmt->read(s, &whennext);
606 if (ast_write(s->owner, fr)) {
607 ast_log(LOG_WARNING, "Failed to write frame\n");
608 s->owner->vstreamid = -1;
612 /* Stream has finished */
613 s->owner->vstreamid = -1;
617 if (whennext != s->lasttimeout) {
618 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
619 s->lasttimeout = whennext;
625 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
631 int ast_playstream(struct ast_filestream *s)
633 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
634 ast_readaudio_callback(s);
636 ast_readvideo_callback(s);
640 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
642 return fs->fmt->seek(fs, sample_offset, whence);
645 int ast_truncstream(struct ast_filestream *fs)
647 return fs->fmt->trunc(fs);
650 long ast_tellstream(struct ast_filestream *fs)
652 return fs->fmt->tell(fs);
655 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
657 /* I think this is right, 8000 samples per second, 1000 ms a second so 8
659 long samples = ms * 8;
660 return ast_seekstream(fs, samples, SEEK_CUR);
663 int ast_stream_rewind(struct ast_filestream *fs, long ms)
665 long samples = ms * 8;
666 samples = samples * -1;
667 return ast_seekstream(fs, samples, SEEK_CUR);
670 int ast_closestream(struct ast_filestream *f)
674 /* Stop a running stream if there is one */
676 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
677 f->owner->stream = NULL;
678 if (f->owner->streamid > -1)
679 ast_sched_del(f->owner->sched, f->owner->streamid);
680 f->owner->streamid = -1;
681 #ifdef ZAPTEL_OPTIMIZATIONS
682 ast_settimeout(f->owner, 0, NULL, NULL);
685 f->owner->vstream = NULL;
686 if (f->owner->vstreamid > -1)
687 ast_sched_del(f->owner->sched, f->owner->vstreamid);
688 f->owner->vstreamid = -1;
691 /* destroy the translator on exit */
693 ast_translator_free_path(f->trans);
697 if (f->realfilename && f->filename) {
698 size = strlen(f->filename) + strlen(f->realfilename) + 15;
701 snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
702 ast_safe_system(cmd);
709 if (f->realfilename) {
710 free(f->realfilename);
711 f->realfilename = NULL;
718 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
725 char lang2[MAX_LANGUAGE];
727 if (preflang && !ast_strlen_zero(preflang)) {
728 /* Insert the language between the last two parts of the path */
729 ast_copy_string(tmp, filename, sizeof(tmp));
730 c = strrchr(tmp, '/');
735 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
739 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, postfix);
741 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
744 ast_copy_string(lang2, preflang, sizeof(lang2));
746 strsep(&stringp, "_");
747 /* If language is a specific locality of a language (like es_MX), strip the locality and try again */
748 if (strcmp(lang2, preflang)) {
749 if (ast_strlen_zero(prefix)) {
750 snprintf(filename2, sizeof(filename2), "%s/%s", lang2, postfix);
752 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
754 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
759 /* Fallback to no language (usually winds up being American English) */
761 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
766 int ast_filedelete(const char *filename, const char *fmt)
768 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
771 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
773 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
776 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
778 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
781 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
783 struct ast_filestream *fs;
784 struct ast_filestream *vfs;
786 fs = ast_openstream(chan, filename, preflang);
787 vfs = ast_openvstream(chan, filename, preflang);
789 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
791 if (ast_applystream(chan, fs))
793 if (vfs && ast_applystream(chan, vfs))
795 if (ast_playstream(fs))
797 if (vfs && ast_playstream(vfs))
800 if (option_verbose > 2)
801 ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
805 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
809 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
812 struct ast_format *f;
813 struct ast_filestream *fs = NULL;
816 if (ast_mutex_lock(&formatlock)) {
817 ast_log(LOG_WARNING, "Unable to lock format list\n");
821 for (f = formats; f && !fs; f = f->next) {
822 if (!exts_compare(f->exts, type))
825 fn = build_filename(filename, type);
826 fd = open(fn, flags);
830 if (!(fs = f->open(fd))) {
831 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
841 fs->filename = strdup(filename);
843 } else if (errno != EEXIST)
844 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
848 ast_mutex_unlock(&formatlock);
850 ast_log(LOG_WARNING, "No such format '%s'\n", type);
855 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
858 struct ast_format *f;
859 struct ast_filestream *fs = NULL;
860 char *fn, *orig_fn = NULL;
864 if (ast_mutex_lock(&formatlock)) {
865 ast_log(LOG_WARNING, "Unable to lock format list\n");
869 /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
870 if (flags & O_APPEND) {
871 /* We really can't use O_APPEND as it will break WAV header updates */
877 myflags |= O_WRONLY | O_CREAT;
879 for (f = formats; f && !fs; f = f->next) {
880 if (!exts_compare(f->exts, type))
883 fn = build_filename(filename, type);
884 fd = open(fn, flags | myflags, mode);
886 if (option_cache_record_files && fd >= 0) {
891 We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
892 What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
894 orig_fn = ast_strdupa(fn);
895 for (c = fn; *c; c++)
899 size = strlen(fn) + strlen(record_cache_dir) + 2;
901 memset(buf, 0, size);
902 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
905 fd = open(fn, flags | myflags, mode);
910 if ((fs = f->rewrite(fd, comment))) {
916 fs->realfilename = strdup(orig_fn);
917 fs->filename = strdup(fn);
919 fs->realfilename = NULL;
920 fs->filename = strdup(filename);
924 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
931 } else if (errno != EEXIST) {
932 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
936 /* if buf != NULL then fn is already free and pointing to it */
941 ast_mutex_unlock(&formatlock);
943 ast_log(LOG_WARNING, "No such format '%s'\n", type);
948 int ast_waitstream(struct ast_channel *c, const char *breakon)
950 /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
952 struct ast_frame *fr;
953 if (!breakon) breakon = "";
955 res = ast_sched_wait(c->sched);
956 if ((res < 0) && !c->timingfunc) {
962 res = ast_waitfor(c, res);
964 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
966 } else if (res > 0) {
970 ast_log(LOG_DEBUG, "Got hung up\n");
975 switch(fr->frametype) {
978 if (strchr(breakon, res)) {
983 case AST_FRAME_CONTROL:
984 switch(fr->subclass) {
985 case AST_CONTROL_HANGUP:
988 case AST_CONTROL_RINGING:
989 case AST_CONTROL_ANSWER:
993 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
999 ast_sched_runq(c->sched);
1001 return (c->_softhangup ? -1 : 0);
1004 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
1007 struct ast_frame *fr;
1017 res = ast_sched_wait(c->sched);
1018 if ((res < 0) && !c->timingfunc) {
1024 res = ast_waitfor(c, res);
1026 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1033 ast_log(LOG_DEBUG, "Got hung up\n");
1038 switch(fr->frametype) {
1039 case AST_FRAME_DTMF:
1041 if (strchr(forward,res)) {
1042 ast_stream_fastforward(c->stream, ms);
1043 } else if (strchr(rewind,res)) {
1044 ast_stream_rewind(c->stream, ms);
1045 } else if (strchr(breakon, res)) {
1050 case AST_FRAME_CONTROL:
1051 switch(fr->subclass) {
1052 case AST_CONTROL_HANGUP:
1055 case AST_CONTROL_RINGING:
1056 case AST_CONTROL_ANSWER:
1060 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1066 ast_sched_runq(c->sched);
1070 return (c->_softhangup ? -1 : 0);
1073 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1078 struct ast_frame *fr;
1079 struct ast_channel *rchan;
1085 ms = ast_sched_wait(c->sched);
1086 if ((ms < 0) && !c->timingfunc) {
1092 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1093 if (!rchan && (outfd < 0) && (ms)) {
1097 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1099 } else if (outfd > -1) {
1100 /* The FD we were watching has something waiting */
1106 ast_log(LOG_DEBUG, "Got hung up\n");
1111 switch(fr->frametype) {
1112 case AST_FRAME_DTMF:
1114 if (strchr(breakon, res)) {
1119 case AST_FRAME_CONTROL:
1120 switch(fr->subclass) {
1121 case AST_CONTROL_HANGUP:
1124 case AST_CONTROL_RINGING:
1125 case AST_CONTROL_ANSWER:
1129 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1131 case AST_FRAME_VOICE:
1132 /* Write audio if appropriate */
1134 write(audiofd, fr->data, fr->datalen);
1139 ast_sched_runq(c->sched);
1141 return (c->_softhangup ? -1 : 0);
1144 int ast_waitstream_exten(struct ast_channel *c, const char *context)
1146 /* Waitstream, with return in the case of a valid 1 digit extension */
1147 /* in the current or specified context being pressed */
1148 /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
1150 struct ast_frame *fr;
1151 char exten[AST_MAX_EXTENSION] = "";
1153 if (!context) context = c->context;
1155 res = ast_sched_wait(c->sched);
1156 if ((res < 0) && !c->timingfunc) {
1162 res = ast_waitfor(c, res);
1164 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
1166 } else if (res > 0) {
1170 ast_log(LOG_DEBUG, "Got hung up\n");
1175 switch(fr->frametype) {
1176 case AST_FRAME_DTMF:
1178 snprintf(exten, sizeof(exten), "%c", res);
1179 if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
1184 case AST_FRAME_CONTROL:
1185 switch(fr->subclass) {
1186 case AST_CONTROL_HANGUP:
1189 case AST_CONTROL_RINGING:
1190 case AST_CONTROL_ANSWER:
1194 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1200 ast_sched_runq(c->sched);
1202 return (c->_softhangup ? -1 : 0);
1205 static int show_file_formats(int fd, int argc, char *argv[])
1207 #define FORMAT "%-10s %-10s %-20s\n"
1208 #define FORMAT2 "%-10s %-10s %-20s\n"
1209 struct ast_format *f;
1211 return RESULT_SHOWUSAGE;
1212 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1214 if (ast_mutex_lock(&formatlock)) {
1215 ast_log(LOG_WARNING, "Unable to lock format list\n");
1221 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1224 ast_mutex_unlock(&formatlock);
1225 return RESULT_SUCCESS;
1228 struct ast_cli_entry show_file =
1230 { "show", "file", "formats" },
1232 "Displays file formats",
1233 "Usage: show file formats\n"
1234 " displays currently registered file formats (if any)\n"
1237 int ast_file_init(void)
1239 ast_cli_register(&show_file);